LCOV - code coverage report
Current view: top level - exchange - taler-exchange-httpd_keys.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 528 640 82.5 %
Date: 2021-08-30 06:43:37 Functions: 46 48 95.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2020, 2021 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU 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             :  */
      21             : #include "platform.h"
      22             : #include "taler_json_lib.h"
      23             : #include "taler_mhd_lib.h"
      24             : #include "taler_dbevents.h"
      25             : #include "taler-exchange-httpd.h"
      26             : #include "taler-exchange-httpd_keys.h"
      27             : #include "taler-exchange-httpd_responses.h"
      28             : #include "taler_exchangedb_plugin.h"
      29             : 
      30             : 
      31             : /**
      32             :  * How many /keys request do we hold in suspension at
      33             :  * most at any time?
      34             :  */
      35             : #define SKR_LIMIT 32
      36             : 
      37             : 
      38             : /**
      39             :  * Taler protocol version in the format CURRENT:REVISION:AGE
      40             :  * as used by GNU libtool.  See
      41             :  * https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
      42             :  *
      43             :  * Please be very careful when updating and follow
      44             :  * https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info
      45             :  * precisely.  Note that this version has NOTHING to do with the
      46             :  * release version, and the format is NOT the same that semantic
      47             :  * versioning uses either.
      48             :  *
      49             :  * When changing this version, you likely want to also update
      50             :  * #TALER_PROTOCOL_CURRENT and #TALER_PROTOCOL_AGE in
      51             :  * exchange_api_handle.c!
      52             :  */
      53             : #define EXCHANGE_PROTOCOL_VERSION "9:0:0"
      54             : 
      55             : 
      56             : /**
      57             :  * Information about a denomination on offer by the denomination helper.
      58             :  */
      59             : struct HelperDenomination
      60             : {
      61             : 
      62             :   /**
      63             :    * When will the helper start to use this key for signing?
      64             :    */
      65             :   struct GNUNET_TIME_Absolute start_time;
      66             : 
      67             :   /**
      68             :    * For how long will the helper allow signing? 0 if
      69             :    * the key was revoked or purged.
      70             :    */
      71             :   struct GNUNET_TIME_Relative validity_duration;
      72             : 
      73             :   /**
      74             :    * Hash of the denomination key.
      75             :    */
      76             :   struct GNUNET_HashCode h_denom_pub;
      77             : 
      78             :   /**
      79             :    * Signature over this key from the security module's key.
      80             :    */
      81             :   struct TALER_SecurityModuleSignatureP sm_sig;
      82             : 
      83             :   /**
      84             :    * The (full) public key.
      85             :    */
      86             :   struct TALER_DenominationPublicKey denom_pub;
      87             : 
      88             :   /**
      89             :    * Name in configuration section for this denomination type.
      90             :    */
      91             :   char *section_name;
      92             : 
      93             : };
      94             : 
      95             : 
      96             : /**
      97             :  * Signatures of an auditor over a denomination key of this exchange.
      98             :  */
      99             : struct TEH_AuditorSignature
     100             : {
     101             :   /**
     102             :    * We store the signatures in a DLL.
     103             :    */
     104             :   struct TEH_AuditorSignature *prev;
     105             : 
     106             :   /**
     107             :    * We store the signatures in a DLL.
     108             :    */
     109             :   struct TEH_AuditorSignature *next;
     110             : 
     111             :   /**
     112             :    * A signature from the auditor.
     113             :    */
     114             :   struct TALER_AuditorSignatureP asig;
     115             : 
     116             :   /**
     117             :    * Public key of the auditor.
     118             :    */
     119             :   struct TALER_AuditorPublicKeyP apub;
     120             : 
     121             : };
     122             : 
     123             : 
     124             : /**
     125             :  * Information about a signing key on offer by the esign helper.
     126             :  */
     127             : struct HelperSignkey
     128             : {
     129             :   /**
     130             :    * When will the helper start to use this key for signing?
     131             :    */
     132             :   struct GNUNET_TIME_Absolute start_time;
     133             : 
     134             :   /**
     135             :    * For how long will the helper allow signing? 0 if
     136             :    * the key was revoked or purged.
     137             :    */
     138             :   struct GNUNET_TIME_Relative validity_duration;
     139             : 
     140             :   /**
     141             :    * The public key.
     142             :    */
     143             :   struct TALER_ExchangePublicKeyP exchange_pub;
     144             : 
     145             :   /**
     146             :    * Signature over this key from the security module's key.
     147             :    */
     148             :   struct TALER_SecurityModuleSignatureP sm_sig;
     149             : 
     150             : };
     151             : 
     152             : 
     153             : /**
     154             :  * State associated with the crypto helpers / security modules.
     155             :  * Created per-thread, but NOT updated when the #key_generation
     156             :  * is updated (instead constantly kept in sync whenever
     157             :  * #TEH_keys_get_state() is called).
     158             :  */
     159             : struct HelperState
     160             : {
     161             : 
     162             :   /**
     163             :    * Handle for the esign/EdDSA helper.
     164             :    */
     165             :   struct TALER_CRYPTO_ExchangeSignHelper *esh;
     166             : 
     167             :   /**
     168             :    * Handle for the denom/RSA helper.
     169             :    */
     170             :   struct TALER_CRYPTO_DenominationHelper *dh;
     171             : 
     172             :   /**
     173             :    * Map from H(denom_pub) to `struct HelperDenomination` entries.
     174             :    */
     175             :   struct GNUNET_CONTAINER_MultiHashMap *denom_keys;
     176             : 
     177             :   /**
     178             :    * Map from `struct TALER_ExchangePublicKey` to `struct HelperSignkey`
     179             :    * entries.  Based on the fact that a `struct GNUNET_PeerIdentity` is also
     180             :    * an EdDSA public key.
     181             :    */
     182             :   struct GNUNET_CONTAINER_MultiPeerMap *esign_keys;
     183             : 
     184             : };
     185             : 
     186             : 
     187             : /**
     188             :  * Entry in (sorted) array with possible pre-build responses for /keys.
     189             :  * We keep pre-build responses for the various (valid) cherry-picking
     190             :  * values around.
     191             :  */
     192             : struct KeysResponseData
     193             : {
     194             : 
     195             :   /**
     196             :    * Response to return if the client supports (deflate) compression.
     197             :    */
     198             :   struct MHD_Response *response_compressed;
     199             : 
     200             :   /**
     201             :    * Response to return if the client does not support compression.
     202             :    */
     203             :   struct MHD_Response *response_uncompressed;
     204             : 
     205             :   /**
     206             :    * Cherry-picking timestamp the client must have set for this
     207             :    * response to be valid.  0 if this is the "full" response.
     208             :    * The client's request must include this date or a higher one
     209             :    * for this response to be applicable.
     210             :    */
     211             :   struct GNUNET_TIME_Absolute cherry_pick_date;
     212             : 
     213             : };
     214             : 
     215             : 
     216             : /**
     217             :  * @brief All information about an exchange online signing key (which is used to
     218             :  * sign messages from the exchange).
     219             :  */
     220             : struct SigningKey
     221             : {
     222             : 
     223             :   /**
     224             :    * The exchange's (online signing) public key.
     225             :    */
     226             :   struct TALER_ExchangePublicKeyP exchange_pub;
     227             : 
     228             :   /**
     229             :    * Meta data about the signing key, such as validity periods.
     230             :    */
     231             :   struct TALER_EXCHANGEDB_SignkeyMetaData meta;
     232             : 
     233             :   /**
     234             :    * The long-term offline master key's signature for this signing key.
     235             :    * Signs over @e exchange_pub and @e meta.
     236             :    */
     237             :   struct TALER_MasterSignatureP master_sig;
     238             : 
     239             : };
     240             : 
     241             : 
     242             : struct TEH_KeyStateHandle
     243             : {
     244             : 
     245             :   /**
     246             :    * Mapping from denomination keys to denomination key issue struct.
     247             :    * Used to lookup the key by hash.
     248             :    */
     249             :   struct GNUNET_CONTAINER_MultiHashMap *denomkey_map;
     250             : 
     251             :   /**
     252             :    * Map from `struct TALER_ExchangePublicKey` to `struct SigningKey`
     253             :    * entries.  Based on the fact that a `struct GNUNET_PeerIdentity` is also
     254             :    * an EdDSA public key.
     255             :    */
     256             :   struct GNUNET_CONTAINER_MultiPeerMap *signkey_map;
     257             : 
     258             :   /**
     259             :    * json array with the auditors of this exchange. Contains exactly
     260             :    * the information needed for the "auditors" field of the /keys response.
     261             :    */
     262             :   json_t *auditors;
     263             : 
     264             :   /**
     265             :    * Sorted array of responses to /keys (MUST be sorted by cherry-picking date) of
     266             :    * length @e krd_array_length;
     267             :    */
     268             :   struct KeysResponseData *krd_array;
     269             : 
     270             :   /**
     271             :    * Length of the @e krd_array.
     272             :    */
     273             :   unsigned int krd_array_length;
     274             : 
     275             :   /**
     276             :    * Information we track for thecrypto helpers.  Preserved
     277             :    * when the @e key_generation changes, thus kept separate.
     278             :    */
     279             :   struct HelperState *helpers;
     280             : 
     281             :   /**
     282             :    * Cached reply for a GET /management/keys request.  Used so we do not
     283             :    * re-create the reply every time.
     284             :    */
     285             :   json_t *management_keys_reply;
     286             : 
     287             :   /**
     288             :    * For which (global) key_generation was this data structure created?
     289             :    * Used to check when we are outdated and need to be re-generated.
     290             :    */
     291             :   uint64_t key_generation;
     292             : 
     293             :   /**
     294             :    * When did we initiate the key reloading?
     295             :    */
     296             :   struct GNUNET_TIME_Absolute reload_time;
     297             : 
     298             :   /**
     299             :    * When is the next key invalid and we expect to have a different reply?
     300             :    */
     301             :   struct GNUNET_TIME_Absolute next_reload;
     302             : 
     303             :   /**
     304             :    * When does our online signing key expire and we
     305             :    * thus need to re-generate this response?
     306             :    */
     307             :   struct GNUNET_TIME_Absolute signature_expires;
     308             : 
     309             :   /**
     310             :    * True if #finish_keys_response() was not yet run and this key state
     311             :    * is only suitable for the /management/keys API.
     312             :    */
     313             :   bool management_only;
     314             : 
     315             : };
     316             : 
     317             : 
     318             : /**
     319             :  * Entry of /keys requests that are currently suspended because we are
     320             :  * waiting for /keys to become ready.
     321             :  */
     322             : struct SuspendedKeysRequests
     323             : {
     324             :   /**
     325             :    * Kept in a DLL.
     326             :    */
     327             :   struct SuspendedKeysRequests *next;
     328             : 
     329             :   /**
     330             :    * Kept in a DLL.
     331             :    */
     332             :   struct SuspendedKeysRequests *prev;
     333             : 
     334             :   /**
     335             :    * The suspended connection.
     336             :    */
     337             :   struct MHD_Connection *connection;
     338             : };
     339             : 
     340             : 
     341             : /**
     342             :  * Stores the latest generation of our key state.
     343             :  */
     344             : static struct TEH_KeyStateHandle *key_state;
     345             : 
     346             : /**
     347             :  * Counter incremented whenever we have a reason to re-build the keys because
     348             :  * something external changed (in another thread).  See #TEH_keys_get_state() and
     349             :  * #TEH_keys_update_states() for uses of this variable.
     350             :  */
     351             : static uint64_t key_generation;
     352             : 
     353             : /**
     354             :  * Handler listening for wire updates by other exchange
     355             :  * services.
     356             :  */
     357             : static struct GNUNET_DB_EventHandler *keys_eh;
     358             : 
     359             : /**
     360             :  * Head of DLL of suspended /keys requests.
     361             :  */
     362             : static struct SuspendedKeysRequests *skr_head;
     363             : 
     364             : /**
     365             :  * Tail of DLL of suspended /keys requests.
     366             :  */
     367             : static struct SuspendedKeysRequests *skr_tail;
     368             : 
     369             : /**
     370             :  * Number of entries in the @e skr_head DLL.
     371             :  */
     372             : static unsigned int skr_size;
     373             : 
     374             : /**
     375             :  * Handle to a connection that should be force-resumed
     376             :  * with a hard error due to @a skr_size hitting
     377             :  * #SKR_LIMIT.
     378             :  */
     379             : static struct MHD_Connection *skr_connection;
     380             : 
     381             : /**
     382             :  * For how long should a signing key be legally retained?
     383             :  * Configuration value.
     384             :  */
     385             : static struct GNUNET_TIME_Relative signkey_legal_duration;
     386             : 
     387             : /**
     388             :  * RSA security module public key, all zero if not known.
     389             :  */
     390             : static struct TALER_SecurityModulePublicKeyP denom_sm_pub;
     391             : 
     392             : /**
     393             :  * EdDSA security module public key, all zero if not known.
     394             :  */
     395             : static struct TALER_SecurityModulePublicKeyP esign_sm_pub;
     396             : 
     397             : /**
     398             :  * Are we shutting down?
     399             :  */
     400             : static bool terminating;
     401             : 
     402             : /**
     403             :  * Suspend /keys request while we (hopefully) are waiting to be
     404             :  * provisioned with key material.
     405             :  *
     406             :  * @param[in] connection to suspend
     407             :  */
     408             : static MHD_RESULT
     409          32 : suspend_request (struct MHD_Connection *connection)
     410             : {
     411             :   struct SuspendedKeysRequests *skr;
     412             : 
     413          32 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     414             :               "Suspending /keys request until key material changes\n");
     415          32 :   if (terminating)
     416             :   {
     417           0 :     return TALER_MHD_reply_with_error (connection,
     418             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
     419             :                                        TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
     420             :                                        "Exchange terminating");
     421             :   }
     422          32 :   skr = GNUNET_new (struct SuspendedKeysRequests);
     423          32 :   skr->connection = connection;
     424          32 :   MHD_suspend_connection (connection);
     425          32 :   GNUNET_CONTAINER_DLL_insert (skr_head,
     426             :                                skr_tail,
     427             :                                skr);
     428          32 :   skr_size++;
     429          32 :   if (skr_size > SKR_LIMIT)
     430             :   {
     431           0 :     skr = skr_tail;
     432           0 :     GNUNET_CONTAINER_DLL_remove (skr_head,
     433             :                                  skr_tail,
     434             :                                  skr);
     435           0 :     skr_size--;
     436           0 :     skr_connection = skr->connection;
     437           0 :     MHD_resume_connection (skr->connection);
     438           0 :     TALER_MHD_daemon_trigger ();
     439           0 :     GNUNET_free (skr);
     440             :   }
     441          32 :   return MHD_YES;
     442             : }
     443             : 
     444             : 
     445             : void
     446          64 : TEH_resume_keys_requests (bool do_shutdown)
     447             : {
     448             :   struct SuspendedKeysRequests *skr;
     449             : 
     450          64 :   if (do_shutdown)
     451          12 :     terminating = true;
     452          96 :   while (NULL != (skr = skr_head))
     453             :   {
     454          32 :     GNUNET_CONTAINER_DLL_remove (skr_head,
     455             :                                  skr_tail,
     456             :                                  skr);
     457          32 :     skr_size--;
     458          32 :     MHD_resume_connection (skr->connection);
     459          32 :     TALER_MHD_daemon_trigger ();
     460          32 :     GNUNET_free (skr);
     461             :   }
     462          64 : }
     463             : 
     464             : 
     465             : /**
     466             :  * Clear memory for responses to "/keys" in @a ksh.
     467             :  *
     468             :  * @param[in,out] ksh key state to update
     469             :  */
     470             : static void
     471          52 : clear_response_cache (struct TEH_KeyStateHandle *ksh)
     472             : {
     473         120 :   for (unsigned int i = 0; i<ksh->krd_array_length; i++)
     474             :   {
     475          68 :     struct KeysResponseData *krd = &ksh->krd_array[i];
     476             : 
     477          68 :     MHD_destroy_response (krd->response_compressed);
     478          68 :     MHD_destroy_response (krd->response_uncompressed);
     479             :   }
     480          52 :   GNUNET_array_grow (ksh->krd_array,
     481             :                      ksh->krd_array_length,
     482             :                      0);
     483          52 : }
     484             : 
     485             : 
     486             : /**
     487             :  * Check that the given RSA security module's public key is the one
     488             :  * we have pinned.  If it does not match, we die hard.
     489             :  *
     490             :  * @param sm_pub RSA security module public key to check
     491             :  */
     492             : static void
     493         504 : check_denom_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub)
     494             : {
     495         504 :   if (0 !=
     496         504 :       GNUNET_memcmp (sm_pub,
     497             :                      &denom_sm_pub))
     498             :   {
     499           9 :     if (! GNUNET_is_zero (&denom_sm_pub))
     500             :     {
     501           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     502             :                   "Our RSA security module changed its key. This must not happen.\n");
     503           0 :       GNUNET_assert (0);
     504             :     }
     505           9 :     denom_sm_pub = *sm_pub; /* TOFU ;-) */
     506             :   }
     507         504 : }
     508             : 
     509             : 
     510             : /**
     511             :  * Check that the given EdDSA security module's public key is the one
     512             :  * we have pinned.  If it does not match, we die hard.
     513             :  *
     514             :  * @param sm_pub EdDSA security module public key to check
     515             :  */
     516             : static void
     517          64 : check_esign_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub)
     518             : {
     519          64 :   if (0 !=
     520          64 :       GNUNET_memcmp (sm_pub,
     521             :                      &esign_sm_pub))
     522             :   {
     523           9 :     if (! GNUNET_is_zero (&esign_sm_pub))
     524             :     {
     525           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     526             :                   "Our EdDSA security module changed its key. This must not happen.\n");
     527           0 :       GNUNET_assert (0);
     528             :     }
     529           9 :     esign_sm_pub = *sm_pub; /* TOFU ;-) */
     530             :   }
     531          64 : }
     532             : 
     533             : 
     534             : /**
     535             :  * Helper function for #destroy_key_helpers to free all entries
     536             :  * in the `denom_keys` map.
     537             :  *
     538             :  * @param cls the `struct HelperDenomination`
     539             :  * @param h_denom_pub hash of the denomination public key
     540             :  * @param value the `struct HelperDenomination` to release
     541             :  * @return #GNUNET_OK (continue to iterate)
     542             :  */
     543             : static int
     544         504 : free_denom_cb (void *cls,
     545             :                const struct GNUNET_HashCode *h_denom_pub,
     546             :                void *value)
     547             : {
     548         504 :   struct HelperDenomination *hd = value;
     549             : 
     550             :   (void) cls;
     551             :   (void) h_denom_pub;
     552         504 :   GNUNET_CRYPTO_rsa_public_key_free (hd->denom_pub.rsa_public_key);
     553         504 :   GNUNET_free (hd->section_name);
     554         504 :   GNUNET_free (hd);
     555         504 :   return GNUNET_OK;
     556             : }
     557             : 
     558             : 
     559             : /**
     560             :  * Helper function for #destroy_key_helpers to free all entries
     561             :  * in the `esign_keys` map.
     562             :  *
     563             :  * @param cls the `struct HelperSignkey`
     564             :  * @param pid unused, matches the exchange public key
     565             :  * @param value the `struct HelperSignkey` to release
     566             :  * @return #GNUNET_OK (continue to iterate)
     567             :  */
     568             : static int
     569          64 : free_esign_cb (void *cls,
     570             :                const struct GNUNET_PeerIdentity *pid,
     571             :                void *value)
     572             : {
     573          64 :   struct HelperSignkey *hsk = value;
     574             : 
     575             :   (void) cls;
     576             :   (void) pid;
     577          64 :   GNUNET_free (hsk);
     578          64 :   return GNUNET_OK;
     579             : }
     580             : 
     581             : 
     582             : /**
     583             :  * Destroy helper state. Does NOT call free() on @a hs, as that
     584             :  * state is not separately allocated!  Dual to #setup_key_helpers().
     585             :  *
     586             :  * @param[in] hs helper state to free, but NOT the @a hs pointer itself!
     587             :  */
     588             : static void
     589          42 : destroy_key_helpers (struct HelperState *hs)
     590             : {
     591          42 :   GNUNET_CONTAINER_multihashmap_iterate (hs->denom_keys,
     592             :                                          &free_denom_cb,
     593             :                                          hs);
     594          42 :   GNUNET_CONTAINER_multihashmap_destroy (hs->denom_keys);
     595          42 :   hs->denom_keys = NULL;
     596          42 :   GNUNET_CONTAINER_multipeermap_iterate (hs->esign_keys,
     597             :                                          &free_esign_cb,
     598             :                                          hs);
     599          42 :   GNUNET_CONTAINER_multipeermap_destroy (hs->esign_keys);
     600          42 :   hs->esign_keys = NULL;
     601          42 :   if (NULL != hs->dh)
     602             :   {
     603          36 :     TALER_CRYPTO_helper_denom_disconnect (hs->dh);
     604          36 :     hs->dh = NULL;
     605             :   }
     606          42 :   if (NULL != hs->esh)
     607             :   {
     608          36 :     TALER_CRYPTO_helper_esign_disconnect (hs->esh);
     609          36 :     hs->esh = NULL;
     610             :   }
     611          42 : }
     612             : 
     613             : 
     614             : /**
     615             :  * Function called with information about available keys for signing.  Usually
     616             :  * only called once per key upon connect. Also called again in case a key is
     617             :  * being revoked, in that case with an @a end_time of zero.
     618             :  *
     619             :  * @param cls closure with the `struct HelperState *`
     620             :  * @param section_name name of the denomination type in the configuration;
     621             :  *                 NULL if the key has been revoked or purged
     622             :  * @param start_time when does the key become available for signing;
     623             :  *                 zero if the key has been revoked or purged
     624             :  * @param validity_duration how long does the key remain available for signing;
     625             :  *                 zero if the key has been revoked or purged
     626             :  * @param h_denom_pub hash of the @a denom_pub that is available (or was purged)
     627             :  * @param denom_pub the public key itself, NULL if the key was revoked or purged
     628             :  * @param sm_pub public key of the security module, NULL if the key was revoked or purged
     629             :  * @param sm_sig signature from the security module, NULL if the key was revoked or purged
     630             :  *               The signature was already verified against @a sm_pub.
     631             :  */
     632             : static void
     633         511 : helper_denom_cb (
     634             :   void *cls,
     635             :   const char *section_name,
     636             :   struct GNUNET_TIME_Absolute start_time,
     637             :   struct GNUNET_TIME_Relative validity_duration,
     638             :   const struct GNUNET_HashCode *h_denom_pub,
     639             :   const struct TALER_DenominationPublicKey *denom_pub,
     640             :   const struct TALER_SecurityModulePublicKeyP *sm_pub,
     641             :   const struct TALER_SecurityModuleSignatureP *sm_sig)
     642             : {
     643         511 :   struct HelperState *hs = cls;
     644             :   struct HelperDenomination *hd;
     645             : 
     646         511 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     647             :               "RSA helper announces key %s for denomination type %s with validity %s\n",
     648             :               GNUNET_h2s (h_denom_pub),
     649             :               section_name,
     650             :               GNUNET_STRINGS_relative_time_to_string (validity_duration,
     651             :                                                       GNUNET_NO));
     652         511 :   hd = GNUNET_CONTAINER_multihashmap_get (hs->denom_keys,
     653             :                                           h_denom_pub);
     654         511 :   if (NULL != hd)
     655             :   {
     656             :     /* should be just an update (revocation!), so update existing entry */
     657           7 :     hd->validity_duration = validity_duration;
     658           7 :     return;
     659             :   }
     660         504 :   GNUNET_assert (NULL != sm_pub);
     661         504 :   check_denom_sm_pub (sm_pub);
     662         504 :   hd = GNUNET_new (struct HelperDenomination);
     663         504 :   hd->start_time = start_time;
     664         504 :   hd->validity_duration = validity_duration;
     665         504 :   hd->h_denom_pub = *h_denom_pub;
     666         504 :   hd->sm_sig = *sm_sig;
     667             :   hd->denom_pub.rsa_public_key
     668         504 :     = GNUNET_CRYPTO_rsa_public_key_dup (denom_pub->rsa_public_key);
     669         504 :   hd->section_name = GNUNET_strdup (section_name);
     670         504 :   GNUNET_assert (
     671             :     GNUNET_OK ==
     672             :     GNUNET_CONTAINER_multihashmap_put (
     673             :       hs->denom_keys,
     674             :       &hd->h_denom_pub,
     675             :       hd,
     676             :       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
     677             : }
     678             : 
     679             : 
     680             : /**
     681             :  * Function called with information about available keys for signing.  Usually
     682             :  * only called once per key upon connect. Also called again in case a key is
     683             :  * being revoked, in that case with an @a end_time of zero.
     684             :  *
     685             :  * @param cls closure with the `struct HelperState *`
     686             :  * @param start_time when does the key become available for signing;
     687             :  *                 zero if the key has been revoked or purged
     688             :  * @param validity_duration how long does the key remain available for signing;
     689             :  *                 zero if the key has been revoked or purged
     690             :  * @param exchange_pub the public key itself, NULL if the key was revoked or purged
     691             :  * @param sm_pub public key of the security module, NULL if the key was revoked or purged
     692             :  * @param sm_sig signature from the security module, NULL if the key was revoked or purged
     693             :  *               The signature was already verified against @a sm_pub.
     694             :  */
     695             : static void
     696          64 : helper_esign_cb (
     697             :   void *cls,
     698             :   struct GNUNET_TIME_Absolute start_time,
     699             :   struct GNUNET_TIME_Relative validity_duration,
     700             :   const struct TALER_ExchangePublicKeyP *exchange_pub,
     701             :   const struct TALER_SecurityModulePublicKeyP *sm_pub,
     702             :   const struct TALER_SecurityModuleSignatureP *sm_sig)
     703             : {
     704          64 :   struct HelperState *hs = cls;
     705             :   struct HelperSignkey *hsk;
     706             :   struct GNUNET_PeerIdentity pid;
     707             : 
     708          64 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     709             :               "EdDSA helper announces signing key %s with validity %s\n",
     710             :               TALER_B2S (exchange_pub),
     711             :               GNUNET_STRINGS_relative_time_to_string (validity_duration,
     712             :                                                       GNUNET_NO));
     713          64 :   pid.public_key = exchange_pub->eddsa_pub;
     714          64 :   hsk = GNUNET_CONTAINER_multipeermap_get (hs->esign_keys,
     715             :                                            &pid);
     716          64 :   if (NULL != hsk)
     717             :   {
     718             :     /* should be just an update (revocation!), so update existing entry */
     719           0 :     hsk->validity_duration = validity_duration;
     720           0 :     GNUNET_break (0 == start_time.abs_value_us);
     721           0 :     return;
     722             :   }
     723          64 :   GNUNET_assert (NULL != sm_pub);
     724          64 :   check_esign_sm_pub (sm_pub);
     725          64 :   hsk = GNUNET_new (struct HelperSignkey);
     726          64 :   hsk->start_time = start_time;
     727          64 :   hsk->validity_duration = validity_duration;
     728          64 :   hsk->exchange_pub = *exchange_pub;
     729          64 :   hsk->sm_sig = *sm_sig;
     730          64 :   GNUNET_assert (
     731             :     GNUNET_OK ==
     732             :     GNUNET_CONTAINER_multipeermap_put (
     733             :       hs->esign_keys,
     734             :       &pid,
     735             :       hsk,
     736             :       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
     737             : }
     738             : 
     739             : 
     740             : /**
     741             :  * Setup helper state.
     742             :  *
     743             :  * @param[out] hs helper state to initialize
     744             :  * @return #GNUNET_OK on success
     745             :  */
     746             : static int
     747          42 : setup_key_helpers (struct HelperState *hs)
     748             : {
     749             :   hs->denom_keys
     750          42 :     = GNUNET_CONTAINER_multihashmap_create (1024,
     751             :                                             GNUNET_YES);
     752             :   hs->esign_keys
     753          42 :     = GNUNET_CONTAINER_multipeermap_create (32,
     754             :                                             GNUNET_NO /* MUST BE NO! */);
     755          42 :   hs->dh = TALER_CRYPTO_helper_denom_connect (TEH_cfg,
     756             :                                               &helper_denom_cb,
     757             :                                               hs);
     758          42 :   if (NULL == hs->dh)
     759             :   {
     760           6 :     destroy_key_helpers (hs);
     761           6 :     return GNUNET_SYSERR;
     762             :   }
     763          36 :   hs->esh = TALER_CRYPTO_helper_esign_connect (TEH_cfg,
     764             :                                                &helper_esign_cb,
     765             :                                                hs);
     766          36 :   if (NULL == hs->esh)
     767             :   {
     768           0 :     destroy_key_helpers (hs);
     769           0 :     return GNUNET_SYSERR;
     770             :   }
     771          36 :   return GNUNET_OK;
     772             : }
     773             : 
     774             : 
     775             : /**
     776             :  * Synchronize helper state. Polls the key helper for updates.
     777             :  *
     778             :  * @param[in,out] hs helper state to synchronize
     779             :  */
     780             : static void
     781         415 : sync_key_helpers (struct HelperState *hs)
     782             : {
     783         415 :   TALER_CRYPTO_helper_denom_poll (hs->dh);
     784         415 :   TALER_CRYPTO_helper_esign_poll (hs->esh);
     785         415 : }
     786             : 
     787             : 
     788             : /**
     789             :  * Free denomination key data.
     790             :  *
     791             :  * @param cls a `struct TEH_KeyStateHandle`, unused
     792             :  * @param h_denom_pub hash of the denomination public key, unused
     793             :  * @param value a `struct TEH_DenominationKey` to free
     794             :  * @return #GNUNET_OK (continue to iterate)
     795             :  */
     796             : static int
     797         301 : clear_denomination_cb (void *cls,
     798             :                        const struct GNUNET_HashCode *h_denom_pub,
     799             :                        void *value)
     800             : {
     801         301 :   struct TEH_DenominationKey *dk = value;
     802             :   struct TEH_AuditorSignature *as;
     803             : 
     804             :   (void) cls;
     805             :   (void) h_denom_pub;
     806         301 :   GNUNET_CRYPTO_rsa_public_key_free (dk->denom_pub.rsa_public_key);
     807         301 :   while (NULL != (as = dk->as_head))
     808             :   {
     809           0 :     GNUNET_CONTAINER_DLL_remove (dk->as_head,
     810             :                                  dk->as_tail,
     811             :                                  as);
     812           0 :     GNUNET_free (as);
     813             :   }
     814         301 :   GNUNET_free (dk);
     815         301 :   return GNUNET_OK;
     816             : }
     817             : 
     818             : 
     819             : /**
     820             :  * Free denomination key data.
     821             :  *
     822             :  * @param cls a `struct TEH_KeyStateHandle`, unused
     823             :  * @param pid the online signing key (type-disguised), unused
     824             :  * @param value a `struct SigningKey` to free
     825             :  * @return #GNUNET_OK (continue to iterate)
     826             :  */
     827             : static int
     828          30 : clear_signkey_cb (void *cls,
     829             :                   const struct GNUNET_PeerIdentity *pid,
     830             :                   void *value)
     831             : {
     832          30 :   struct SigningKey *sk = value;
     833             : 
     834             :   (void) cls;
     835             :   (void) pid;
     836          30 :   GNUNET_free (sk);
     837          30 :   return GNUNET_OK;
     838             : }
     839             : 
     840             : 
     841             : /**
     842             :  * Free resources associated with @a cls, possibly excluding
     843             :  * the helper data.
     844             :  *
     845             :  * @param[in] ksh key state to release
     846             :  * @param free_helper true to also release the helper state
     847             :  */
     848             : static void
     849          52 : destroy_key_state (struct TEH_KeyStateHandle *ksh,
     850             :                    bool free_helper)
     851             : {
     852          52 :   clear_response_cache (ksh);
     853          52 :   GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
     854             :                                          &clear_denomination_cb,
     855             :                                          ksh);
     856          52 :   GNUNET_CONTAINER_multihashmap_destroy (ksh->denomkey_map);
     857          52 :   GNUNET_CONTAINER_multipeermap_iterate (ksh->signkey_map,
     858             :                                          &clear_signkey_cb,
     859             :                                          ksh);
     860          52 :   GNUNET_CONTAINER_multipeermap_destroy (ksh->signkey_map);
     861          52 :   json_decref (ksh->auditors);
     862          52 :   ksh->auditors = NULL;
     863          52 :   if (free_helper)
     864             :   {
     865          36 :     destroy_key_helpers (ksh->helpers);
     866          36 :     GNUNET_free (ksh->helpers);
     867             :   }
     868          52 :   if (NULL != ksh->management_keys_reply)
     869             :   {
     870           8 :     json_decref (ksh->management_keys_reply);
     871           8 :     ksh->management_keys_reply = NULL;
     872             :   }
     873          52 :   GNUNET_free (ksh);
     874          52 : }
     875             : 
     876             : 
     877             : /**
     878             :  * Function called whenever another exchange process has updated
     879             :  * the keys data in the database.
     880             :  *
     881             :  * @param cls NULL
     882             :  * @param extra unused
     883             :  * @param extra_size number of bytes in @a extra unused
     884             :  */
     885             : static void
     886          26 : keys_update_event_cb (void *cls,
     887             :                       const void *extra,
     888             :                       size_t extra_size)
     889             : {
     890             :   (void) cls;
     891             :   (void) extra;
     892             :   (void) extra_size;
     893          26 :   key_generation++;
     894          26 :   TEH_resume_keys_requests (false);
     895          26 : }
     896             : 
     897             : 
     898             : enum GNUNET_GenericReturnValue
     899          12 : TEH_keys_init ()
     900             : {
     901          12 :   struct GNUNET_DB_EventHeaderP es = {
     902          12 :     .size = htons (sizeof (es)),
     903          12 :     .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED),
     904             :   };
     905             : 
     906          12 :   if (GNUNET_OK !=
     907          12 :       GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
     908             :                                            "exchange",
     909             :                                            "SIGNKEY_LEGAL_DURATION",
     910             :                                            &signkey_legal_duration))
     911             :   {
     912           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     913             :                                "exchange",
     914             :                                "SIGNKEY_LEGAL_DURATION");
     915           0 :     return GNUNET_SYSERR;
     916             :   }
     917          12 :   keys_eh = TEH_plugin->event_listen (TEH_plugin->cls,
     918             :                                       GNUNET_TIME_UNIT_FOREVER_REL,
     919             :                                       &es,
     920             :                                       &keys_update_event_cb,
     921             :                                       NULL);
     922          12 :   if (NULL == keys_eh)
     923             :   {
     924           0 :     GNUNET_break (0);
     925           0 :     return GNUNET_SYSERR;
     926             :   }
     927          12 :   return GNUNET_OK;
     928             : }
     929             : 
     930             : 
     931             : /**
     932             :  * Fully clean up our state.
     933             :  */
     934             : void
     935          12 : TEH_keys_finished ()
     936             : {
     937          12 :   if (NULL != key_state)
     938           8 :     destroy_key_state (key_state,
     939             :                        true);
     940          12 :   if (NULL != keys_eh)
     941             :   {
     942          12 :     TEH_plugin->event_listen_cancel (TEH_plugin->cls,
     943             :                                      keys_eh);
     944          12 :     keys_eh = NULL;
     945             :   }
     946          12 : }
     947             : 
     948             : 
     949             : /**
     950             :  * Function called with information about the exchange's denomination keys.
     951             :  *
     952             :  * @param cls closure with a `struct TEH_KeyStateHandle *`
     953             :  * @param denom_pub public key of the denomination
     954             :  * @param h_denom_pub hash of @a denom_pub
     955             :  * @param meta meta data information about the denomination type (value, expirations, fees)
     956             :  * @param master_sig master signature affirming the validity of this denomination
     957             :  * @param recoup_possible true if the key was revoked and clients can currently recoup
     958             :  *        coins of this denomination
     959             :  */
     960             : static void
     961         301 : denomination_info_cb (
     962             :   void *cls,
     963             :   const struct TALER_DenominationPublicKey *denom_pub,
     964             :   const struct GNUNET_HashCode *h_denom_pub,
     965             :   const struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta,
     966             :   const struct TALER_MasterSignatureP *master_sig,
     967             :   bool recoup_possible)
     968             : {
     969         301 :   struct TEH_KeyStateHandle *ksh = cls;
     970             :   struct TEH_DenominationKey *dk;
     971             : 
     972         301 :   if ( (0 == meta->start.abs_value_us) ||
     973         301 :        (0 == meta->expire_withdraw.abs_value_us) ||
     974         301 :        (0 == meta->expire_deposit.abs_value_us) ||
     975         301 :        (0 == meta->expire_legal.abs_value_us) )
     976             :   {
     977           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     978             :                 "Database contains invalid denomination key %s\n",
     979             :                 GNUNET_h2s (h_denom_pub));
     980           0 :     return;
     981             :   }
     982         301 :   dk = GNUNET_new (struct TEH_DenominationKey);
     983             :   dk->denom_pub.rsa_public_key
     984         301 :     = GNUNET_CRYPTO_rsa_public_key_dup (denom_pub->rsa_public_key);
     985         301 :   dk->h_denom_pub = *h_denom_pub;
     986         301 :   dk->meta = *meta;
     987         301 :   dk->master_sig = *master_sig;
     988         301 :   dk->recoup_possible = recoup_possible;
     989         301 :   GNUNET_assert (
     990             :     GNUNET_OK ==
     991             :     GNUNET_CONTAINER_multihashmap_put (ksh->denomkey_map,
     992             :                                        &dk->h_denom_pub,
     993             :                                        dk,
     994             :                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
     995             : }
     996             : 
     997             : 
     998             : /**
     999             :  * Function called with information about the exchange's online signing keys.
    1000             :  *
    1001             :  * @param cls closure with a `struct TEH_KeyStateHandle *`
    1002             :  * @param exchange_pub the public key
    1003             :  * @param meta meta data information about the denomination type (expirations)
    1004             :  * @param master_sig master signature affirming the validity of this denomination
    1005             :  */
    1006             : static void
    1007          30 : signkey_info_cb (
    1008             :   void *cls,
    1009             :   const struct TALER_ExchangePublicKeyP *exchange_pub,
    1010             :   const struct TALER_EXCHANGEDB_SignkeyMetaData *meta,
    1011             :   const struct TALER_MasterSignatureP *master_sig)
    1012             : {
    1013          30 :   struct TEH_KeyStateHandle *ksh = cls;
    1014             :   struct SigningKey *sk;
    1015             :   struct GNUNET_PeerIdentity pid;
    1016             : 
    1017          30 :   sk = GNUNET_new (struct SigningKey);
    1018          30 :   sk->exchange_pub = *exchange_pub;
    1019          30 :   sk->meta = *meta;
    1020          30 :   sk->master_sig = *master_sig;
    1021          30 :   pid.public_key = exchange_pub->eddsa_pub;
    1022          30 :   GNUNET_assert (
    1023             :     GNUNET_OK ==
    1024             :     GNUNET_CONTAINER_multipeermap_put (ksh->signkey_map,
    1025             :                                        &pid,
    1026             :                                        sk,
    1027             :                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    1028          30 : }
    1029             : 
    1030             : 
    1031             : /**
    1032             :  * Closure for #get_auditor_sigs.
    1033             :  */
    1034             : struct GetAuditorSigsContext
    1035             : {
    1036             :   /**
    1037             :    * Where to store the matching signatures.
    1038             :    */
    1039             :   json_t *denom_keys;
    1040             : 
    1041             :   /**
    1042             :    * Public key of the auditor to match against.
    1043             :    */
    1044             :   const struct TALER_AuditorPublicKeyP *auditor_pub;
    1045             : };
    1046             : 
    1047             : 
    1048             : /**
    1049             :  * Extract the auditor signatures matching the auditor's public
    1050             :  * key from the @a value and generate the respective JSON.
    1051             :  *
    1052             :  * @param cls a `struct GetAuditorSigsContext`
    1053             :  * @param h_denom_pub hash of the denomination public key
    1054             :  * @param value a `struct TEH_DenominationKey`
    1055             :  * @return #GNUNET_OK (continue to iterate)
    1056             :  */
    1057             : static int
    1058         236 : get_auditor_sigs (void *cls,
    1059             :                   const struct GNUNET_HashCode *h_denom_pub,
    1060             :                   void *value)
    1061             : {
    1062         236 :   struct GetAuditorSigsContext *ctx = cls;
    1063         236 :   struct TEH_DenominationKey *dk = value;
    1064             : 
    1065         236 :   for (struct TEH_AuditorSignature *as = dk->as_head;
    1066             :        NULL != as;
    1067           0 :        as = as->next)
    1068             :   {
    1069           0 :     if (0 !=
    1070           0 :         GNUNET_memcmp (ctx->auditor_pub,
    1071             :                        &as->apub))
    1072           0 :       continue;
    1073           0 :     GNUNET_break (0 ==
    1074             :                   json_array_append_new (
    1075             :                     ctx->denom_keys,
    1076             :                     GNUNET_JSON_PACK (
    1077             :                       GNUNET_JSON_pack_data_auto ("denom_pub_h",
    1078             :                                                   h_denom_pub),
    1079             :                       GNUNET_JSON_pack_data_auto ("auditor_sig",
    1080             :                                                   &as->asig))));
    1081             :   }
    1082         236 :   return GNUNET_OK;
    1083             : }
    1084             : 
    1085             : 
    1086             : /**
    1087             :  * Function called with information about the exchange's auditors.
    1088             :  *
    1089             :  * @param cls closure with a `struct TEH_KeyStateHandle *`
    1090             :  * @param auditor_pub the public key of the auditor
    1091             :  * @param auditor_url URL of the REST API of the auditor
    1092             :  * @param auditor_name human readable official name of the auditor
    1093             :  */
    1094             : static void
    1095          34 : auditor_info_cb (
    1096             :   void *cls,
    1097             :   const struct TALER_AuditorPublicKeyP *auditor_pub,
    1098             :   const char *auditor_url,
    1099             :   const char *auditor_name)
    1100             : {
    1101          34 :   struct TEH_KeyStateHandle *ksh = cls;
    1102             :   struct GetAuditorSigsContext ctx;
    1103             : 
    1104          34 :   ctx.denom_keys = json_array ();
    1105          34 :   GNUNET_assert (NULL != ctx.denom_keys);
    1106          34 :   ctx.auditor_pub = auditor_pub;
    1107          34 :   GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
    1108             :                                          &get_auditor_sigs,
    1109             :                                          &ctx);
    1110          34 :   GNUNET_break (0 ==
    1111             :                 json_array_append_new (
    1112             :                   ksh->auditors,
    1113             :                   GNUNET_JSON_PACK (
    1114             :                     GNUNET_JSON_pack_string ("auditor_name",
    1115             :                                              auditor_name),
    1116             :                     GNUNET_JSON_pack_data_auto ("auditor_pub",
    1117             :                                                 auditor_pub),
    1118             :                     GNUNET_JSON_pack_string ("auditor_url",
    1119             :                                              auditor_url),
    1120             :                     GNUNET_JSON_pack_array_steal ("denomination_keys",
    1121             :                                                   ctx.denom_keys))));
    1122          34 : }
    1123             : 
    1124             : 
    1125             : /**
    1126             :  * Function called with information about the denominations
    1127             :  * audited by the exchange's auditors.
    1128             :  *
    1129             :  * @param cls closure with a `struct TEH_KeyStateHandle *`
    1130             :  * @param auditor_pub the public key of an auditor
    1131             :  * @param h_denom_pub hash of a denomination key audited by this auditor
    1132             :  * @param auditor_sig signature from the auditor affirming this
    1133             :  */
    1134             : static void
    1135           0 : auditor_denom_cb (
    1136             :   void *cls,
    1137             :   const struct TALER_AuditorPublicKeyP *auditor_pub,
    1138             :   const struct GNUNET_HashCode *h_denom_pub,
    1139             :   const struct TALER_AuditorSignatureP *auditor_sig)
    1140             : {
    1141           0 :   struct TEH_KeyStateHandle *ksh = cls;
    1142             :   struct TEH_DenominationKey *dk;
    1143             :   struct TEH_AuditorSignature *as;
    1144             : 
    1145           0 :   dk = GNUNET_CONTAINER_multihashmap_get (ksh->denomkey_map,
    1146             :                                           h_denom_pub);
    1147           0 :   if (NULL == dk)
    1148             :   {
    1149             :     /* Odd, this should be impossible as per foreign key
    1150             :        constraint on 'auditor_denom_sigs'! Well, we can
    1151             :        safely continue anyway, so let's just log it. */
    1152           0 :     GNUNET_break (0);
    1153           0 :     return;
    1154             :   }
    1155           0 :   as = GNUNET_new (struct TEH_AuditorSignature);
    1156           0 :   as->asig = *auditor_sig;
    1157           0 :   as->apub = *auditor_pub;
    1158           0 :   GNUNET_CONTAINER_DLL_insert (dk->as_head,
    1159             :                                dk->as_tail,
    1160             :                                as);
    1161             : }
    1162             : 
    1163             : 
    1164             : /**
    1165             :  * Closure for #add_sign_key_cb.
    1166             :  */
    1167             : struct SignKeyCtx
    1168             : {
    1169             :   /**
    1170             :    * When does the next signing key expire. Updated.
    1171             :    */
    1172             :   struct GNUNET_TIME_Absolute next_sk_expire;
    1173             : 
    1174             :   /**
    1175             :    * JSON array of signing keys (being created).
    1176             :    */
    1177             :   json_t *signkeys;
    1178             : };
    1179             : 
    1180             : 
    1181             : /**
    1182             :  * Function called for all signing keys, used to build up the
    1183             :  * respective JSON response.
    1184             :  *
    1185             :  * @param cls a `struct SignKeyCtx *` with the array to append keys to
    1186             :  * @param pid the exchange public key (in type disguise)
    1187             :  * @param value a `struct SigningKey`
    1188             :  * @return #GNUNET_OK (continue to iterate)
    1189             :  */
    1190             : static int
    1191          30 : add_sign_key_cb (void *cls,
    1192             :                  const struct GNUNET_PeerIdentity *pid,
    1193             :                  void *value)
    1194             : {
    1195          30 :   struct SignKeyCtx *ctx = cls;
    1196          30 :   struct SigningKey *sk = value;
    1197             : 
    1198             :   ctx->next_sk_expire =
    1199          30 :     GNUNET_TIME_absolute_min (ctx->next_sk_expire,
    1200             :                               sk->meta.expire_sign);
    1201             : 
    1202          30 :   GNUNET_assert (
    1203             :     0 ==
    1204             :     json_array_append_new (
    1205             :       ctx->signkeys,
    1206             :       GNUNET_JSON_PACK (
    1207             :         GNUNET_JSON_pack_time_abs ("stamp_start",
    1208             :                                    sk->meta.start),
    1209             :         GNUNET_JSON_pack_time_abs ("stamp_expire",
    1210             :                                    sk->meta.expire_sign),
    1211             :         GNUNET_JSON_pack_time_abs ("stamp_end",
    1212             :                                    sk->meta.expire_legal),
    1213             :         GNUNET_JSON_pack_data_auto ("master_sig",
    1214             :                                     &sk->master_sig),
    1215             :         GNUNET_JSON_pack_data_auto ("key",
    1216             :                                     &sk->exchange_pub))));
    1217          30 :   return GNUNET_OK;
    1218             : }
    1219             : 
    1220             : 
    1221             : /**
    1222             :  * Closure for #add_denom_key_cb.
    1223             :  */
    1224             : struct DenomKeyCtx
    1225             : {
    1226             :   /**
    1227             :    * Heap for sorting active denomination keys by start time.
    1228             :    */
    1229             :   struct GNUNET_CONTAINER_Heap *heap;
    1230             : 
    1231             :   /**
    1232             :    * JSON array of revoked denomination keys.
    1233             :    */
    1234             :   json_t *recoup;
    1235             : 
    1236             :   /**
    1237             :    * When does the next denomination key expire. Updated.
    1238             :    */
    1239             :   struct GNUNET_TIME_Absolute next_dk_expire;
    1240             : 
    1241             : };
    1242             : 
    1243             : 
    1244             : /**
    1245             :  * Function called for all denomination keys, used to build up the
    1246             :  * JSON list of *revoked* denomination keys and the
    1247             :  * heap of non-revoked denomination keys by timeout.
    1248             :  *
    1249             :  * @param cls a `struct DenomKeyCtx`
    1250             :  * @param h_denom_pub hash of the denomination key
    1251             :  * @param value a `struct TEH_DenominationKey`
    1252             :  * @return #GNUNET_OK (continue to iterate)
    1253             :  */
    1254             : static int
    1255         301 : add_denom_key_cb (void *cls,
    1256             :                   const struct GNUNET_HashCode *h_denom_pub,
    1257             :                   void *value)
    1258             : {
    1259         301 :   struct DenomKeyCtx *dkc = cls;
    1260         301 :   struct TEH_DenominationKey *dk = value;
    1261             : 
    1262         301 :   if (dk->recoup_possible)
    1263             :   {
    1264          16 :     GNUNET_assert (
    1265             :       0 ==
    1266             :       json_array_append_new (
    1267             :         dkc->recoup,
    1268             :         GNUNET_JSON_PACK (
    1269             :           GNUNET_JSON_pack_data_auto ("h_denom_pub",
    1270             :                                       h_denom_pub))));
    1271             :   }
    1272             :   else
    1273             :   {
    1274             :     dkc->next_dk_expire =
    1275         285 :       GNUNET_TIME_absolute_min (dkc->next_dk_expire,
    1276             :                                 dk->meta.expire_withdraw);
    1277         285 :     (void) GNUNET_CONTAINER_heap_insert (dkc->heap,
    1278             :                                          dk,
    1279             :                                          dk->meta.start.abs_value_us);
    1280             :   }
    1281         301 :   return GNUNET_OK;
    1282             : }
    1283             : 
    1284             : 
    1285             : /**
    1286             :  * Produce HTTP "Date:" header.
    1287             :  *
    1288             :  * @param at time to write to @a date
    1289             :  * @param[out] date where to write the header, with
    1290             :  *        at least 128 bytes available space.
    1291             :  */
    1292             : static void
    1293         272 : get_date_string (struct GNUNET_TIME_Absolute at,
    1294             :                  char date[128])
    1295             : {
    1296             :   static const char *const days[] =
    1297             :   { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
    1298             :   static const char *const mons[] =
    1299             :   { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
    1300             :     "Nov", "Dec"};
    1301             :   struct tm now;
    1302             :   time_t t;
    1303             : #if ! defined(HAVE_C11_GMTIME_S) && ! defined(HAVE_W32_GMTIME_S) && \
    1304             :   ! defined(HAVE_GMTIME_R)
    1305             :   struct tm*pNow;
    1306             : #endif
    1307             : 
    1308         272 :   date[0] = 0;
    1309         272 :   t = (time_t) (at.abs_value_us / 1000LL / 1000LL);
    1310             : #if defined(HAVE_C11_GMTIME_S)
    1311             :   if (NULL == gmtime_s (&t, &now))
    1312             :     return;
    1313             : #elif defined(HAVE_W32_GMTIME_S)
    1314             :   if (0 != gmtime_s (&now, &t))
    1315             :     return;
    1316             : #elif defined(HAVE_GMTIME_R)
    1317             :   if (NULL == gmtime_r (&t, &now))
    1318             :     return;
    1319             : #else
    1320         272 :   pNow = gmtime (&t);
    1321         272 :   if (NULL == pNow)
    1322           0 :     return;
    1323         272 :   now = *pNow;
    1324             : #endif
    1325         272 :   sprintf (date,
    1326             :            "%3s, %02u %3s %04u %02u:%02u:%02u GMT",
    1327         272 :            days[now.tm_wday % 7],
    1328         272 :            (unsigned int) now.tm_mday,
    1329         272 :            mons[now.tm_mon % 12],
    1330         272 :            (unsigned int) (1900 + now.tm_year),
    1331         272 :            (unsigned int) now.tm_hour,
    1332         272 :            (unsigned int) now.tm_min,
    1333         272 :            (unsigned int) now.tm_sec);
    1334             : }
    1335             : 
    1336             : 
    1337             : /**
    1338             :  * Add the headers we want to set for every /keys response.
    1339             :  *
    1340             :  * @param ksh the key state to use
    1341             :  * @param[in,out] response the response to modify
    1342             :  * @return #GNUNET_OK on success
    1343             :  */
    1344             : static int
    1345         136 : setup_general_response_headers (const struct TEH_KeyStateHandle *ksh,
    1346             :                                 struct MHD_Response *response)
    1347             : {
    1348             :   char dat[128];
    1349             : 
    1350         136 :   TALER_MHD_add_global_headers (response);
    1351         136 :   GNUNET_break (MHD_YES ==
    1352             :                 MHD_add_response_header (response,
    1353             :                                          MHD_HTTP_HEADER_CONTENT_TYPE,
    1354             :                                          "application/json"));
    1355         136 :   get_date_string (ksh->reload_time,
    1356             :                    dat);
    1357         136 :   GNUNET_break (MHD_YES ==
    1358             :                 MHD_add_response_header (response,
    1359             :                                          MHD_HTTP_HEADER_LAST_MODIFIED,
    1360             :                                          dat));
    1361         136 :   if (0 != ksh->next_reload.abs_value_us)
    1362             :   {
    1363             :     struct GNUNET_TIME_Absolute m;
    1364             : 
    1365         136 :     m = GNUNET_TIME_relative_to_absolute (TEH_max_keys_caching);
    1366         136 :     m = GNUNET_TIME_absolute_min (m,
    1367             :                                   ksh->next_reload);
    1368         136 :     get_date_string (m,
    1369             :                      dat);
    1370         136 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1371             :                 "Setting /keys 'Expires' header to '%s'\n",
    1372             :                 dat);
    1373         136 :     GNUNET_break (MHD_YES ==
    1374             :                   MHD_add_response_header (response,
    1375             :                                            MHD_HTTP_HEADER_EXPIRES,
    1376             :                                            dat));
    1377             :   }
    1378         136 :   return GNUNET_OK;
    1379             : }
    1380             : 
    1381             : 
    1382             : /**
    1383             :  * Initialize @a krd using the given values for @a signkeys,
    1384             :  * @a recoup and @a denoms.
    1385             :  *
    1386             :  * @param[in,out] ksh key state handle we build @a krd for
    1387             :  * @param[in] denom_keys_hash hash over all the denominatoin keys in @a denoms
    1388             :  * @param last_cpd timestamp to use
    1389             :  * @param signkeys list of sign keys to return
    1390             :  * @param recoup list of revoked keys to return
    1391             :  * @param denoms list of denominations to return
    1392             :  * @return #GNUNET_OK on success
    1393             :  */
    1394             : static int
    1395          96 : create_krd (struct TEH_KeyStateHandle *ksh,
    1396             :             const struct GNUNET_HashCode *denom_keys_hash,
    1397             :             struct GNUNET_TIME_Absolute last_cpd,
    1398             :             json_t *signkeys,
    1399             :             json_t *recoup,
    1400             :             json_t *denoms)
    1401             : {
    1402             :   struct KeysResponseData krd;
    1403             :   struct TALER_ExchangePublicKeyP exchange_pub;
    1404             :   struct TALER_ExchangeSignatureP exchange_sig;
    1405             :   json_t *keys;
    1406             : 
    1407          96 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1408             :               "Creating /keys at cherry pick date %s\n",
    1409             :               GNUNET_STRINGS_absolute_time_to_string (last_cpd));
    1410             :   /* Sign hash over denomination keys */
    1411             :   {
    1412         192 :     struct TALER_ExchangeKeySetPS ks = {
    1413          96 :       .purpose.size = htonl (sizeof (ks)),
    1414          96 :       .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_KEY_SET),
    1415          96 :       .list_issue_date = GNUNET_TIME_absolute_hton (last_cpd),
    1416             :       .hc = *denom_keys_hash
    1417             :     };
    1418             :     enum TALER_ErrorCode ec;
    1419             : 
    1420          96 :     if (TALER_EC_NONE !=
    1421          96 :         (ec = TEH_keys_exchange_sign2 (ksh,
    1422             :                                        &ks,
    1423             :                                        &exchange_pub,
    1424             :                                        &exchange_sig)))
    1425             :     {
    1426          28 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1427             :                   "Could not create key response data: cannot sign (%s)\n",
    1428             :                   TALER_ErrorCode_get_hint (ec));
    1429          28 :       return GNUNET_SYSERR;
    1430             :     }
    1431             :   }
    1432             :   {
    1433             :     const struct SigningKey *sk;
    1434             : 
    1435          68 :     sk = GNUNET_CONTAINER_multipeermap_get (
    1436          68 :       ksh->signkey_map,
    1437             :       (const struct GNUNET_PeerIdentity *) &exchange_pub);
    1438          68 :     ksh->signature_expires = GNUNET_TIME_absolute_min (sk->meta.expire_sign,
    1439             :                                                        ksh->signature_expires);
    1440             :   }
    1441             : 
    1442          68 :   keys = GNUNET_JSON_PACK (
    1443             :     GNUNET_JSON_pack_string ("version",
    1444             :                              EXCHANGE_PROTOCOL_VERSION),
    1445             :     GNUNET_JSON_pack_string ("currency",
    1446             :                              TEH_currency),
    1447             :     GNUNET_JSON_pack_data_auto ("master_public_key",
    1448             :                                 &TEH_master_public_key),
    1449             :     GNUNET_JSON_pack_time_rel ("reserve_closing_delay",
    1450             :                                TEH_reserve_closing_delay),
    1451             :     GNUNET_JSON_pack_array_incref ("signkeys",
    1452             :                                    signkeys),
    1453             :     GNUNET_JSON_pack_array_incref ("recoup",
    1454             :                                    recoup),
    1455             :     GNUNET_JSON_pack_array_incref ("denoms",
    1456             :                                    denoms),
    1457             :     GNUNET_JSON_pack_array_incref ("auditors",
    1458             :                                    ksh->auditors),
    1459             :     GNUNET_JSON_pack_time_abs ("list_issue_date",
    1460             :                                last_cpd),
    1461             :     GNUNET_JSON_pack_data_auto ("eddsa_pub",
    1462             :                                 &exchange_pub),
    1463             :     GNUNET_JSON_pack_data_auto ("eddsa_sig",
    1464             :                                 &exchange_sig));
    1465          68 :   GNUNET_assert (NULL != keys);
    1466             : 
    1467             :   {
    1468             :     char *keys_json;
    1469             :     void *keys_jsonz;
    1470             :     size_t keys_jsonz_size;
    1471             :     int comp;
    1472             : 
    1473             :     /* Convert /keys response to UTF8-String */
    1474          68 :     keys_json = json_dumps (keys,
    1475             :                             JSON_INDENT (2));
    1476          68 :     json_decref (keys);
    1477          68 :     GNUNET_assert (NULL != keys_json);
    1478             : 
    1479             :     /* Keep copy for later compression... */
    1480          68 :     keys_jsonz = GNUNET_strdup (keys_json);
    1481          68 :     keys_jsonz_size = strlen (keys_json);
    1482             : 
    1483             :     /* Create uncompressed response */
    1484             :     krd.response_uncompressed
    1485          68 :       = MHD_create_response_from_buffer (keys_jsonz_size,
    1486             :                                          keys_json,
    1487             :                                          MHD_RESPMEM_MUST_FREE);
    1488          68 :     GNUNET_assert (NULL != krd.response_uncompressed);
    1489          68 :     GNUNET_assert (GNUNET_OK ==
    1490             :                    setup_general_response_headers (ksh,
    1491             :                                                    krd.response_uncompressed));
    1492             :     /* Also compute compressed version of /keys response */
    1493          68 :     comp = TALER_MHD_body_compress (&keys_jsonz,
    1494             :                                     &keys_jsonz_size);
    1495             :     krd.response_compressed
    1496          68 :       = MHD_create_response_from_buffer (keys_jsonz_size,
    1497             :                                          keys_jsonz,
    1498             :                                          MHD_RESPMEM_MUST_FREE);
    1499          68 :     GNUNET_assert (NULL != krd.response_compressed);
    1500             :     /* If the response is actually compressed, set the
    1501             :        respective header. */
    1502          68 :     GNUNET_assert ( (MHD_YES != comp) ||
    1503             :                     (MHD_YES ==
    1504             :                      MHD_add_response_header (krd.response_compressed,
    1505             :                                               MHD_HTTP_HEADER_CONTENT_ENCODING,
    1506             :                                               "deflate")) );
    1507          68 :     GNUNET_assert (GNUNET_OK ==
    1508             :                    setup_general_response_headers (ksh,
    1509             :                                                    krd.response_compressed));
    1510             :   }
    1511          68 :   krd.cherry_pick_date = last_cpd;
    1512          68 :   GNUNET_array_append (ksh->krd_array,
    1513             :                        ksh->krd_array_length,
    1514             :                        krd);
    1515          68 :   return GNUNET_OK;
    1516             : }
    1517             : 
    1518             : 
    1519             : /**
    1520             :  * Update the "/keys" responses in @a ksh, computing the detailed replies.
    1521             :  *
    1522             :  * This function is to recompute all (including cherry-picked) responses we
    1523             :  * might want to return, based on the state already in @a ksh.
    1524             :  *
    1525             :  * @param[in,out] ksh state handle to update
    1526             :  * @return #GNUNET_OK on success
    1527             :  */
    1528             : static int
    1529          44 : finish_keys_response (struct TEH_KeyStateHandle *ksh)
    1530             : {
    1531             :   json_t *recoup;
    1532             :   struct SignKeyCtx sctx;
    1533             :   json_t *denoms;
    1534             :   struct GNUNET_TIME_Absolute last_cpd;
    1535             :   struct GNUNET_CONTAINER_Heap *heap;
    1536             :   struct GNUNET_HashContext *hash_context;
    1537             : 
    1538          44 :   sctx.signkeys = json_array ();
    1539          44 :   sctx.next_sk_expire = GNUNET_TIME_UNIT_FOREVER_ABS;
    1540          44 :   GNUNET_assert (NULL != sctx.signkeys);
    1541          44 :   GNUNET_CONTAINER_multipeermap_iterate (ksh->signkey_map,
    1542             :                                          &add_sign_key_cb,
    1543             :                                          &sctx);
    1544          44 :   recoup = json_array ();
    1545          44 :   GNUNET_assert (NULL != recoup);
    1546          44 :   heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX);
    1547             :   {
    1548          44 :     struct DenomKeyCtx dkc = {
    1549             :       .recoup = recoup,
    1550             :       .heap = heap,
    1551          44 :       .next_dk_expire = GNUNET_TIME_UNIT_FOREVER_ABS,
    1552             :     };
    1553             : 
    1554          44 :     GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
    1555             :                                            &add_denom_key_cb,
    1556             :                                            &dkc);
    1557             :     ksh->next_reload
    1558          44 :       = GNUNET_TIME_absolute_min (dkc.next_dk_expire,
    1559             :                                   sctx.next_sk_expire);
    1560             :   }
    1561          44 :   denoms = json_array ();
    1562          44 :   GNUNET_assert (NULL != denoms);
    1563          44 :   last_cpd = GNUNET_TIME_UNIT_ZERO_ABS;
    1564          44 :   hash_context = GNUNET_CRYPTO_hash_context_start ();
    1565             :   {
    1566             :     struct TEH_DenominationKey *dk;
    1567             : 
    1568             :     /* heap = min heap, sorted by start time */
    1569         313 :     while (NULL != (dk = GNUNET_CONTAINER_heap_remove_root (heap)))
    1570             :     {
    1571         271 :       if ( (last_cpd.abs_value_us != dk->meta.start.abs_value_us) &&
    1572          72 :            (0 != last_cpd.abs_value_us) )
    1573             :       {
    1574             :         struct GNUNET_HashCode hc;
    1575             : 
    1576          54 :         GNUNET_CRYPTO_hash_context_finish (
    1577             :           GNUNET_CRYPTO_hash_context_copy (hash_context),
    1578             :           &hc);
    1579          54 :         if (GNUNET_OK !=
    1580          54 :             create_krd (ksh,
    1581             :                         &hc,
    1582             :                         last_cpd,
    1583             :                         sctx.signkeys,
    1584             :                         recoup,
    1585             :                         denoms))
    1586             :         {
    1587           2 :           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1588             :                       "Failed to generate key response data for %s\n",
    1589             :                       GNUNET_STRINGS_absolute_time_to_string (last_cpd));
    1590           2 :           GNUNET_CRYPTO_hash_context_abort (hash_context);
    1591             :           /* drain heap before destroying it */
    1592          16 :           while (NULL != (dk = GNUNET_CONTAINER_heap_remove_root (heap)))
    1593             :             /* intentionally empty */;
    1594           2 :           GNUNET_CONTAINER_heap_destroy (heap);
    1595           2 :           json_decref (denoms);
    1596           2 :           json_decref (sctx.signkeys);
    1597           2 :           json_decref (recoup);
    1598           2 :           return GNUNET_SYSERR;
    1599             :         }
    1600             :       }
    1601         269 :       last_cpd = dk->meta.start;
    1602         269 :       GNUNET_CRYPTO_hash_context_read (hash_context,
    1603         269 :                                        &dk->h_denom_pub,
    1604             :                                        sizeof (struct GNUNET_HashCode));
    1605         269 :       GNUNET_assert (
    1606             :         0 ==
    1607             :         json_array_append_new (
    1608             :           denoms,
    1609             :           GNUNET_JSON_PACK (
    1610             :             GNUNET_JSON_pack_data_auto ("master_sig",
    1611             :                                         &dk->master_sig),
    1612             :             GNUNET_JSON_pack_time_abs ("stamp_start",
    1613             :                                        dk->meta.start),
    1614             :             GNUNET_JSON_pack_time_abs ("stamp_expire_withdraw",
    1615             :                                        dk->meta.expire_withdraw),
    1616             :             GNUNET_JSON_pack_time_abs ("stamp_expire_deposit",
    1617             :                                        dk->meta.expire_deposit),
    1618             :             GNUNET_JSON_pack_time_abs ("stamp_expire_legal",
    1619             :                                        dk->meta.expire_legal),
    1620             :             GNUNET_JSON_pack_rsa_public_key ("denom_pub",
    1621             :                                              dk->denom_pub.rsa_public_key),
    1622             :             TALER_JSON_pack_amount ("value",
    1623             :                                     &dk->meta.value),
    1624             :             TALER_JSON_pack_amount ("fee_withdraw",
    1625             :                                     &dk->meta.fee_withdraw),
    1626             :             TALER_JSON_pack_amount ("fee_deposit",
    1627             :                                     &dk->meta.fee_deposit),
    1628             :             TALER_JSON_pack_amount ("fee_refresh",
    1629             :                                     &dk->meta.fee_refresh),
    1630             :             TALER_JSON_pack_amount ("fee_refund",
    1631             :                                     &dk->meta.fee_refund))));
    1632             :     }
    1633             :   }
    1634          42 :   GNUNET_CONTAINER_heap_destroy (heap);
    1635             :   {
    1636             :     struct GNUNET_HashCode hc;
    1637             : 
    1638          42 :     GNUNET_CRYPTO_hash_context_finish (hash_context,
    1639             :                                        &hc);
    1640          42 :     if (GNUNET_OK !=
    1641          42 :         create_krd (ksh,
    1642             :                     &hc,
    1643             :                     last_cpd,
    1644             :                     sctx.signkeys,
    1645             :                     recoup,
    1646             :                     denoms))
    1647             :     {
    1648          26 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1649             :                   "Failed to generate key response data for %s\n",
    1650             :                   GNUNET_STRINGS_absolute_time_to_string (last_cpd));
    1651          26 :       json_decref (denoms);
    1652          26 :       json_decref (sctx.signkeys);
    1653          26 :       json_decref (recoup);
    1654          26 :       return GNUNET_SYSERR;
    1655             :     }
    1656             :   }
    1657          16 :   json_decref (sctx.signkeys);
    1658          16 :   json_decref (recoup);
    1659          16 :   json_decref (denoms);
    1660          16 :   ksh->management_only = false;
    1661          16 :   return GNUNET_OK;
    1662             : }
    1663             : 
    1664             : 
    1665             : /**
    1666             :  * Create a key state.
    1667             :  *
    1668             :  * @param[in] hs helper state to (re)use, NULL if not available
    1669             :  * @param management_only if we should NOT run 'finish_keys_response()'
    1670             :  *                  because we only need the state for the /management/keys API
    1671             :  * @return NULL on error (i.e. failed to access database)
    1672             :  */
    1673             : static struct TEH_KeyStateHandle *
    1674          58 : build_key_state (struct HelperState *hs,
    1675             :                  bool management_only)
    1676             : {
    1677             :   struct TEH_KeyStateHandle *ksh;
    1678             :   enum GNUNET_DB_QueryStatus qs;
    1679             : 
    1680          58 :   ksh = GNUNET_new (struct TEH_KeyStateHandle);
    1681          58 :   ksh->signature_expires = GNUNET_TIME_UNIT_FOREVER_ABS;
    1682          58 :   ksh->reload_time = GNUNET_TIME_absolute_get ();
    1683          58 :   GNUNET_TIME_round_abs (&ksh->reload_time);
    1684             :   /* We must use the key_generation from when we STARTED the process! */
    1685          58 :   ksh->key_generation = key_generation;
    1686          58 :   if (NULL == hs)
    1687             :   {
    1688          42 :     ksh->helpers = GNUNET_new (struct HelperState);
    1689          42 :     if (GNUNET_OK !=
    1690          42 :         setup_key_helpers (ksh->helpers))
    1691             :     {
    1692           6 :       GNUNET_free (ksh->helpers);
    1693           6 :       GNUNET_assert (NULL == ksh->management_keys_reply);
    1694           6 :       GNUNET_free (ksh);
    1695           6 :       return NULL;
    1696             :     }
    1697             :   }
    1698             :   else
    1699             :   {
    1700          16 :     ksh->helpers = hs;
    1701             :   }
    1702          52 :   ksh->denomkey_map = GNUNET_CONTAINER_multihashmap_create (1024,
    1703             :                                                             GNUNET_YES);
    1704          52 :   ksh->signkey_map = GNUNET_CONTAINER_multipeermap_create (32,
    1705             :                                                            GNUNET_NO /* MUST be NO! */);
    1706          52 :   ksh->auditors = json_array ();
    1707          52 :   GNUNET_assert (NULL != ksh->auditors);
    1708             :   /* NOTE: fetches master-signed signkeys, but ALSO those that were revoked! */
    1709          52 :   qs = TEH_plugin->iterate_denominations (TEH_plugin->cls,
    1710             :                                           &denomination_info_cb,
    1711             :                                           ksh);
    1712          52 :   if (qs < 0)
    1713             :   {
    1714           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
    1715           0 :     GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
    1716           0 :     destroy_key_state (ksh,
    1717             :                        true);
    1718           0 :     return NULL;
    1719             :   }
    1720             :   /* NOTE: ONLY fetches non-revoked AND master-signed signkeys! */
    1721          52 :   qs = TEH_plugin->iterate_active_signkeys (TEH_plugin->cls,
    1722             :                                             &signkey_info_cb,
    1723             :                                             ksh);
    1724          52 :   if (qs < 0)
    1725             :   {
    1726           0 :     GNUNET_break (0);
    1727           0 :     destroy_key_state (ksh,
    1728             :                        true);
    1729           0 :     return NULL;
    1730             :   }
    1731          52 :   qs = TEH_plugin->iterate_auditor_denominations (TEH_plugin->cls,
    1732             :                                                   &auditor_denom_cb,
    1733             :                                                   ksh);
    1734          52 :   if (qs < 0)
    1735             :   {
    1736           0 :     GNUNET_break (0);
    1737           0 :     destroy_key_state (ksh,
    1738             :                        true);
    1739           0 :     return NULL;
    1740             :   }
    1741          52 :   qs = TEH_plugin->iterate_active_auditors (TEH_plugin->cls,
    1742             :                                             &auditor_info_cb,
    1743             :                                             ksh);
    1744          52 :   if (qs < 0)
    1745             :   {
    1746           0 :     GNUNET_break (0);
    1747           0 :     destroy_key_state (ksh,
    1748             :                        true);
    1749           0 :     return NULL;
    1750             :   }
    1751          52 :   if (management_only)
    1752             :   {
    1753           8 :     ksh->management_only = true;
    1754           8 :     return ksh;
    1755             :   }
    1756          44 :   if (GNUNET_OK !=
    1757          44 :       finish_keys_response (ksh))
    1758             :   {
    1759          28 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1760             :                 "Could not finish /keys response (likely no signing keys available yet)\n");
    1761          28 :     destroy_key_state (ksh,
    1762             :                        true);
    1763          28 :     return NULL;
    1764             :   }
    1765          16 :   return ksh;
    1766             : }
    1767             : 
    1768             : 
    1769             : void
    1770          26 : TEH_keys_update_states ()
    1771             : {
    1772          26 :   struct GNUNET_DB_EventHeaderP es = {
    1773          26 :     .size = htons (sizeof (es)),
    1774          26 :     .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED),
    1775             :   };
    1776             : 
    1777          26 :   TEH_plugin->event_notify (TEH_plugin->cls,
    1778             :                             &es,
    1779             :                             NULL,
    1780             :                             0);
    1781          26 :   key_generation++;
    1782          26 :   TEH_resume_keys_requests (false);
    1783          26 : }
    1784             : 
    1785             : 
    1786             : /**
    1787             :  * Obtain the key state for the current thread. Should ONLY be used
    1788             :  * directly if @a management_only is true. Otherwise use #TEH_keys_get_state().
    1789             :  *
    1790             :  * @param management_only if we should NOT run 'finish_keys_response()'
    1791             :  *                  because we only need the state for the /management/keys API
    1792             :  * @return NULL on error
    1793             :  */
    1794             : static struct TEH_KeyStateHandle *
    1795         465 : get_key_state (bool management_only)
    1796             : {
    1797             :   struct TEH_KeyStateHandle *old_ksh;
    1798             :   struct TEH_KeyStateHandle *ksh;
    1799             : 
    1800         465 :   old_ksh = key_state;
    1801         465 :   if (NULL == old_ksh)
    1802             :   {
    1803          42 :     ksh = build_key_state (NULL,
    1804             :                            management_only);
    1805          42 :     if (NULL == ksh)
    1806          34 :       return NULL;
    1807           8 :     key_state = ksh;
    1808           8 :     return ksh;
    1809             :   }
    1810         830 :   if ( (old_ksh->key_generation < key_generation) ||
    1811         407 :        (GNUNET_TIME_absolute_is_past (old_ksh->signature_expires)) )
    1812             :   {
    1813          16 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1814             :                 "Rebuilding /keys, generation upgrade from %llu to %llu\n",
    1815             :                 (unsigned long long) old_ksh->key_generation,
    1816             :                 (unsigned long long) key_generation);
    1817          16 :     ksh = build_key_state (old_ksh->helpers,
    1818             :                            management_only);
    1819          16 :     key_state = ksh;
    1820          16 :     old_ksh->helpers = NULL;
    1821          16 :     destroy_key_state (old_ksh,
    1822             :                        false);
    1823          16 :     return ksh;
    1824             :   }
    1825         407 :   sync_key_helpers (old_ksh->helpers);
    1826         407 :   return old_ksh;
    1827             : }
    1828             : 
    1829             : 
    1830             : struct TEH_KeyStateHandle *
    1831         325 : TEH_keys_get_state (void)
    1832             : {
    1833             :   struct TEH_KeyStateHandle *ksh;
    1834             : 
    1835         325 :   ksh = get_key_state (false);
    1836         325 :   if (NULL == ksh)
    1837          32 :     return NULL;
    1838         293 :   if (ksh->management_only)
    1839             :   {
    1840           0 :     if (GNUNET_OK !=
    1841           0 :         finish_keys_response (ksh))
    1842           0 :       return NULL;
    1843             :   }
    1844         293 :   return ksh;
    1845             : }
    1846             : 
    1847             : 
    1848             : struct TEH_DenominationKey *
    1849         127 : TEH_keys_denomination_by_hash (const struct GNUNET_HashCode *h_denom_pub,
    1850             :                                struct MHD_Connection *conn,
    1851             :                                MHD_RESULT *mret)
    1852             : {
    1853             :   struct TEH_KeyStateHandle *ksh;
    1854             : 
    1855         127 :   ksh = TEH_keys_get_state ();
    1856         127 :   if (NULL == ksh)
    1857             :   {
    1858           0 :     *mret = TALER_MHD_reply_with_error (conn,
    1859             :                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
    1860             :                                         TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
    1861             :                                         NULL);
    1862           0 :     return NULL;
    1863             :   }
    1864         127 :   return TEH_keys_denomination_by_hash2 (ksh,
    1865             :                                          h_denom_pub,
    1866             :                                          conn,
    1867             :                                          mret);
    1868             : }
    1869             : 
    1870             : 
    1871             : struct TEH_DenominationKey *
    1872         150 : TEH_keys_denomination_by_hash2 (struct TEH_KeyStateHandle *ksh,
    1873             :                                 const struct GNUNET_HashCode *h_denom_pub,
    1874             :                                 struct MHD_Connection *conn,
    1875             :                                 MHD_RESULT *mret)
    1876             : {
    1877             :   struct TEH_DenominationKey *dk;
    1878             : 
    1879         150 :   dk = GNUNET_CONTAINER_multihashmap_get (ksh->denomkey_map,
    1880             :                                           h_denom_pub);
    1881         150 :   if (NULL == dk)
    1882             :   {
    1883           0 :     *mret = TEH_RESPONSE_reply_unknown_denom_pub_hash (conn,
    1884             :                                                        h_denom_pub);
    1885           0 :     return NULL;
    1886             :   }
    1887         150 :   return dk;
    1888             : }
    1889             : 
    1890             : 
    1891             : struct TALER_DenominationSignature
    1892          61 : TEH_keys_denomination_sign (const struct GNUNET_HashCode *h_denom_pub,
    1893             :                             const void *msg,
    1894             :                             size_t msg_size,
    1895             :                             enum TALER_ErrorCode *ec)
    1896             : {
    1897             :   struct TEH_KeyStateHandle *ksh;
    1898          61 :   struct TALER_DenominationSignature none = { NULL };
    1899             : 
    1900          61 :   ksh = TEH_keys_get_state ();
    1901          61 :   if (NULL == ksh)
    1902             :   {
    1903           0 :     *ec = TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
    1904           0 :     return none;
    1905             :   }
    1906          61 :   return TALER_CRYPTO_helper_denom_sign (ksh->helpers->dh,
    1907             :                                          h_denom_pub,
    1908             :                                          msg,
    1909             :                                          msg_size,
    1910             :                                          ec);
    1911             : }
    1912             : 
    1913             : 
    1914             : void
    1915           8 : TEH_keys_denomination_revoke (const struct GNUNET_HashCode *h_denom_pub)
    1916             : {
    1917             :   struct TEH_KeyStateHandle *ksh;
    1918             : 
    1919           8 :   ksh = TEH_keys_get_state ();
    1920           8 :   if (NULL == ksh)
    1921             :   {
    1922           0 :     GNUNET_break (0);
    1923           0 :     return;
    1924             :   }
    1925           8 :   TALER_CRYPTO_helper_denom_revoke (ksh->helpers->dh,
    1926             :                                     h_denom_pub);
    1927           8 :   TEH_keys_update_states ();
    1928             : }
    1929             : 
    1930             : 
    1931             : enum TALER_ErrorCode
    1932          72 : TEH_keys_exchange_sign_ (
    1933             :   const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
    1934             :   struct TALER_ExchangePublicKeyP *pub,
    1935             :   struct TALER_ExchangeSignatureP *sig)
    1936             : {
    1937             :   struct TEH_KeyStateHandle *ksh;
    1938             : 
    1939          72 :   ksh = TEH_keys_get_state ();
    1940          72 :   if (NULL == ksh)
    1941             :   {
    1942             :     /* This *can* happen if the exchange's crypto helper is not running
    1943             :        or had some bad error. */
    1944           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1945             :                 "Cannot sign request, no valid signing keys available.\n");
    1946           0 :     return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
    1947             :   }
    1948          72 :   return TEH_keys_exchange_sign2_ (ksh,
    1949             :                                    purpose,
    1950             :                                    pub,
    1951             :                                    sig);
    1952             : }
    1953             : 
    1954             : 
    1955             : enum TALER_ErrorCode
    1956         168 : TEH_keys_exchange_sign2_ (
    1957             :   struct TEH_KeyStateHandle *ksh,
    1958             :   const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
    1959             :   struct TALER_ExchangePublicKeyP *pub,
    1960             :   struct TALER_ExchangeSignatureP *sig)
    1961             : {
    1962             :   enum TALER_ErrorCode ec;
    1963             : 
    1964         168 :   ec = TALER_CRYPTO_helper_esign_sign_ (ksh->helpers->esh,
    1965             :                                         purpose,
    1966             :                                         pub,
    1967             :                                         sig);
    1968         168 :   if (TALER_EC_NONE != ec)
    1969           0 :     return ec;
    1970             :   {
    1971             :     /* Here we check here that 'pub' is set to an exchange public key that is
    1972             :        actually signed by the master key! Otherwise, we happily continue to
    1973             :        use key material even if the offline signatures have not been made
    1974             :        yet! */
    1975             :     struct GNUNET_PeerIdentity pid;
    1976             :     struct SigningKey *sk;
    1977             : 
    1978         168 :     pid.public_key = pub->eddsa_pub;
    1979         168 :     sk = GNUNET_CONTAINER_multipeermap_get (ksh->signkey_map,
    1980             :                                             &pid);
    1981         168 :     if (NULL == sk)
    1982             :     {
    1983             :       /* just to be safe, zero out the (valid) signature, as the key
    1984             :          should not or no longer be used */
    1985          28 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1986             :                   "Cannot sign, offline key signatures are missing!\n");
    1987          28 :       memset (sig,
    1988             :               0,
    1989             :               sizeof (*sig));
    1990          28 :       return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    1991             :     }
    1992             :   }
    1993         140 :   return ec;
    1994             : }
    1995             : 
    1996             : 
    1997             : void
    1998           0 : TEH_keys_exchange_revoke (const struct TALER_ExchangePublicKeyP *exchange_pub)
    1999             : {
    2000             :   struct TEH_KeyStateHandle *ksh;
    2001             : 
    2002           0 :   ksh = TEH_keys_get_state ();
    2003           0 :   if (NULL == ksh)
    2004             :   {
    2005           0 :     GNUNET_break (0);
    2006           0 :     return;
    2007             :   }
    2008           0 :   TALER_CRYPTO_helper_esign_revoke (ksh->helpers->esh,
    2009             :                                     exchange_pub);
    2010           0 :   TEH_keys_update_states ();
    2011             : }
    2012             : 
    2013             : 
    2014             : /**
    2015             :  * Comparator used for a binary search by cherry_pick_date for @a key in the
    2016             :  * `struct KeysResponseData` array. See libc's qsort() and bsearch() functions.
    2017             :  *
    2018             :  * @param key pointer to a `struct GNUNET_TIME_Absolute`
    2019             :  * @param value pointer to a `struct KeysResponseData` array entry
    2020             :  * @return 0 if time matches, -1 if key is smaller, 1 if key is larger
    2021             :  */
    2022             : static int
    2023          41 : krd_search_comparator (const void *key,
    2024             :                        const void *value)
    2025             : {
    2026          41 :   const struct GNUNET_TIME_Absolute *kd = key;
    2027          41 :   const struct KeysResponseData *krd = value;
    2028             : 
    2029          41 :   if (kd->abs_value_us > krd->cherry_pick_date.abs_value_us)
    2030          14 :     return -1;
    2031          27 :   if (kd->abs_value_us < krd->cherry_pick_date.abs_value_us)
    2032          20 :     return 1;
    2033           7 :   return 0;
    2034             : }
    2035             : 
    2036             : 
    2037             : MHD_RESULT
    2038          49 : TEH_keys_get_handler (struct TEH_RequestContext *rc,
    2039             :                       const char *const args[])
    2040             : {
    2041             :   struct GNUNET_TIME_Absolute last_issue_date;
    2042             : 
    2043             :   (void) args;
    2044             :   {
    2045             :     const char *have_cherrypick;
    2046             : 
    2047          49 :     have_cherrypick = MHD_lookup_connection_value (rc->connection,
    2048             :                                                    MHD_GET_ARGUMENT_KIND,
    2049             :                                                    "last_issue_date");
    2050          49 :     if (NULL != have_cherrypick)
    2051             :     {
    2052             :       unsigned long long cherrypickn;
    2053             : 
    2054           7 :       if (1 !=
    2055           7 :           sscanf (have_cherrypick,
    2056             :                   "%llu",
    2057             :                   &cherrypickn))
    2058             :       {
    2059           0 :         GNUNET_break_op (0);
    2060           0 :         return TALER_MHD_reply_with_error (rc->connection,
    2061             :                                            MHD_HTTP_BAD_REQUEST,
    2062             :                                            TALER_EC_GENERIC_PARAMETER_MALFORMED,
    2063             :                                            have_cherrypick);
    2064             :       }
    2065             :       /* The following multiplication may overflow; but this should not really
    2066             :          be a problem, as giving back 'older' data than what the client asks for
    2067             :          (given that the client asks for data in the distant future) is not
    2068             :          problematic */
    2069           7 :       last_issue_date = GNUNET_TIME_absolute_from_s (cherrypickn);
    2070             :     }
    2071             :     else
    2072             :     {
    2073          42 :       last_issue_date.abs_value_us = 0LLU;
    2074             :     }
    2075             :   }
    2076             : 
    2077             :   {
    2078             :     struct TEH_KeyStateHandle *ksh;
    2079             :     const struct KeysResponseData *krd;
    2080             : 
    2081          49 :     ksh = TEH_keys_get_state ();
    2082          49 :     if (NULL == ksh)
    2083             :     {
    2084          32 :       if ( (SKR_LIMIT == skr_size) &&
    2085           0 :            (rc->connection == skr_connection) )
    2086             :       {
    2087           0 :         return TALER_MHD_reply_with_error (rc->connection,
    2088             :                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    2089             :                                            TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
    2090             :                                            "too many connections suspended on /keys");
    2091             :       }
    2092          32 :       return suspend_request (rc->connection);
    2093             :     }
    2094          17 :     krd = bsearch (&last_issue_date,
    2095          17 :                    ksh->krd_array,
    2096          17 :                    ksh->krd_array_length,
    2097             :                    sizeof (struct KeysResponseData),
    2098             :                    &krd_search_comparator);
    2099          17 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2100             :                 "Filtering /keys by cherry pick date %s found entry %u/%u\n",
    2101             :                 GNUNET_STRINGS_absolute_time_to_string (last_issue_date),
    2102             :                 (unsigned int) (krd - ksh->krd_array),
    2103             :                 ksh->krd_array_length);
    2104          17 :     if ( (NULL == krd) &&
    2105          10 :          (ksh->krd_array_length > 0) )
    2106             :     {
    2107          10 :       if (0 != last_issue_date.abs_value_us)
    2108           0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    2109             :                     "Client provided invalid cherry picking timestamp %s, returning full response\n",
    2110             :                     GNUNET_STRINGS_absolute_time_to_string (last_issue_date));
    2111          10 :       krd = &ksh->krd_array[ksh->krd_array_length - 1];
    2112             :     }
    2113          17 :     if (NULL == krd)
    2114             :     {
    2115             :       /* Maybe client picked time stamp too far in the future?  In that case,
    2116             :          "INTERNAL_SERVER_ERROR" might be misleading, could be more like a
    2117             :          NOT_FOUND situation. But, OTOH, for 'sane' clients it is more likely
    2118             :          to be our fault, so let's speculatively assume we are to blame ;-) *///
    2119           0 :       GNUNET_break (0);
    2120           0 :       return TALER_MHD_reply_with_error (rc->connection,
    2121             :                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
    2122             :                                          TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
    2123             :                                          "no key data for given timestamp");
    2124             :     }
    2125          17 :     return MHD_queue_response (rc->connection,
    2126             :                                MHD_HTTP_OK,
    2127             :                                (MHD_YES ==
    2128          17 :                                 TALER_MHD_can_compress (rc->connection))
    2129             :                                ? krd->response_compressed
    2130             :                                : krd->response_uncompressed);
    2131             :   }
    2132             : }
    2133             : 
    2134             : 
    2135             : /**
    2136             :  * Load fees and expiration times (!) for the denomination type configured in
    2137             :  * section @a section_name.  Before calling this function, the `start` and
    2138             :  * `validity_duration` times must already be initialized in @a meta.
    2139             :  *
    2140             :  * @param section_name section in the configuration to use
    2141             :  * @param[in,out] meta denomination type data to complete
    2142             :  * @return #GNUNET_OK on success
    2143             :  */
    2144             : static enum GNUNET_GenericReturnValue
    2145         232 : load_fees (const char *section_name,
    2146             :            struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta)
    2147             : {
    2148             :   struct GNUNET_TIME_Relative deposit_duration;
    2149             :   struct GNUNET_TIME_Relative legal_duration;
    2150             : 
    2151         232 :   GNUNET_assert (0 != meta->start.abs_value_us); /* caller bug */
    2152         232 :   if (GNUNET_OK !=
    2153         232 :       GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
    2154             :                                            section_name,
    2155             :                                            "DURATION_SPEND",
    2156             :                                            &deposit_duration))
    2157             :   {
    2158           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    2159             :                                section_name,
    2160             :                                "DURATION_SPEND");
    2161           0 :     return GNUNET_SYSERR;
    2162             :   }
    2163         232 :   if (GNUNET_OK !=
    2164         232 :       GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
    2165             :                                            section_name,
    2166             :                                            "DURATION_LEGAL",
    2167             :                                            &legal_duration))
    2168             :   {
    2169           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    2170             :                                section_name,
    2171             :                                "DURATION_LEGAL");
    2172           0 :     return GNUNET_SYSERR;
    2173             :   }
    2174             :   /* NOTE: this is a change from the 0.8 semantics of the configuration:
    2175             :      before duration_spend was relative to 'start', not to 'expire_withdraw'.
    2176             :      But doing it this way avoids the error case where previously
    2177             :      duration_spend < duration_withdraw was not allowed. */
    2178         232 :   meta->expire_deposit = GNUNET_TIME_absolute_add (meta->expire_withdraw,
    2179             :                                                    deposit_duration);
    2180         232 :   meta->expire_legal = GNUNET_TIME_absolute_add (meta->expire_deposit,
    2181             :                                                  legal_duration);
    2182         232 :   if (GNUNET_OK !=
    2183         232 :       TALER_config_get_amount (TEH_cfg,
    2184             :                                section_name,
    2185             :                                "VALUE",
    2186             :                                &meta->value))
    2187             :   {
    2188           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    2189             :                                "Need amount for option `%s' in section `%s'\n",
    2190             :                                "VALUE",
    2191             :                                section_name);
    2192           0 :     return GNUNET_SYSERR;
    2193             :   }
    2194         232 :   if (GNUNET_OK !=
    2195         232 :       TALER_config_get_amount (TEH_cfg,
    2196             :                                section_name,
    2197             :                                "FEE_WITHDRAW",
    2198             :                                &meta->fee_withdraw))
    2199             :   {
    2200           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    2201             :                                "Need amount for option `%s' in section `%s'\n",
    2202             :                                "FEE_WITHDRAW",
    2203             :                                section_name);
    2204           0 :     return GNUNET_SYSERR;
    2205             :   }
    2206         232 :   if (GNUNET_OK !=
    2207         232 :       TALER_config_get_amount (TEH_cfg,
    2208             :                                section_name,
    2209             :                                "FEE_DEPOSIT",
    2210             :                                &meta->fee_deposit))
    2211             :   {
    2212           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    2213             :                                "Need amount for option `%s' in section `%s'\n",
    2214             :                                "FEE_DEPOSIT",
    2215             :                                section_name);
    2216           0 :     return GNUNET_SYSERR;
    2217             :   }
    2218         232 :   if (GNUNET_OK !=
    2219         232 :       TALER_config_get_amount (TEH_cfg,
    2220             :                                section_name,
    2221             :                                "FEE_REFRESH",
    2222             :                                &meta->fee_refresh))
    2223             :   {
    2224           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    2225             :                                "Need amount for option `%s' in section `%s'\n",
    2226             :                                "FEE_REFRESH",
    2227             :                                section_name);
    2228           0 :     return GNUNET_SYSERR;
    2229             :   }
    2230         232 :   if (GNUNET_OK !=
    2231         232 :       TALER_config_get_amount (TEH_cfg,
    2232             :                                section_name,
    2233             :                                "FEE_REFUND",
    2234             :                                &meta->fee_refund))
    2235             :   {
    2236           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    2237             :                                "Need amount for option `%s' in section `%s'\n",
    2238             :                                "FEE_REFUND",
    2239             :                                section_name);
    2240           0 :     return GNUNET_SYSERR;
    2241             :   }
    2242         232 :   if ( (0 != strcasecmp (TEH_currency,
    2243         232 :                          meta->value.currency)) ||
    2244         232 :        (0 != strcasecmp (TEH_currency,
    2245         232 :                          meta->fee_withdraw.currency)) ||
    2246         232 :        (0 != strcasecmp (TEH_currency,
    2247         232 :                          meta->fee_deposit.currency)) ||
    2248         232 :        (0 != strcasecmp (TEH_currency,
    2249         232 :                          meta->fee_refresh.currency)) ||
    2250         232 :        (0 != strcasecmp (TEH_currency,
    2251         232 :                          meta->fee_refund.currency)) )
    2252             :   {
    2253           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    2254             :                                "Need amounts in section `%s' to use currency `%s'\n",
    2255             :                                section_name,
    2256             :                                TEH_currency);
    2257           0 :     return GNUNET_SYSERR;
    2258             :   }
    2259         232 :   return GNUNET_OK;
    2260             : }
    2261             : 
    2262             : 
    2263             : enum GNUNET_GenericReturnValue
    2264         116 : TEH_keys_load_fees (const struct GNUNET_HashCode *h_denom_pub,
    2265             :                     struct TALER_DenominationPublicKey *denom_pub,
    2266             :                     struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta)
    2267             : {
    2268             :   struct TEH_KeyStateHandle *ksh;
    2269             :   struct HelperDenomination *hd;
    2270             :   enum GNUNET_GenericReturnValue ok;
    2271             : 
    2272         116 :   ksh = get_key_state (true);
    2273         116 :   if (NULL == ksh)
    2274             :   {
    2275           0 :     GNUNET_break (0);
    2276           0 :     return GNUNET_SYSERR;
    2277             :   }
    2278             : 
    2279         116 :   hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
    2280             :                                           h_denom_pub);
    2281         116 :   if (NULL == hd)
    2282             :   {
    2283           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    2284             :                 "Denomination %s not known\n",
    2285             :                 GNUNET_h2s (h_denom_pub));
    2286           0 :     return GNUNET_NO;
    2287             :   }
    2288         116 :   meta->start = hd->start_time;
    2289         116 :   meta->expire_withdraw = GNUNET_TIME_absolute_add (meta->start,
    2290             :                                                     hd->validity_duration);
    2291         116 :   ok = load_fees (hd->section_name,
    2292             :                   meta);
    2293         116 :   if (GNUNET_OK == ok)
    2294             :     denom_pub->rsa_public_key
    2295         116 :       = GNUNET_CRYPTO_rsa_public_key_dup (hd->denom_pub.rsa_public_key);
    2296             :   else
    2297           0 :     denom_pub->rsa_public_key = NULL;
    2298         116 :   return ok;
    2299             : }
    2300             : 
    2301             : 
    2302             : int
    2303          14 : TEH_keys_get_timing (const struct TALER_ExchangePublicKeyP *exchange_pub,
    2304             :                      struct TALER_EXCHANGEDB_SignkeyMetaData *meta)
    2305             : {
    2306             :   struct TEH_KeyStateHandle *ksh;
    2307             :   struct HelperSignkey *hsk;
    2308             :   struct GNUNET_PeerIdentity pid;
    2309             : 
    2310          14 :   ksh = get_key_state (true);
    2311          14 :   if (NULL == ksh)
    2312             :   {
    2313           0 :     GNUNET_break (0);
    2314           0 :     return GNUNET_SYSERR;
    2315             :   }
    2316             : 
    2317          14 :   pid.public_key = exchange_pub->eddsa_pub;
    2318          14 :   hsk = GNUNET_CONTAINER_multipeermap_get (ksh->helpers->esign_keys,
    2319             :                                            &pid);
    2320          14 :   meta->start = hsk->start_time;
    2321          14 :   meta->expire_sign = GNUNET_TIME_absolute_add (meta->start,
    2322             :                                                 hsk->validity_duration);
    2323          14 :   meta->expire_legal = GNUNET_TIME_absolute_add (meta->expire_sign,
    2324             :                                                  signkey_legal_duration);
    2325          14 :   return GNUNET_OK;
    2326             : }
    2327             : 
    2328             : 
    2329             : /**
    2330             :  * Closure for #add_future_denomkey_cb and #add_future_signkey_cb.
    2331             :  */
    2332             : struct FutureBuilderContext
    2333             : {
    2334             :   /**
    2335             :    * Our key state.
    2336             :    */
    2337             :   struct TEH_KeyStateHandle *ksh;
    2338             : 
    2339             :   /**
    2340             :    * Array of denomination keys.
    2341             :    */
    2342             :   json_t *denoms;
    2343             : 
    2344             :   /**
    2345             :    * Array of signing keys.
    2346             :    */
    2347             :   json_t *signkeys;
    2348             : 
    2349             : };
    2350             : 
    2351             : 
    2352             : /**
    2353             :  * Function called on all of our current and future denomination keys
    2354             :  * known to the helper process. Filters out those that are current
    2355             :  * and adds the remaining denomination keys (with their configuration
    2356             :  * data) to the JSON array.
    2357             :  *
    2358             :  * @param cls the `struct FutureBuilderContext *`
    2359             :  * @param h_denom_pub hash of the denomination public key
    2360             :  * @param value a `struct HelperDenomination`
    2361             :  * @return #GNUNET_OK (continue to iterate)
    2362             :  */
    2363             : static int
    2364         116 : add_future_denomkey_cb (void *cls,
    2365             :                         const struct GNUNET_HashCode *h_denom_pub,
    2366             :                         void *value)
    2367             : {
    2368         116 :   struct FutureBuilderContext *fbc = cls;
    2369         116 :   struct HelperDenomination *hd = value;
    2370             :   struct TEH_DenominationKey *dk;
    2371             :   struct TALER_EXCHANGEDB_DenominationKeyMetaData meta;
    2372             : 
    2373         116 :   dk = GNUNET_CONTAINER_multihashmap_get (fbc->ksh->denomkey_map,
    2374             :                                           h_denom_pub);
    2375         116 :   if (NULL != dk)
    2376           0 :     return GNUNET_OK; /* skip: this key is already active! */
    2377         116 :   if (GNUNET_TIME_relative_is_zero (hd->validity_duration))
    2378           0 :     return GNUNET_OK; /* this key already expired! */
    2379         116 :   meta.start = hd->start_time;
    2380         116 :   meta.expire_withdraw = GNUNET_TIME_absolute_add (meta.start,
    2381             :                                                    hd->validity_duration);
    2382         116 :   if (GNUNET_OK !=
    2383         116 :       load_fees (hd->section_name,
    2384             :                  &meta))
    2385             :   {
    2386             :     /* Woops, couldn't determine fee structure!? */
    2387           0 :     return GNUNET_OK;
    2388             :   }
    2389         116 :   GNUNET_assert (
    2390             :     0 ==
    2391             :     json_array_append_new (
    2392             :       fbc->denoms,
    2393             :       GNUNET_JSON_PACK (
    2394             :         TALER_JSON_pack_amount ("value",
    2395             :                                 &meta.value),
    2396             :         GNUNET_JSON_pack_time_abs ("stamp_start",
    2397             :                                    meta.start),
    2398             :         GNUNET_JSON_pack_time_abs ("stamp_expire_withdraw",
    2399             :                                    meta.expire_withdraw),
    2400             :         GNUNET_JSON_pack_time_abs ("stamp_expire_deposit",
    2401             :                                    meta.expire_deposit),
    2402             :         GNUNET_JSON_pack_time_abs ("stamp_expire_legal",
    2403             :                                    meta.expire_legal),
    2404             :         GNUNET_JSON_pack_rsa_public_key ("denom_pub",
    2405             :                                          hd->denom_pub.rsa_public_key),
    2406             :         TALER_JSON_pack_amount ("fee_withdraw",
    2407             :                                 &meta.fee_withdraw),
    2408             :         TALER_JSON_pack_amount ("fee_deposit",
    2409             :                                 &meta.fee_deposit),
    2410             :         TALER_JSON_pack_amount ("fee_refresh",
    2411             :                                 &meta.fee_refresh),
    2412             :         TALER_JSON_pack_amount ("fee_refund",
    2413             :                                 &meta.fee_refund),
    2414             :         GNUNET_JSON_pack_data_auto ("denom_secmod_sig",
    2415             :                                     &hd->sm_sig),
    2416             :         GNUNET_JSON_pack_string ("section_name",
    2417             :                                  hd->section_name))));
    2418         116 :   return GNUNET_OK;
    2419             : }
    2420             : 
    2421             : 
    2422             : /**
    2423             :  * Function called on all of our current and future exchange signing keys
    2424             :  * known to the helper process. Filters out those that are current
    2425             :  * and adds the remaining signing keys (with their configuration
    2426             :  * data) to the JSON array.
    2427             :  *
    2428             :  * @param cls the `struct FutureBuilderContext *`
    2429             :  * @param pid actually the exchange public key (type disguised)
    2430             :  * @param value a `struct HelperDenomination`
    2431             :  * @return #GNUNET_OK (continue to iterate)
    2432             :  */
    2433             : static int
    2434          14 : add_future_signkey_cb (void *cls,
    2435             :                        const struct GNUNET_PeerIdentity *pid,
    2436             :                        void *value)
    2437             : {
    2438          14 :   struct FutureBuilderContext *fbc = cls;
    2439          14 :   struct HelperSignkey *hsk = value;
    2440             :   struct SigningKey *sk;
    2441             :   struct GNUNET_TIME_Absolute stamp_expire;
    2442             :   struct GNUNET_TIME_Absolute legal_end;
    2443             : 
    2444          14 :   sk = GNUNET_CONTAINER_multipeermap_get (fbc->ksh->signkey_map,
    2445             :                                           pid);
    2446          14 :   if (NULL != sk)
    2447           0 :     return GNUNET_OK; /* skip: this key is already active */
    2448          14 :   if (GNUNET_TIME_relative_is_zero (hsk->validity_duration))
    2449           0 :     return GNUNET_OK; /* this key already expired! */
    2450          14 :   stamp_expire = GNUNET_TIME_absolute_add (hsk->start_time,
    2451             :                                            hsk->validity_duration);
    2452          14 :   legal_end = GNUNET_TIME_absolute_add (stamp_expire,
    2453             :                                         signkey_legal_duration);
    2454          14 :   GNUNET_assert (0 ==
    2455             :                  json_array_append_new (
    2456             :                    fbc->signkeys,
    2457             :                    GNUNET_JSON_PACK (
    2458             :                      GNUNET_JSON_pack_data_auto ("key",
    2459             :                                                  &hsk->exchange_pub),
    2460             :                      GNUNET_JSON_pack_time_abs ("stamp_start",
    2461             :                                                 hsk->start_time),
    2462             :                      GNUNET_JSON_pack_time_abs ("stamp_expire",
    2463             :                                                 stamp_expire),
    2464             :                      GNUNET_JSON_pack_time_abs ("stamp_end",
    2465             :                                                 legal_end),
    2466             :                      GNUNET_JSON_pack_data_auto ("signkey_secmod_sig",
    2467             :                                                  &hsk->sm_sig))));
    2468          14 :   return GNUNET_OK;
    2469             : }
    2470             : 
    2471             : 
    2472             : MHD_RESULT
    2473          10 : TEH_keys_management_get_keys_handler (const struct TEH_RequestHandler *rh,
    2474             :                                       struct MHD_Connection *connection)
    2475             : {
    2476             :   struct TEH_KeyStateHandle *ksh;
    2477             :   json_t *reply;
    2478             : 
    2479          10 :   ksh = get_key_state (true);
    2480          10 :   if (NULL == ksh)
    2481             :   {
    2482           2 :     return TALER_MHD_reply_with_error (connection,
    2483             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    2484             :                                        TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
    2485             :                                        "no key state");
    2486             :   }
    2487           8 :   sync_key_helpers (ksh->helpers);
    2488           8 :   if (NULL == ksh->management_keys_reply)
    2489             :   {
    2490          24 :     struct FutureBuilderContext fbc = {
    2491             :       .ksh = ksh,
    2492           8 :       .denoms = json_array (),
    2493           8 :       .signkeys = json_array ()
    2494             :     };
    2495             : 
    2496           8 :     GNUNET_assert (NULL != fbc.denoms);
    2497           8 :     GNUNET_assert (NULL != fbc.signkeys);
    2498           8 :     GNUNET_CONTAINER_multihashmap_iterate (ksh->helpers->denom_keys,
    2499             :                                            &add_future_denomkey_cb,
    2500             :                                            &fbc);
    2501           8 :     GNUNET_CONTAINER_multipeermap_iterate (ksh->helpers->esign_keys,
    2502             :                                            &add_future_signkey_cb,
    2503             :                                            &fbc);
    2504           8 :     reply = GNUNET_JSON_PACK (
    2505             :       GNUNET_JSON_pack_array_steal ("future_denoms",
    2506             :                                     fbc.denoms),
    2507             :       GNUNET_JSON_pack_array_steal ("future_signkeys",
    2508             :                                     fbc.signkeys),
    2509             :       GNUNET_JSON_pack_data_auto ("master_pub",
    2510             :                                   &TEH_master_public_key),
    2511             :       GNUNET_JSON_pack_data_auto ("denom_secmod_public_key",
    2512             :                                   &denom_sm_pub),
    2513             :       GNUNET_JSON_pack_data_auto ("signkey_secmod_public_key",
    2514             :                                   &esign_sm_pub));
    2515           8 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2516             :                 "Returning GET /management/keys response:\n");
    2517           8 :     if (NULL == reply)
    2518           0 :       return TALER_MHD_reply_with_error (connection,
    2519             :                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
    2520             :                                          TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE,
    2521             :                                          NULL);
    2522           8 :     GNUNET_assert (NULL == ksh->management_keys_reply);
    2523           8 :     ksh->management_keys_reply = reply;
    2524             :   }
    2525             :   else
    2526             :   {
    2527           0 :     reply = ksh->management_keys_reply;
    2528             :   }
    2529           8 :   return TALER_MHD_reply_json (connection,
    2530             :                                reply,
    2531             :                                MHD_HTTP_OK);
    2532             : }
    2533             : 
    2534             : 
    2535             : /* end of taler-exchange-httpd_keys.c */

Generated by: LCOV version 1.14