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: 0 973 0.0 %
Date: 2022-08-25 06:15:09 Functions: 0 59 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    This file is part of TALER
       3             :    Copyright (C) 2020-2022 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_kyclogic_lib.h"
      25             : #include "taler_dbevents.h"
      26             : #include "taler-exchange-httpd.h"
      27             : #include "taler-exchange-httpd_keys.h"
      28             : #include "taler-exchange-httpd_responses.h"
      29             : #include "taler_exchangedb_plugin.h"
      30             : #include "taler_extensions.h"
      31             : 
      32             : 
      33             : /**
      34             :  * How many /keys request do we hold in suspension at
      35             :  * most at any time?
      36             :  */
      37             : #define SKR_LIMIT 32
      38             : 
      39             : 
      40             : /**
      41             :  * When do we forcefully timeout a /keys request?
      42             :  */
      43             : #define KEYS_TIMEOUT GNUNET_TIME_UNIT_MINUTES
      44             : 
      45             : 
      46             : /**
      47             :  * Taler protocol version in the format CURRENT:REVISION:AGE
      48             :  * as used by GNU libtool.  See
      49             :  * https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
      50             :  *
      51             :  * Please be very careful when updating and follow
      52             :  * https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info
      53             :  * precisely.  Note that this version has NOTHING to do with the
      54             :  * release version, and the format is NOT the same that semantic
      55             :  * versioning uses either.
      56             :  *
      57             :  * When changing this version, you likely want to also update
      58             :  * #TALER_PROTOCOL_CURRENT and #TALER_PROTOCOL_AGE in
      59             :  * exchange_api_handle.c!
      60             :  */
      61             : #define EXCHANGE_PROTOCOL_VERSION "14:0:2"
      62             : 
      63             : 
      64             : /**
      65             :  * Information about a denomination on offer by the denomination helper.
      66             :  */
      67             : struct HelperDenomination
      68             : {
      69             : 
      70             :   /**
      71             :    * When will the helper start to use this key for signing?
      72             :    */
      73             :   struct GNUNET_TIME_Timestamp start_time;
      74             : 
      75             :   /**
      76             :    * For how long will the helper allow signing? 0 if
      77             :    * the key was revoked or purged.
      78             :    */
      79             :   struct GNUNET_TIME_Relative validity_duration;
      80             : 
      81             :   /**
      82             :    * Hash of the full denomination key.
      83             :    */
      84             :   struct TALER_DenominationHashP h_denom_pub;
      85             : 
      86             :   /**
      87             :    * Signature over this key from the security module's key.
      88             :    */
      89             :   struct TALER_SecurityModuleSignatureP sm_sig;
      90             : 
      91             :   /**
      92             :    * The (full) public key.
      93             :    */
      94             :   struct TALER_DenominationPublicKey denom_pub;
      95             : 
      96             :   /**
      97             :    * Details depend on the @e denom_pub.cipher type.
      98             :    */
      99             :   union
     100             :   {
     101             : 
     102             :     /**
     103             :      * Hash of the RSA key.
     104             :      */
     105             :     struct TALER_RsaPubHashP h_rsa;
     106             : 
     107             :     /**
     108             :      * Hash of the CS key.
     109             :      */
     110             :     struct TALER_CsPubHashP h_cs;
     111             : 
     112             :   } h_details;
     113             : 
     114             :   /**
     115             :    * Name in configuration section for this denomination type.
     116             :    */
     117             :   char *section_name;
     118             : 
     119             : 
     120             : };
     121             : 
     122             : 
     123             : /**
     124             :  * Signatures of an auditor over a denomination key of this exchange.
     125             :  */
     126             : struct TEH_AuditorSignature
     127             : {
     128             :   /**
     129             :    * We store the signatures in a DLL.
     130             :    */
     131             :   struct TEH_AuditorSignature *prev;
     132             : 
     133             :   /**
     134             :    * We store the signatures in a DLL.
     135             :    */
     136             :   struct TEH_AuditorSignature *next;
     137             : 
     138             :   /**
     139             :    * A signature from the auditor.
     140             :    */
     141             :   struct TALER_AuditorSignatureP asig;
     142             : 
     143             :   /**
     144             :    * Public key of the auditor.
     145             :    */
     146             :   struct TALER_AuditorPublicKeyP apub;
     147             : 
     148             : };
     149             : 
     150             : 
     151             : /**
     152             :  * Information about a signing key on offer by the esign helper.
     153             :  */
     154             : struct HelperSignkey
     155             : {
     156             :   /**
     157             :    * When will the helper start to use this key for signing?
     158             :    */
     159             :   struct GNUNET_TIME_Timestamp start_time;
     160             : 
     161             :   /**
     162             :    * For how long will the helper allow signing? 0 if
     163             :    * the key was revoked or purged.
     164             :    */
     165             :   struct GNUNET_TIME_Relative validity_duration;
     166             : 
     167             :   /**
     168             :    * The public key.
     169             :    */
     170             :   struct TALER_ExchangePublicKeyP exchange_pub;
     171             : 
     172             :   /**
     173             :    * Signature over this key from the security module's key.
     174             :    */
     175             :   struct TALER_SecurityModuleSignatureP sm_sig;
     176             : 
     177             : };
     178             : 
     179             : 
     180             : /**
     181             :  * State associated with the crypto helpers / security modules.  NOT updated
     182             :  * when the #key_generation is updated (instead constantly kept in sync
     183             :  * whenever #TEH_keys_get_state() is called).
     184             :  */
     185             : struct HelperState
     186             : {
     187             : 
     188             :   /**
     189             :    * Handle for the esign/EdDSA helper.
     190             :    */
     191             :   struct TALER_CRYPTO_ExchangeSignHelper *esh;
     192             : 
     193             :   /**
     194             :    * Handle for the denom/RSA helper.
     195             :    */
     196             :   struct TALER_CRYPTO_RsaDenominationHelper *rsadh;
     197             : 
     198             :   /**
     199             :    * Handle for the denom/CS helper.
     200             :    */
     201             :   struct TALER_CRYPTO_CsDenominationHelper *csdh;
     202             : 
     203             :   /**
     204             :    * Map from H(denom_pub) to `struct HelperDenomination` entries.
     205             :    */
     206             :   struct GNUNET_CONTAINER_MultiHashMap *denom_keys;
     207             : 
     208             :   /**
     209             :    * Map from H(rsa_pub) to `struct HelperDenomination` entries.
     210             :    */
     211             :   struct GNUNET_CONTAINER_MultiHashMap *rsa_keys;
     212             : 
     213             :   /**
     214             :    * Map from H(cs_pub) to `struct HelperDenomination` entries.
     215             :    */
     216             :   struct GNUNET_CONTAINER_MultiHashMap *cs_keys;
     217             : 
     218             :   /**
     219             :    * Map from `struct TALER_ExchangePublicKey` to `struct HelperSignkey`
     220             :    * entries.  Based on the fact that a `struct GNUNET_PeerIdentity` is also
     221             :    * an EdDSA public key.
     222             :    */
     223             :   struct GNUNET_CONTAINER_MultiPeerMap *esign_keys;
     224             : 
     225             : };
     226             : 
     227             : 
     228             : /**
     229             :  * Entry in (sorted) array with possible pre-build responses for /keys.
     230             :  * We keep pre-build responses for the various (valid) cherry-picking
     231             :  * values around.
     232             :  */
     233             : struct KeysResponseData
     234             : {
     235             : 
     236             :   /**
     237             :    * Response to return if the client supports (deflate) compression.
     238             :    */
     239             :   struct MHD_Response *response_compressed;
     240             : 
     241             :   /**
     242             :    * Response to return if the client does not support compression.
     243             :    */
     244             :   struct MHD_Response *response_uncompressed;
     245             : 
     246             :   /**
     247             :    * ETag for these responses.
     248             :    */
     249             :   char *etag;
     250             : 
     251             :   /**
     252             :    * Cherry-picking timestamp the client must have set for this
     253             :    * response to be valid.  0 if this is the "full" response.
     254             :    * The client's request must include this date or a higher one
     255             :    * for this response to be applicable.
     256             :    */
     257             :   struct GNUNET_TIME_Timestamp cherry_pick_date;
     258             : 
     259             : };
     260             : 
     261             : 
     262             : /**
     263             :  * @brief All information about an exchange online signing key (which is used to
     264             :  * sign messages from the exchange).
     265             :  */
     266             : struct SigningKey
     267             : {
     268             : 
     269             :   /**
     270             :    * The exchange's (online signing) public key.
     271             :    */
     272             :   struct TALER_ExchangePublicKeyP exchange_pub;
     273             : 
     274             :   /**
     275             :    * Meta data about the signing key, such as validity periods.
     276             :    */
     277             :   struct TALER_EXCHANGEDB_SignkeyMetaData meta;
     278             : 
     279             :   /**
     280             :    * The long-term offline master key's signature for this signing key.
     281             :    * Signs over @e exchange_pub and @e meta.
     282             :    */
     283             :   struct TALER_MasterSignatureP master_sig;
     284             : 
     285             : };
     286             : 
     287             : struct TEH_KeyStateHandle
     288             : {
     289             : 
     290             :   /**
     291             :    * Mapping from denomination keys to denomination key issue struct.
     292             :    * Used to lookup the key by hash.
     293             :    */
     294             :   struct GNUNET_CONTAINER_MultiHashMap *denomkey_map;
     295             : 
     296             :   /**
     297             :    * Map from `struct TALER_ExchangePublicKey` to `struct SigningKey`
     298             :    * entries.  Based on the fact that a `struct GNUNET_PeerIdentity` is also
     299             :    * an EdDSA public key.
     300             :    */
     301             :   struct GNUNET_CONTAINER_MultiPeerMap *signkey_map;
     302             : 
     303             :   /**
     304             :    * Head of DLL of our global fees.
     305             :    */
     306             :   struct TEH_GlobalFee *gf_head;
     307             : 
     308             :   /**
     309             :    * Tail of DLL of our global fees.
     310             :    */
     311             :   struct TEH_GlobalFee *gf_tail;
     312             : 
     313             :   /**
     314             :    * json array with the auditors of this exchange. Contains exactly
     315             :    * the information needed for the "auditors" field of the /keys response.
     316             :    */
     317             :   json_t *auditors;
     318             : 
     319             :   /**
     320             :    * json array with the global fees of this exchange. Contains exactly
     321             :    * the information needed for the "global_fees" field of the /keys response.
     322             :    */
     323             :   json_t *global_fees;
     324             : 
     325             :   /**
     326             :    * Sorted array of responses to /keys (MUST be sorted by cherry-picking date) of
     327             :    * length @e krd_array_length;
     328             :    */
     329             :   struct KeysResponseData *krd_array;
     330             : 
     331             :   /**
     332             :    * Length of the @e krd_array.
     333             :    */
     334             :   unsigned int krd_array_length;
     335             : 
     336             :   /**
     337             :    * Information we track for thecrypto helpers.  Preserved
     338             :    * when the @e key_generation changes, thus kept separate.
     339             :    */
     340             :   struct HelperState *helpers;
     341             : 
     342             :   /**
     343             :    * Cached reply for a GET /management/keys request.  Used so we do not
     344             :    * re-create the reply every time.
     345             :    */
     346             :   json_t *management_keys_reply;
     347             : 
     348             :   /**
     349             :    * For which (global) key_generation was this data structure created?
     350             :    * Used to check when we are outdated and need to be re-generated.
     351             :    */
     352             :   uint64_t key_generation;
     353             : 
     354             :   /**
     355             :    * When did we initiate the key reloading?
     356             :    */
     357             :   struct GNUNET_TIME_Timestamp reload_time;
     358             : 
     359             :   /**
     360             :    * What is the period at which we rotate keys
     361             :    * (signing or denomination keys)?
     362             :    */
     363             :   struct GNUNET_TIME_Relative rekey_frequency;
     364             : 
     365             :   /**
     366             :    * When does our online signing key expire and we
     367             :    * thus need to re-generate this response?
     368             :    */
     369             :   struct GNUNET_TIME_Timestamp signature_expires;
     370             : 
     371             :   /**
     372             :    * True if #finish_keys_response() was not yet run and this key state
     373             :    * is only suitable for the /management/keys API.
     374             :    */
     375             :   bool management_only;
     376             : 
     377             : };
     378             : 
     379             : 
     380             : /**
     381             :  * Entry of /keys requests that are currently suspended because we are
     382             :  * waiting for /keys to become ready.
     383             :  */
     384             : struct SuspendedKeysRequests
     385             : {
     386             :   /**
     387             :    * Kept in a DLL.
     388             :    */
     389             :   struct SuspendedKeysRequests *next;
     390             : 
     391             :   /**
     392             :    * Kept in a DLL.
     393             :    */
     394             :   struct SuspendedKeysRequests *prev;
     395             : 
     396             :   /**
     397             :    * The suspended connection.
     398             :    */
     399             :   struct MHD_Connection *connection;
     400             : 
     401             :   /**
     402             :    * When does this request timeout?
     403             :    */
     404             :   struct GNUNET_TIME_Absolute timeout;
     405             : };
     406             : 
     407             : /**
     408             :  * Stores the latest generation of our key state.
     409             :  */
     410             : static struct TEH_KeyStateHandle *key_state;
     411             : 
     412             : /**
     413             :  * Counter incremented whenever we have a reason to re-build the keys because
     414             :  * something external changed.  See #TEH_keys_get_state() and
     415             :  * #TEH_keys_update_states() for uses of this variable.
     416             :  */
     417             : static uint64_t key_generation;
     418             : 
     419             : /**
     420             :  * Handler listening for wire updates by other exchange
     421             :  * services.
     422             :  */
     423             : static struct GNUNET_DB_EventHandler *keys_eh;
     424             : 
     425             : /**
     426             :  * Head of DLL of suspended /keys requests.
     427             :  */
     428             : static struct SuspendedKeysRequests *skr_head;
     429             : 
     430             : /**
     431             :  * Tail of DLL of suspended /keys requests.
     432             :  */
     433             : static struct SuspendedKeysRequests *skr_tail;
     434             : 
     435             : /**
     436             :  * Number of entries in the @e skr_head DLL.
     437             :  */
     438             : static unsigned int skr_size;
     439             : 
     440             : /**
     441             :  * Handle to a connection that should be force-resumed
     442             :  * with a hard error due to @a skr_size hitting
     443             :  * #SKR_LIMIT.
     444             :  */
     445             : static struct MHD_Connection *skr_connection;
     446             : 
     447             : /**
     448             :  * Task to force timeouts on /keys requests.
     449             :  */
     450             : static struct GNUNET_SCHEDULER_Task *keys_tt;
     451             : 
     452             : /**
     453             :  * For how long should a signing key be legally retained?
     454             :  * Configuration value.
     455             :  */
     456             : static struct GNUNET_TIME_Relative signkey_legal_duration;
     457             : 
     458             : /**
     459             :  * RSA security module public key, all zero if not known.
     460             :  */
     461             : static struct TALER_SecurityModulePublicKeyP denom_rsa_sm_pub;
     462             : 
     463             : /**
     464             :  * CS security module public key, all zero if not known.
     465             :  */
     466             : static struct TALER_SecurityModulePublicKeyP denom_cs_sm_pub;
     467             : 
     468             : /**
     469             :  * EdDSA security module public key, all zero if not known.
     470             :  */
     471             : static struct TALER_SecurityModulePublicKeyP esign_sm_pub;
     472             : 
     473             : /**
     474             :  * Are we shutting down?
     475             :  */
     476             : static bool terminating;
     477             : 
     478             : 
     479             : /**
     480             :  * Function called to forcefully resume suspended keys requests.
     481             :  *
     482             :  * @param cls unused, NULL
     483             :  */
     484             : static void
     485           0 : keys_timeout_cb (void *cls)
     486             : {
     487             :   struct SuspendedKeysRequests *skr;
     488             : 
     489             :   (void) cls;
     490           0 :   keys_tt = NULL;
     491           0 :   while (NULL != (skr = skr_head))
     492             :   {
     493           0 :     if (GNUNET_TIME_absolute_is_future (skr->timeout))
     494           0 :       break;
     495           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     496             :                 "Resuming /keys request due to timeout\n");
     497           0 :     GNUNET_CONTAINER_DLL_remove (skr_head,
     498             :                                  skr_tail,
     499             :                                  skr);
     500           0 :     MHD_resume_connection (skr->connection);
     501           0 :     TALER_MHD_daemon_trigger ();
     502           0 :     GNUNET_free (skr);
     503             :   }
     504           0 :   if (NULL == skr)
     505           0 :     return;
     506           0 :   keys_tt = GNUNET_SCHEDULER_add_at (skr->timeout,
     507             :                                      &keys_timeout_cb,
     508             :                                      NULL);
     509             : }
     510             : 
     511             : 
     512             : /**
     513             :  * Suspend /keys request while we (hopefully) are waiting to be
     514             :  * provisioned with key material.
     515             :  *
     516             :  * @param[in] connection to suspend
     517             :  */
     518             : static MHD_RESULT
     519           0 : suspend_request (struct MHD_Connection *connection)
     520             : {
     521             :   struct SuspendedKeysRequests *skr;
     522             : 
     523           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     524             :               "Suspending /keys request until key material changes\n");
     525           0 :   if (terminating)
     526             :   {
     527           0 :     return TALER_MHD_reply_with_error (connection,
     528             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
     529             :                                        TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
     530             :                                        "Exchange terminating");
     531             :   }
     532           0 :   skr = GNUNET_new (struct SuspendedKeysRequests);
     533           0 :   skr->connection = connection;
     534           0 :   MHD_suspend_connection (connection);
     535           0 :   GNUNET_CONTAINER_DLL_insert (skr_head,
     536             :                                skr_tail,
     537             :                                skr);
     538           0 :   skr->timeout = GNUNET_TIME_relative_to_absolute (KEYS_TIMEOUT);
     539           0 :   if (NULL == keys_tt)
     540             :   {
     541           0 :     keys_tt = GNUNET_SCHEDULER_add_at (skr->timeout,
     542             :                                        &keys_timeout_cb,
     543             :                                        NULL);
     544             :   }
     545           0 :   skr_size++;
     546           0 :   if (skr_size > SKR_LIMIT)
     547             :   {
     548           0 :     skr = skr_tail;
     549           0 :     GNUNET_CONTAINER_DLL_remove (skr_head,
     550             :                                  skr_tail,
     551             :                                  skr);
     552           0 :     skr_size--;
     553           0 :     skr_connection = skr->connection;
     554           0 :     MHD_resume_connection (skr->connection);
     555           0 :     TALER_MHD_daemon_trigger ();
     556           0 :     GNUNET_free (skr);
     557             :   }
     558           0 :   return MHD_YES;
     559             : }
     560             : 
     561             : 
     562             : /**
     563             :  * Called on each denomination key. Checks that the key still works.
     564             :  *
     565             :  * @param cls NULL
     566             :  * @param hc denomination hash (unused)
     567             :  * @param value a `struct TEH_DenominationKey`
     568             :  * @return #GNUNET_OK
     569             :  */
     570             : static enum GNUNET_GenericReturnValue
     571           0 : check_dk (void *cls,
     572             :           const struct GNUNET_HashCode *hc,
     573             :           void *value)
     574             : {
     575           0 :   struct TEH_DenominationKey *dk = value;
     576             : 
     577             :   (void) cls;
     578             :   (void) hc;
     579           0 :   GNUNET_assert (TALER_DENOMINATION_INVALID != dk->denom_pub.cipher);
     580           0 :   if (TALER_DENOMINATION_RSA == dk->denom_pub.cipher)
     581           0 :     GNUNET_assert (GNUNET_CRYPTO_rsa_public_key_check (
     582             :                      dk->denom_pub.details.rsa_public_key));
     583             :   // nothing to do for TALER_DENOMINATION_CS
     584           0 :   return GNUNET_OK;
     585             : }
     586             : 
     587             : 
     588             : void
     589           0 : TEH_check_invariants ()
     590             : {
     591             :   struct TEH_KeyStateHandle *ksh;
     592             : 
     593           0 :   if (0 == TEH_check_invariants_flag)
     594           0 :     return;
     595           0 :   ksh = TEH_keys_get_state ();
     596           0 :   if (NULL == ksh)
     597           0 :     return;
     598           0 :   GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
     599             :                                          &check_dk,
     600             :                                          NULL);
     601             : }
     602             : 
     603             : 
     604             : void
     605           0 : TEH_resume_keys_requests (bool do_shutdown)
     606             : {
     607             :   struct SuspendedKeysRequests *skr;
     608             : 
     609           0 :   if (do_shutdown)
     610           0 :     terminating = true;
     611           0 :   while (NULL != (skr = skr_head))
     612             :   {
     613           0 :     GNUNET_CONTAINER_DLL_remove (skr_head,
     614             :                                  skr_tail,
     615             :                                  skr);
     616           0 :     skr_size--;
     617           0 :     MHD_resume_connection (skr->connection);
     618           0 :     TALER_MHD_daemon_trigger ();
     619           0 :     GNUNET_free (skr);
     620             :   }
     621           0 : }
     622             : 
     623             : 
     624             : /**
     625             :  * Clear memory for responses to "/keys" in @a ksh.
     626             :  *
     627             :  * @param[in,out] ksh key state to update
     628             :  */
     629             : static void
     630           0 : clear_response_cache (struct TEH_KeyStateHandle *ksh)
     631             : {
     632           0 :   for (unsigned int i = 0; i<ksh->krd_array_length; i++)
     633             :   {
     634           0 :     struct KeysResponseData *krd = &ksh->krd_array[i];
     635             : 
     636           0 :     MHD_destroy_response (krd->response_compressed);
     637           0 :     MHD_destroy_response (krd->response_uncompressed);
     638           0 :     GNUNET_free (krd->etag);
     639             :   }
     640           0 :   GNUNET_array_grow (ksh->krd_array,
     641             :                      ksh->krd_array_length,
     642             :                      0);
     643           0 : }
     644             : 
     645             : 
     646             : /**
     647             :  * Check that the given RSA security module's public key is the one
     648             :  * we have pinned.  If it does not match, we die hard.
     649             :  *
     650             :  * @param sm_pub RSA security module public key to check
     651             :  */
     652             : static void
     653           0 : check_denom_rsa_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub)
     654             : {
     655           0 :   if (0 !=
     656           0 :       GNUNET_memcmp (sm_pub,
     657             :                      &denom_rsa_sm_pub))
     658             :   {
     659           0 :     if (! GNUNET_is_zero (&denom_rsa_sm_pub))
     660             :     {
     661           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     662             :                   "Our RSA security module changed its key. This must not happen.\n");
     663           0 :       GNUNET_assert (0);
     664             :     }
     665           0 :     denom_rsa_sm_pub = *sm_pub; /* TOFU ;-) */
     666             :   }
     667           0 : }
     668             : 
     669             : 
     670             : /**
     671             :  * Check that the given CS security module's public key is the one
     672             :  * we have pinned.  If it does not match, we die hard.
     673             :  *
     674             :  * @param sm_pub RSA security module public key to check
     675             :  */
     676             : static void
     677           0 : check_denom_cs_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub)
     678             : {
     679           0 :   if (0 !=
     680           0 :       GNUNET_memcmp (sm_pub,
     681             :                      &denom_cs_sm_pub))
     682             :   {
     683           0 :     if (! GNUNET_is_zero (&denom_cs_sm_pub))
     684             :     {
     685           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     686             :                   "Our CS security module changed its key. This must not happen.\n");
     687           0 :       GNUNET_assert (0);
     688             :     }
     689           0 :     denom_cs_sm_pub = *sm_pub; /* TOFU ;-) */
     690             :   }
     691           0 : }
     692             : 
     693             : 
     694             : /**
     695             :  * Check that the given EdDSA security module's public key is the one
     696             :  * we have pinned.  If it does not match, we die hard.
     697             :  *
     698             :  * @param sm_pub EdDSA security module public key to check
     699             :  */
     700             : static void
     701           0 : check_esign_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub)
     702             : {
     703           0 :   if (0 !=
     704           0 :       GNUNET_memcmp (sm_pub,
     705             :                      &esign_sm_pub))
     706             :   {
     707           0 :     if (! GNUNET_is_zero (&esign_sm_pub))
     708             :     {
     709           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     710             :                   "Our EdDSA security module changed its key. This must not happen.\n");
     711           0 :       GNUNET_assert (0);
     712             :     }
     713           0 :     esign_sm_pub = *sm_pub; /* TOFU ;-) */
     714             :   }
     715           0 : }
     716             : 
     717             : 
     718             : /**
     719             :  * Helper function for #destroy_key_helpers to free all entries
     720             :  * in the `denom_keys` map.
     721             :  *
     722             :  * @param cls the `struct HelperDenomination`
     723             :  * @param h_denom_pub hash of the denomination public key
     724             :  * @param value the `struct HelperDenomination` to release
     725             :  * @return #GNUNET_OK (continue to iterate)
     726             :  */
     727             : static enum GNUNET_GenericReturnValue
     728           0 : free_denom_cb (void *cls,
     729             :                const struct GNUNET_HashCode *h_denom_pub,
     730             :                void *value)
     731             : {
     732           0 :   struct HelperDenomination *hd = value;
     733             : 
     734             :   (void) cls;
     735             :   (void) h_denom_pub;
     736           0 :   TALER_denom_pub_free (&hd->denom_pub);
     737           0 :   GNUNET_free (hd->section_name);
     738           0 :   GNUNET_free (hd);
     739           0 :   return GNUNET_OK;
     740             : }
     741             : 
     742             : 
     743             : /**
     744             :  * Helper function for #destroy_key_helpers to free all entries
     745             :  * in the `esign_keys` map.
     746             :  *
     747             :  * @param cls the `struct HelperSignkey`
     748             :  * @param pid unused, matches the exchange public key
     749             :  * @param value the `struct HelperSignkey` to release
     750             :  * @return #GNUNET_OK (continue to iterate)
     751             :  */
     752             : static int
     753           0 : free_esign_cb (void *cls,
     754             :                const struct GNUNET_PeerIdentity *pid,
     755             :                void *value)
     756             : {
     757           0 :   struct HelperSignkey *hsk = value;
     758             : 
     759             :   (void) cls;
     760             :   (void) pid;
     761           0 :   GNUNET_free (hsk);
     762           0 :   return GNUNET_OK;
     763             : }
     764             : 
     765             : 
     766             : /**
     767             :  * Destroy helper state. Does NOT call free() on @a hs, as that
     768             :  * state is not separately allocated!  Dual to #setup_key_helpers().
     769             :  *
     770             :  * @param[in] hs helper state to free, but NOT the @a hs pointer itself!
     771             :  */
     772             : static void
     773           0 : destroy_key_helpers (struct HelperState *hs)
     774             : {
     775           0 :   GNUNET_CONTAINER_multihashmap_iterate (hs->denom_keys,
     776             :                                          &free_denom_cb,
     777             :                                          hs);
     778           0 :   GNUNET_CONTAINER_multihashmap_destroy (hs->rsa_keys);
     779           0 :   hs->rsa_keys = NULL;
     780           0 :   GNUNET_CONTAINER_multihashmap_destroy (hs->cs_keys);
     781           0 :   hs->cs_keys = NULL;
     782           0 :   GNUNET_CONTAINER_multihashmap_destroy (hs->denom_keys);
     783           0 :   hs->denom_keys = NULL;
     784           0 :   GNUNET_CONTAINER_multipeermap_iterate (hs->esign_keys,
     785             :                                          &free_esign_cb,
     786             :                                          hs);
     787           0 :   GNUNET_CONTAINER_multipeermap_destroy (hs->esign_keys);
     788           0 :   hs->esign_keys = NULL;
     789           0 :   if (NULL != hs->rsadh)
     790             :   {
     791           0 :     TALER_CRYPTO_helper_rsa_disconnect (hs->rsadh);
     792           0 :     hs->rsadh = NULL;
     793             :   }
     794           0 :   if (NULL != hs->csdh)
     795             :   {
     796           0 :     TALER_CRYPTO_helper_cs_disconnect (hs->csdh);
     797           0 :     hs->csdh = NULL;
     798             :   }
     799           0 :   if (NULL != hs->esh)
     800             :   {
     801           0 :     TALER_CRYPTO_helper_esign_disconnect (hs->esh);
     802           0 :     hs->esh = NULL;
     803             :   }
     804           0 : }
     805             : 
     806             : 
     807             : /**
     808             :  * Looks up the AGE_RESTRICTED setting for a denomination in the config and
     809             :  * returns the age restriction (mask) accordingly.
     810             :  *
     811             :  * @param section_name Section in the configuration for the particular
     812             :  *    denomination.
     813             :  */
     814             : static struct TALER_AgeMask
     815           0 : load_age_mask (const char*section_name)
     816             : {
     817             :   static const struct TALER_AgeMask null_mask = {0};
     818           0 :   struct TALER_AgeMask age_mask = TALER_extensions_age_restriction_ageMask ();
     819             : 
     820           0 :   if (age_mask.bits == 0)
     821           0 :     return null_mask;
     822             : 
     823           0 :   if (GNUNET_OK != (GNUNET_CONFIGURATION_have_value (
     824             :                       TEH_cfg,
     825             :                       section_name,
     826             :                       "AGE_RESTRICTED")))
     827           0 :     return null_mask;
     828             : 
     829             :   {
     830             :     enum GNUNET_GenericReturnValue ret;
     831             : 
     832           0 :     if (GNUNET_SYSERR ==
     833           0 :         (ret = GNUNET_CONFIGURATION_get_value_yesno (TEH_cfg,
     834             :                                                      section_name,
     835             :                                                      "AGE_RESTRICTED")))
     836             :     {
     837           0 :       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     838             :                                  section_name,
     839             :                                  "AGE_RESTRICTED",
     840             :                                  "Value must be YES or NO\n");
     841           0 :       return null_mask;
     842             :     }
     843             :   }
     844           0 :   return age_mask;
     845             : }
     846             : 
     847             : 
     848             : /**
     849             :  * Function called with information about available keys for signing.  Usually
     850             :  * only called once per key upon connect. Also called again in case a key is
     851             :  * being revoked, in that case with an @a end_time of zero.
     852             :  *
     853             :  * @param cls closure with the `struct HelperState *`
     854             :  * @param section_name name of the denomination type in the configuration;
     855             :  *                 NULL if the key has been revoked or purged
     856             :  * @param start_time when does the key become available for signing;
     857             :  *                 zero if the key has been revoked or purged
     858             :  * @param validity_duration how long does the key remain available for signing;
     859             :  *                 zero if the key has been revoked or purged
     860             :  * @param h_rsa hash of the @a denom_pub that is available (or was purged)
     861             :  * @param denom_pub the public key itself, NULL if the key was revoked or purged
     862             :  * @param sm_pub public key of the security module, NULL if the key was revoked or purged
     863             :  * @param sm_sig signature from the security module, NULL if the key was revoked or purged
     864             :  *               The signature was already verified against @a sm_pub.
     865             :  */
     866             : static void
     867           0 : helper_rsa_cb (
     868             :   void *cls,
     869             :   const char *section_name,
     870             :   struct GNUNET_TIME_Timestamp start_time,
     871             :   struct GNUNET_TIME_Relative validity_duration,
     872             :   const struct TALER_RsaPubHashP *h_rsa,
     873             :   const struct TALER_DenominationPublicKey *denom_pub,
     874             :   const struct TALER_SecurityModulePublicKeyP *sm_pub,
     875             :   const struct TALER_SecurityModuleSignatureP *sm_sig)
     876             : {
     877           0 :   struct HelperState *hs = cls;
     878             :   struct HelperDenomination *hd;
     879             : 
     880           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     881             :               "RSA helper announces key %s for denomination type %s with validity %s\n",
     882             :               GNUNET_h2s (&h_rsa->hash),
     883             :               section_name,
     884             :               GNUNET_STRINGS_relative_time_to_string (validity_duration,
     885             :                                                       GNUNET_NO));
     886           0 :   key_generation++;
     887           0 :   TEH_resume_keys_requests (false);
     888           0 :   hd = GNUNET_CONTAINER_multihashmap_get (hs->rsa_keys,
     889             :                                           &h_rsa->hash);
     890           0 :   if (NULL != hd)
     891             :   {
     892             :     /* should be just an update (revocation!), so update existing entry */
     893           0 :     hd->validity_duration = validity_duration;
     894           0 :     return;
     895             :   }
     896           0 :   GNUNET_assert (NULL != sm_pub);
     897           0 :   check_denom_rsa_sm_pub (sm_pub);
     898           0 :   hd = GNUNET_new (struct HelperDenomination);
     899           0 :   hd->start_time = start_time;
     900           0 :   hd->validity_duration = validity_duration;
     901           0 :   hd->h_details.h_rsa = *h_rsa;
     902           0 :   hd->sm_sig = *sm_sig;
     903           0 :   GNUNET_assert (TALER_DENOMINATION_RSA == denom_pub->cipher);
     904           0 :   TALER_denom_pub_deep_copy (&hd->denom_pub,
     905             :                              denom_pub);
     906           0 :   GNUNET_assert (TALER_DENOMINATION_RSA == hd->denom_pub.cipher);
     907             :   /* load the age mask for the denomination, if applicable */
     908           0 :   hd->denom_pub.age_mask = load_age_mask (section_name);
     909           0 :   TALER_denom_pub_hash (&hd->denom_pub,
     910             :                         &hd->h_denom_pub);
     911           0 :   hd->section_name = GNUNET_strdup (section_name);
     912           0 :   GNUNET_assert (
     913             :     GNUNET_OK ==
     914             :     GNUNET_CONTAINER_multihashmap_put (
     915             :       hs->denom_keys,
     916             :       &hd->h_denom_pub.hash,
     917             :       hd,
     918             :       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
     919           0 :   GNUNET_assert (
     920             :     GNUNET_OK ==
     921             :     GNUNET_CONTAINER_multihashmap_put (
     922             :       hs->rsa_keys,
     923             :       &hd->h_details.h_rsa.hash,
     924             :       hd,
     925             :       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
     926             : }
     927             : 
     928             : 
     929             : /**
     930             :  * Function called with information about available CS keys for signing. Usually
     931             :  * only called once per key upon connect. Also called again in case a key is
     932             :  * being revoked, in that case with an @a end_time of zero.
     933             :  *
     934             :  * @param cls closure with the `struct HelperState *`
     935             :  * @param section_name name of the denomination type in the configuration;
     936             :  *                 NULL if the key has been revoked or purged
     937             :  * @param start_time when does the key become available for signing;
     938             :  *                 zero if the key has been revoked or purged
     939             :  * @param validity_duration how long does the key remain available for signing;
     940             :  *                 zero if the key has been revoked or purged
     941             :  * @param h_cs hash of the @a denom_pub that is available (or was purged)
     942             :  * @param denom_pub the public key itself, NULL if the key was revoked or purged
     943             :  * @param sm_pub public key of the security module, NULL if the key was revoked or purged
     944             :  * @param sm_sig signature from the security module, NULL if the key was revoked or purged
     945             :  *               The signature was already verified against @a sm_pub.
     946             :  */
     947             : static void
     948           0 : helper_cs_cb (
     949             :   void *cls,
     950             :   const char *section_name,
     951             :   struct GNUNET_TIME_Timestamp start_time,
     952             :   struct GNUNET_TIME_Relative validity_duration,
     953             :   const struct TALER_CsPubHashP *h_cs,
     954             :   const struct TALER_DenominationPublicKey *denom_pub,
     955             :   const struct TALER_SecurityModulePublicKeyP *sm_pub,
     956             :   const struct TALER_SecurityModuleSignatureP *sm_sig)
     957             : {
     958           0 :   struct HelperState *hs = cls;
     959             :   struct HelperDenomination *hd;
     960             : 
     961           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     962             :               "CS helper announces key %s for denomination type %s with validity %s\n",
     963             :               GNUNET_h2s (&h_cs->hash),
     964             :               section_name,
     965             :               GNUNET_STRINGS_relative_time_to_string (validity_duration,
     966             :                                                       GNUNET_NO));
     967           0 :   key_generation++;
     968           0 :   TEH_resume_keys_requests (false);
     969           0 :   hd = GNUNET_CONTAINER_multihashmap_get (hs->cs_keys,
     970             :                                           &h_cs->hash);
     971           0 :   if (NULL != hd)
     972             :   {
     973             :     /* should be just an update (revocation!), so update existing entry */
     974           0 :     hd->validity_duration = validity_duration;
     975           0 :     return;
     976             :   }
     977           0 :   GNUNET_assert (NULL != sm_pub);
     978           0 :   check_denom_cs_sm_pub (sm_pub);
     979           0 :   hd = GNUNET_new (struct HelperDenomination);
     980           0 :   hd->start_time = start_time;
     981           0 :   hd->validity_duration = validity_duration;
     982           0 :   hd->h_details.h_cs = *h_cs;
     983           0 :   hd->sm_sig = *sm_sig;
     984           0 :   GNUNET_assert (TALER_DENOMINATION_CS == denom_pub->cipher);
     985           0 :   TALER_denom_pub_deep_copy (&hd->denom_pub,
     986             :                              denom_pub);
     987             :   /* load the age mask for the denomination, if applicable */
     988           0 :   hd->denom_pub.age_mask = load_age_mask (section_name);
     989           0 :   TALER_denom_pub_hash (&hd->denom_pub,
     990             :                         &hd->h_denom_pub);
     991           0 :   hd->section_name = GNUNET_strdup (section_name);
     992           0 :   GNUNET_assert (
     993             :     GNUNET_OK ==
     994             :     GNUNET_CONTAINER_multihashmap_put (
     995             :       hs->denom_keys,
     996             :       &hd->h_denom_pub.hash,
     997             :       hd,
     998             :       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
     999           0 :   GNUNET_assert (
    1000             :     GNUNET_OK ==
    1001             :     GNUNET_CONTAINER_multihashmap_put (
    1002             :       hs->cs_keys,
    1003             :       &hd->h_details.h_cs.hash,
    1004             :       hd,
    1005             :       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    1006             : }
    1007             : 
    1008             : 
    1009             : /**
    1010             :  * Function called with information about available keys for signing.  Usually
    1011             :  * only called once per key upon connect. Also called again in case a key is
    1012             :  * being revoked, in that case with an @a end_time of zero.
    1013             :  *
    1014             :  * @param cls closure with the `struct HelperState *`
    1015             :  * @param start_time when does the key become available for signing;
    1016             :  *                 zero if the key has been revoked or purged
    1017             :  * @param validity_duration how long does the key remain available for signing;
    1018             :  *                 zero if the key has been revoked or purged
    1019             :  * @param exchange_pub the public key itself, NULL if the key was revoked or purged
    1020             :  * @param sm_pub public key of the security module, NULL if the key was revoked or purged
    1021             :  * @param sm_sig signature from the security module, NULL if the key was revoked or purged
    1022             :  *               The signature was already verified against @a sm_pub.
    1023             :  */
    1024             : static void
    1025           0 : helper_esign_cb (
    1026             :   void *cls,
    1027             :   struct GNUNET_TIME_Timestamp start_time,
    1028             :   struct GNUNET_TIME_Relative validity_duration,
    1029             :   const struct TALER_ExchangePublicKeyP *exchange_pub,
    1030             :   const struct TALER_SecurityModulePublicKeyP *sm_pub,
    1031             :   const struct TALER_SecurityModuleSignatureP *sm_sig)
    1032             : {
    1033           0 :   struct HelperState *hs = cls;
    1034             :   struct HelperSignkey *hsk;
    1035             :   struct GNUNET_PeerIdentity pid;
    1036             : 
    1037           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1038             :               "EdDSA helper announces signing key %s with validity %s\n",
    1039             :               TALER_B2S (exchange_pub),
    1040             :               GNUNET_STRINGS_relative_time_to_string (validity_duration,
    1041             :                                                       GNUNET_NO));
    1042           0 :   key_generation++;
    1043           0 :   TEH_resume_keys_requests (false);
    1044           0 :   pid.public_key = exchange_pub->eddsa_pub;
    1045           0 :   hsk = GNUNET_CONTAINER_multipeermap_get (hs->esign_keys,
    1046             :                                            &pid);
    1047           0 :   if (NULL != hsk)
    1048             :   {
    1049             :     /* should be just an update (revocation!), so update existing entry */
    1050           0 :     hsk->validity_duration = validity_duration;
    1051           0 :     return;
    1052             :   }
    1053           0 :   GNUNET_assert (NULL != sm_pub);
    1054           0 :   check_esign_sm_pub (sm_pub);
    1055           0 :   hsk = GNUNET_new (struct HelperSignkey);
    1056           0 :   hsk->start_time = start_time;
    1057           0 :   hsk->validity_duration = validity_duration;
    1058           0 :   hsk->exchange_pub = *exchange_pub;
    1059           0 :   hsk->sm_sig = *sm_sig;
    1060           0 :   GNUNET_assert (
    1061             :     GNUNET_OK ==
    1062             :     GNUNET_CONTAINER_multipeermap_put (
    1063             :       hs->esign_keys,
    1064             :       &pid,
    1065             :       hsk,
    1066             :       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    1067             : }
    1068             : 
    1069             : 
    1070             : /**
    1071             :  * Setup helper state.
    1072             :  *
    1073             :  * @param[out] hs helper state to initialize
    1074             :  * @return #GNUNET_OK on success
    1075             :  */
    1076             : static enum GNUNET_GenericReturnValue
    1077           0 : setup_key_helpers (struct HelperState *hs)
    1078             : {
    1079             :   hs->denom_keys
    1080           0 :     = GNUNET_CONTAINER_multihashmap_create (1024,
    1081             :                                             GNUNET_YES);
    1082             :   hs->rsa_keys
    1083           0 :     = GNUNET_CONTAINER_multihashmap_create (1024,
    1084             :                                             GNUNET_YES);
    1085             :   hs->cs_keys
    1086           0 :     = GNUNET_CONTAINER_multihashmap_create (1024,
    1087             :                                             GNUNET_YES);
    1088             :   hs->esign_keys
    1089           0 :     = GNUNET_CONTAINER_multipeermap_create (32,
    1090             :                                             GNUNET_NO /* MUST BE NO! */);
    1091           0 :   hs->rsadh = TALER_CRYPTO_helper_rsa_connect (TEH_cfg,
    1092             :                                                &helper_rsa_cb,
    1093             :                                                hs);
    1094           0 :   if (NULL == hs->rsadh)
    1095             :   {
    1096           0 :     destroy_key_helpers (hs);
    1097           0 :     return GNUNET_SYSERR;
    1098             :   }
    1099           0 :   hs->csdh = TALER_CRYPTO_helper_cs_connect (TEH_cfg,
    1100             :                                              &helper_cs_cb,
    1101             :                                              hs);
    1102           0 :   if (NULL == hs->csdh)
    1103             :   {
    1104           0 :     destroy_key_helpers (hs);
    1105           0 :     return GNUNET_SYSERR;
    1106             :   }
    1107           0 :   hs->esh = TALER_CRYPTO_helper_esign_connect (TEH_cfg,
    1108             :                                                &helper_esign_cb,
    1109             :                                                hs);
    1110           0 :   if (NULL == hs->esh)
    1111             :   {
    1112           0 :     destroy_key_helpers (hs);
    1113           0 :     return GNUNET_SYSERR;
    1114             :   }
    1115           0 :   return GNUNET_OK;
    1116             : }
    1117             : 
    1118             : 
    1119             : /**
    1120             :  * Synchronize helper state. Polls the key helper for updates.
    1121             :  *
    1122             :  * @param[in,out] hs helper state to synchronize
    1123             :  */
    1124             : static void
    1125           0 : sync_key_helpers (struct HelperState *hs)
    1126             : {
    1127           0 :   TALER_CRYPTO_helper_rsa_poll (hs->rsadh);
    1128           0 :   TALER_CRYPTO_helper_cs_poll (hs->csdh);
    1129           0 :   TALER_CRYPTO_helper_esign_poll (hs->esh);
    1130           0 : }
    1131             : 
    1132             : 
    1133             : /**
    1134             :  * Free denomination key data.
    1135             :  *
    1136             :  * @param cls a `struct TEH_KeyStateHandle`, unused
    1137             :  * @param h_denom_pub hash of the denomination public key, unused
    1138             :  * @param value a `struct TEH_DenominationKey` to free
    1139             :  * @return #GNUNET_OK (continue to iterate)
    1140             :  */
    1141             : static enum GNUNET_GenericReturnValue
    1142           0 : clear_denomination_cb (void *cls,
    1143             :                        const struct GNUNET_HashCode *h_denom_pub,
    1144             :                        void *value)
    1145             : {
    1146           0 :   struct TEH_DenominationKey *dk = value;
    1147             :   struct TEH_AuditorSignature *as;
    1148             : 
    1149             :   (void) cls;
    1150             :   (void) h_denom_pub;
    1151           0 :   TALER_denom_pub_free (&dk->denom_pub);
    1152           0 :   while (NULL != (as = dk->as_head))
    1153             :   {
    1154           0 :     GNUNET_CONTAINER_DLL_remove (dk->as_head,
    1155             :                                  dk->as_tail,
    1156             :                                  as);
    1157           0 :     GNUNET_free (as);
    1158             :   }
    1159           0 :   GNUNET_free (dk);
    1160           0 :   return GNUNET_OK;
    1161             : }
    1162             : 
    1163             : 
    1164             : /**
    1165             :  * Free denomination key data.
    1166             :  *
    1167             :  * @param cls a `struct TEH_KeyStateHandle`, unused
    1168             :  * @param pid the online signing key (type-disguised), unused
    1169             :  * @param value a `struct SigningKey` to free
    1170             :  * @return #GNUNET_OK (continue to iterate)
    1171             :  */
    1172             : static enum GNUNET_GenericReturnValue
    1173           0 : clear_signkey_cb (void *cls,
    1174             :                   const struct GNUNET_PeerIdentity *pid,
    1175             :                   void *value)
    1176             : {
    1177           0 :   struct SigningKey *sk = value;
    1178             : 
    1179             :   (void) cls;
    1180             :   (void) pid;
    1181           0 :   GNUNET_free (sk);
    1182           0 :   return GNUNET_OK;
    1183             : }
    1184             : 
    1185             : 
    1186             : /**
    1187             :  * Free resources associated with @a cls, possibly excluding
    1188             :  * the helper data.
    1189             :  *
    1190             :  * @param[in] ksh key state to release
    1191             :  * @param free_helper true to also release the helper state
    1192             :  */
    1193             : static void
    1194           0 : destroy_key_state (struct TEH_KeyStateHandle *ksh,
    1195             :                    bool free_helper)
    1196             : {
    1197             :   struct TEH_GlobalFee *gf;
    1198             : 
    1199           0 :   clear_response_cache (ksh);
    1200           0 :   while (NULL != (gf = ksh->gf_head))
    1201             :   {
    1202           0 :     GNUNET_CONTAINER_DLL_remove (ksh->gf_head,
    1203             :                                  ksh->gf_tail,
    1204             :                                  gf);
    1205           0 :     GNUNET_free (gf);
    1206             :   }
    1207           0 :   GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
    1208             :                                          &clear_denomination_cb,
    1209             :                                          ksh);
    1210           0 :   GNUNET_CONTAINER_multihashmap_destroy (ksh->denomkey_map);
    1211           0 :   GNUNET_CONTAINER_multipeermap_iterate (ksh->signkey_map,
    1212             :                                          &clear_signkey_cb,
    1213             :                                          ksh);
    1214           0 :   GNUNET_CONTAINER_multipeermap_destroy (ksh->signkey_map);
    1215           0 :   json_decref (ksh->auditors);
    1216           0 :   ksh->auditors = NULL;
    1217           0 :   json_decref (ksh->global_fees);
    1218           0 :   ksh->global_fees = NULL;
    1219           0 :   if (free_helper)
    1220             :   {
    1221           0 :     destroy_key_helpers (ksh->helpers);
    1222           0 :     GNUNET_free (ksh->helpers);
    1223             :   }
    1224           0 :   if (NULL != ksh->management_keys_reply)
    1225             :   {
    1226           0 :     json_decref (ksh->management_keys_reply);
    1227           0 :     ksh->management_keys_reply = NULL;
    1228             :   }
    1229           0 :   GNUNET_free (ksh);
    1230           0 : }
    1231             : 
    1232             : 
    1233             : /**
    1234             :  * Function called whenever another exchange process has updated
    1235             :  * the keys data in the database.
    1236             :  *
    1237             :  * @param cls NULL
    1238             :  * @param extra unused
    1239             :  * @param extra_size number of bytes in @a extra unused
    1240             :  */
    1241             : static void
    1242           0 : keys_update_event_cb (void *cls,
    1243             :                       const void *extra,
    1244             :                       size_t extra_size)
    1245             : {
    1246             :   (void) cls;
    1247             :   (void) extra;
    1248             :   (void) extra_size;
    1249           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1250             :               "Received /keys update event\n");
    1251           0 :   TEH_check_invariants ();
    1252           0 :   key_generation++;
    1253           0 :   TEH_resume_keys_requests (false);
    1254           0 :   TEH_check_invariants ();
    1255           0 : }
    1256             : 
    1257             : 
    1258             : enum GNUNET_GenericReturnValue
    1259           0 : TEH_keys_init ()
    1260             : {
    1261           0 :   struct GNUNET_DB_EventHeaderP es = {
    1262           0 :     .size = htons (sizeof (es)),
    1263           0 :     .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED),
    1264             :   };
    1265             : 
    1266           0 :   if (GNUNET_OK !=
    1267           0 :       GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
    1268             :                                            "exchange",
    1269             :                                            "SIGNKEY_LEGAL_DURATION",
    1270             :                                            &signkey_legal_duration))
    1271             :   {
    1272           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1273             :                                "exchange",
    1274             :                                "SIGNKEY_LEGAL_DURATION");
    1275           0 :     return GNUNET_SYSERR;
    1276             :   }
    1277           0 :   keys_eh = TEH_plugin->event_listen (TEH_plugin->cls,
    1278           0 :                                       GNUNET_TIME_UNIT_FOREVER_REL,
    1279             :                                       &es,
    1280             :                                       &keys_update_event_cb,
    1281             :                                       NULL);
    1282           0 :   if (NULL == keys_eh)
    1283             :   {
    1284           0 :     GNUNET_break (0);
    1285           0 :     return GNUNET_SYSERR;
    1286             :   }
    1287           0 :   return GNUNET_OK;
    1288             : }
    1289             : 
    1290             : 
    1291             : /**
    1292             :  * Fully clean up our state.
    1293             :  */
    1294             : void
    1295           0 : TEH_keys_finished ()
    1296             : {
    1297           0 :   if (NULL != keys_tt)
    1298             :   {
    1299           0 :     GNUNET_SCHEDULER_cancel (keys_tt);
    1300           0 :     keys_tt = NULL;
    1301             :   }
    1302           0 :   if (NULL != key_state)
    1303           0 :     destroy_key_state (key_state,
    1304             :                        true);
    1305           0 :   if (NULL != keys_eh)
    1306             :   {
    1307           0 :     TEH_plugin->event_listen_cancel (TEH_plugin->cls,
    1308             :                                      keys_eh);
    1309           0 :     keys_eh = NULL;
    1310             :   }
    1311           0 : }
    1312             : 
    1313             : 
    1314             : /**
    1315             :  * Function called with information about the exchange's denomination keys.
    1316             :  *
    1317             :  * @param cls closure with a `struct TEH_KeyStateHandle *`
    1318             :  * @param denom_pub public key of the denomination
    1319             :  * @param h_denom_pub hash of @a denom_pub
    1320             :  * @param meta meta data information about the denomination type (value, expirations, fees)
    1321             :  * @param master_sig master signature affirming the validity of this denomination
    1322             :  * @param recoup_possible true if the key was revoked and clients can currently recoup
    1323             :  *        coins of this denomination
    1324             :  */
    1325             : static void
    1326           0 : denomination_info_cb (
    1327             :   void *cls,
    1328             :   const struct TALER_DenominationPublicKey *denom_pub,
    1329             :   const struct TALER_DenominationHashP *h_denom_pub,
    1330             :   const struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta,
    1331             :   const struct TALER_MasterSignatureP *master_sig,
    1332             :   bool recoup_possible)
    1333             : {
    1334           0 :   struct TEH_KeyStateHandle *ksh = cls;
    1335             :   struct TEH_DenominationKey *dk;
    1336             : 
    1337           0 :   GNUNET_assert (TALER_DENOMINATION_INVALID != denom_pub->cipher);
    1338           0 :   if (GNUNET_TIME_absolute_is_zero (meta->start.abs_time) ||
    1339           0 :       GNUNET_TIME_absolute_is_zero (meta->expire_withdraw.abs_time) ||
    1340           0 :       GNUNET_TIME_absolute_is_zero (meta->expire_deposit.abs_time) ||
    1341           0 :       GNUNET_TIME_absolute_is_zero (meta->expire_legal.abs_time) )
    1342             :   {
    1343           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1344             :                 "Database contains invalid denomination key %s\n",
    1345             :                 GNUNET_h2s (&h_denom_pub->hash));
    1346           0 :     return;
    1347             :   }
    1348           0 :   dk = GNUNET_new (struct TEH_DenominationKey);
    1349           0 :   TALER_denom_pub_deep_copy (&dk->denom_pub,
    1350             :                              denom_pub);
    1351           0 :   dk->h_denom_pub = *h_denom_pub;
    1352           0 :   dk->meta = *meta;
    1353           0 :   dk->master_sig = *master_sig;
    1354           0 :   dk->recoup_possible = recoup_possible;
    1355           0 :   dk->denom_pub.age_mask = meta->age_mask;
    1356             : 
    1357           0 :   GNUNET_assert (
    1358             :     GNUNET_OK ==
    1359             :     GNUNET_CONTAINER_multihashmap_put (ksh->denomkey_map,
    1360             :                                        &dk->h_denom_pub.hash,
    1361             :                                        dk,
    1362             :                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    1363             : 
    1364             : }
    1365             : 
    1366             : 
    1367             : /**
    1368             :  * Function called with information about the exchange's online signing keys.
    1369             :  *
    1370             :  * @param cls closure with a `struct TEH_KeyStateHandle *`
    1371             :  * @param exchange_pub the public key
    1372             :  * @param meta meta data information about the denomination type (expirations)
    1373             :  * @param master_sig master signature affirming the validity of this denomination
    1374             :  */
    1375             : static void
    1376           0 : signkey_info_cb (
    1377             :   void *cls,
    1378             :   const struct TALER_ExchangePublicKeyP *exchange_pub,
    1379             :   const struct TALER_EXCHANGEDB_SignkeyMetaData *meta,
    1380             :   const struct TALER_MasterSignatureP *master_sig)
    1381             : {
    1382           0 :   struct TEH_KeyStateHandle *ksh = cls;
    1383             :   struct SigningKey *sk;
    1384             :   struct GNUNET_PeerIdentity pid;
    1385             : 
    1386           0 :   sk = GNUNET_new (struct SigningKey);
    1387           0 :   sk->exchange_pub = *exchange_pub;
    1388           0 :   sk->meta = *meta;
    1389           0 :   sk->master_sig = *master_sig;
    1390           0 :   pid.public_key = exchange_pub->eddsa_pub;
    1391           0 :   GNUNET_assert (
    1392             :     GNUNET_OK ==
    1393             :     GNUNET_CONTAINER_multipeermap_put (ksh->signkey_map,
    1394             :                                        &pid,
    1395             :                                        sk,
    1396             :                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    1397           0 : }
    1398             : 
    1399             : 
    1400             : /**
    1401             :  * Closure for #get_auditor_sigs.
    1402             :  */
    1403             : struct GetAuditorSigsContext
    1404             : {
    1405             :   /**
    1406             :    * Where to store the matching signatures.
    1407             :    */
    1408             :   json_t *denom_keys;
    1409             : 
    1410             :   /**
    1411             :    * Public key of the auditor to match against.
    1412             :    */
    1413             :   const struct TALER_AuditorPublicKeyP *auditor_pub;
    1414             : };
    1415             : 
    1416             : 
    1417             : /**
    1418             :  * Extract the auditor signatures matching the auditor's public
    1419             :  * key from the @a value and generate the respective JSON.
    1420             :  *
    1421             :  * @param cls a `struct GetAuditorSigsContext`
    1422             :  * @param h_denom_pub hash of the denomination public key
    1423             :  * @param value a `struct TEH_DenominationKey`
    1424             :  * @return #GNUNET_OK (continue to iterate)
    1425             :  */
    1426             : static enum GNUNET_GenericReturnValue
    1427           0 : get_auditor_sigs (void *cls,
    1428             :                   const struct GNUNET_HashCode *h_denom_pub,
    1429             :                   void *value)
    1430             : {
    1431           0 :   struct GetAuditorSigsContext *ctx = cls;
    1432           0 :   struct TEH_DenominationKey *dk = value;
    1433             : 
    1434           0 :   for (struct TEH_AuditorSignature *as = dk->as_head;
    1435             :        NULL != as;
    1436           0 :        as = as->next)
    1437             :   {
    1438           0 :     if (0 !=
    1439           0 :         GNUNET_memcmp (ctx->auditor_pub,
    1440             :                        &as->apub))
    1441           0 :       continue;
    1442           0 :     GNUNET_break (0 ==
    1443             :                   json_array_append_new (
    1444             :                     ctx->denom_keys,
    1445             :                     GNUNET_JSON_PACK (
    1446             :                       GNUNET_JSON_pack_data_auto ("denom_pub_h",
    1447             :                                                   h_denom_pub),
    1448             :                       GNUNET_JSON_pack_data_auto ("auditor_sig",
    1449             :                                                   &as->asig))));
    1450             :   }
    1451           0 :   return GNUNET_OK;
    1452             : }
    1453             : 
    1454             : 
    1455             : /**
    1456             :  * Function called with information about the exchange's auditors.
    1457             :  *
    1458             :  * @param cls closure with a `struct TEH_KeyStateHandle *`
    1459             :  * @param auditor_pub the public key of the auditor
    1460             :  * @param auditor_url URL of the REST API of the auditor
    1461             :  * @param auditor_name human readable official name of the auditor
    1462             :  */
    1463             : static void
    1464           0 : auditor_info_cb (
    1465             :   void *cls,
    1466             :   const struct TALER_AuditorPublicKeyP *auditor_pub,
    1467             :   const char *auditor_url,
    1468             :   const char *auditor_name)
    1469             : {
    1470           0 :   struct TEH_KeyStateHandle *ksh = cls;
    1471             :   struct GetAuditorSigsContext ctx;
    1472             : 
    1473           0 :   ctx.denom_keys = json_array ();
    1474           0 :   GNUNET_assert (NULL != ctx.denom_keys);
    1475           0 :   ctx.auditor_pub = auditor_pub;
    1476           0 :   GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
    1477             :                                          &get_auditor_sigs,
    1478             :                                          &ctx);
    1479           0 :   GNUNET_break (0 ==
    1480             :                 json_array_append_new (
    1481             :                   ksh->auditors,
    1482             :                   GNUNET_JSON_PACK (
    1483             :                     GNUNET_JSON_pack_string ("auditor_name",
    1484             :                                              auditor_name),
    1485             :                     GNUNET_JSON_pack_data_auto ("auditor_pub",
    1486             :                                                 auditor_pub),
    1487             :                     GNUNET_JSON_pack_string ("auditor_url",
    1488             :                                              auditor_url),
    1489             :                     GNUNET_JSON_pack_array_steal ("denomination_keys",
    1490             :                                                   ctx.denom_keys))));
    1491           0 : }
    1492             : 
    1493             : 
    1494             : /**
    1495             :  * Function called with information about the denominations
    1496             :  * audited by the exchange's auditors.
    1497             :  *
    1498             :  * @param cls closure with a `struct TEH_KeyStateHandle *`
    1499             :  * @param auditor_pub the public key of an auditor
    1500             :  * @param h_denom_pub hash of a denomination key audited by this auditor
    1501             :  * @param auditor_sig signature from the auditor affirming this
    1502             :  */
    1503             : static void
    1504           0 : auditor_denom_cb (
    1505             :   void *cls,
    1506             :   const struct TALER_AuditorPublicKeyP *auditor_pub,
    1507             :   const struct TALER_DenominationHashP *h_denom_pub,
    1508             :   const struct TALER_AuditorSignatureP *auditor_sig)
    1509             : {
    1510           0 :   struct TEH_KeyStateHandle *ksh = cls;
    1511             :   struct TEH_DenominationKey *dk;
    1512             :   struct TEH_AuditorSignature *as;
    1513             : 
    1514           0 :   dk = GNUNET_CONTAINER_multihashmap_get (ksh->denomkey_map,
    1515             :                                           &h_denom_pub->hash);
    1516           0 :   if (NULL == dk)
    1517             :   {
    1518             :     /* Odd, this should be impossible as per foreign key
    1519             :        constraint on 'auditor_denom_sigs'! Well, we can
    1520             :        safely continue anyway, so let's just log it. */
    1521           0 :     GNUNET_break (0);
    1522           0 :     return;
    1523             :   }
    1524           0 :   as = GNUNET_new (struct TEH_AuditorSignature);
    1525           0 :   as->asig = *auditor_sig;
    1526           0 :   as->apub = *auditor_pub;
    1527           0 :   GNUNET_CONTAINER_DLL_insert (dk->as_head,
    1528             :                                dk->as_tail,
    1529             :                                as);
    1530             : }
    1531             : 
    1532             : 
    1533             : /**
    1534             :  * Closure for #add_sign_key_cb.
    1535             :  */
    1536             : struct SignKeyCtx
    1537             : {
    1538             :   /**
    1539             :    * What is the current rotation frequency for signing keys. Updated.
    1540             :    */
    1541             :   struct GNUNET_TIME_Relative min_sk_frequency;
    1542             : 
    1543             :   /**
    1544             :    * JSON array of signing keys (being created).
    1545             :    */
    1546             :   json_t *signkeys;
    1547             : };
    1548             : 
    1549             : 
    1550             : /**
    1551             :  * Function called for all signing keys, used to build up the
    1552             :  * respective JSON response.
    1553             :  *
    1554             :  * @param cls a `struct SignKeyCtx *` with the array to append keys to
    1555             :  * @param pid the exchange public key (in type disguise)
    1556             :  * @param value a `struct SigningKey`
    1557             :  * @return #GNUNET_OK (continue to iterate)
    1558             :  */
    1559             : static enum GNUNET_GenericReturnValue
    1560           0 : add_sign_key_cb (void *cls,
    1561             :                  const struct GNUNET_PeerIdentity *pid,
    1562             :                  void *value)
    1563             : {
    1564           0 :   struct SignKeyCtx *ctx = cls;
    1565           0 :   struct SigningKey *sk = value;
    1566             : 
    1567             :   (void) pid;
    1568           0 :   if (GNUNET_TIME_absolute_is_future (sk->meta.expire_sign.abs_time))
    1569             :   {
    1570             :     ctx->min_sk_frequency =
    1571           0 :       GNUNET_TIME_relative_min (ctx->min_sk_frequency,
    1572             :                                 GNUNET_TIME_absolute_get_difference (
    1573             :                                   sk->meta.start.abs_time,
    1574             :                                   sk->meta.expire_sign.abs_time));
    1575             :   }
    1576           0 :   GNUNET_assert (
    1577             :     0 ==
    1578             :     json_array_append_new (
    1579             :       ctx->signkeys,
    1580             :       GNUNET_JSON_PACK (
    1581             :         GNUNET_JSON_pack_timestamp ("stamp_start",
    1582             :                                     sk->meta.start),
    1583             :         GNUNET_JSON_pack_timestamp ("stamp_expire",
    1584             :                                     sk->meta.expire_sign),
    1585             :         GNUNET_JSON_pack_timestamp ("stamp_end",
    1586             :                                     sk->meta.expire_legal),
    1587             :         GNUNET_JSON_pack_data_auto ("master_sig",
    1588             :                                     &sk->master_sig),
    1589             :         GNUNET_JSON_pack_data_auto ("key",
    1590             :                                     &sk->exchange_pub))));
    1591           0 :   return GNUNET_OK;
    1592             : }
    1593             : 
    1594             : 
    1595             : /**
    1596             :  * Closure for #add_denom_key_cb.
    1597             :  */
    1598             : struct DenomKeyCtx
    1599             : {
    1600             :   /**
    1601             :    * Heap for sorting active denomination keys by start time.
    1602             :    */
    1603             :   struct GNUNET_CONTAINER_Heap *heap;
    1604             : 
    1605             :   /**
    1606             :    * JSON array of revoked denomination keys.
    1607             :    */
    1608             :   json_t *recoup;
    1609             : 
    1610             :   /**
    1611             :    * What is the minimum key rotation frequency of
    1612             :    * valid denomination keys?
    1613             :    */
    1614             :   struct GNUNET_TIME_Relative min_dk_frequency;
    1615             : };
    1616             : 
    1617             : 
    1618             : /**
    1619             :  * Function called for all denomination keys, used to build up the
    1620             :  * JSON list of *revoked* denomination keys and the
    1621             :  * heap of non-revoked denomination keys by timeout.
    1622             :  *
    1623             :  * @param cls a `struct DenomKeyCtx`
    1624             :  * @param h_denom_pub hash of the denomination key
    1625             :  * @param value a `struct TEH_DenominationKey`
    1626             :  * @return #GNUNET_OK (continue to iterate)
    1627             :  */
    1628             : static enum GNUNET_GenericReturnValue
    1629           0 : add_denom_key_cb (void *cls,
    1630             :                   const struct GNUNET_HashCode *h_denom_pub,
    1631             :                   void *value)
    1632             : {
    1633           0 :   struct DenomKeyCtx *dkc = cls;
    1634           0 :   struct TEH_DenominationKey *dk = value;
    1635             : 
    1636           0 :   if (dk->recoup_possible)
    1637             :   {
    1638           0 :     GNUNET_assert (
    1639             :       0 ==
    1640             :       json_array_append_new (
    1641             :         dkc->recoup,
    1642             :         GNUNET_JSON_PACK (
    1643             :           GNUNET_JSON_pack_data_auto ("h_denom_pub",
    1644             :                                       h_denom_pub))));
    1645             :   }
    1646             :   else
    1647             :   {
    1648           0 :     if (GNUNET_TIME_absolute_is_future (dk->meta.start.abs_time))
    1649             :     {
    1650             :       dkc->min_dk_frequency =
    1651           0 :         GNUNET_TIME_relative_min (dkc->min_dk_frequency,
    1652             :                                   GNUNET_TIME_absolute_get_difference (
    1653             :                                     dk->meta.start.abs_time,
    1654             :                                     dk->meta.expire_withdraw.abs_time));
    1655             :     }
    1656           0 :     (void) GNUNET_CONTAINER_heap_insert (dkc->heap,
    1657             :                                          dk,
    1658             :                                          dk->meta.start.abs_time.abs_value_us);
    1659             :   }
    1660           0 :   return GNUNET_OK;
    1661             : }
    1662             : 
    1663             : 
    1664             : /**
    1665             :  * Add the headers we want to set for every /keys response.
    1666             :  *
    1667             :  * @param ksh the key state to use
    1668             :  * @param[in,out] response the response to modify
    1669             :  * @return #GNUNET_OK on success
    1670             :  */
    1671             : static enum GNUNET_GenericReturnValue
    1672           0 : setup_general_response_headers (struct TEH_KeyStateHandle *ksh,
    1673             :                                 struct MHD_Response *response)
    1674             : {
    1675             :   char dat[128];
    1676             : 
    1677           0 :   TALER_MHD_add_global_headers (response);
    1678           0 :   GNUNET_break (MHD_YES ==
    1679             :                 MHD_add_response_header (response,
    1680             :                                          MHD_HTTP_HEADER_CONTENT_TYPE,
    1681             :                                          "application/json"));
    1682           0 :   TALER_MHD_get_date_string (ksh->reload_time.abs_time,
    1683             :                              dat);
    1684           0 :   GNUNET_break (MHD_YES ==
    1685             :                 MHD_add_response_header (response,
    1686             :                                          MHD_HTTP_HEADER_LAST_MODIFIED,
    1687             :                                          dat));
    1688           0 :   if (! GNUNET_TIME_relative_is_zero (ksh->rekey_frequency))
    1689             :   {
    1690             :     struct GNUNET_TIME_Relative r;
    1691             :     struct GNUNET_TIME_Absolute a;
    1692             :     struct GNUNET_TIME_Timestamp m;
    1693             : 
    1694           0 :     r = GNUNET_TIME_relative_min (TEH_max_keys_caching,
    1695             :                                   ksh->rekey_frequency);
    1696           0 :     a = GNUNET_TIME_relative_to_absolute (r);
    1697           0 :     m = GNUNET_TIME_absolute_to_timestamp (a);
    1698           0 :     TALER_MHD_get_date_string (m.abs_time,
    1699             :                                dat);
    1700           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1701             :                 "Setting /keys 'Expires' header to '%s'\n",
    1702             :                 dat);
    1703           0 :     GNUNET_break (MHD_YES ==
    1704             :                   MHD_add_response_header (response,
    1705             :                                            MHD_HTTP_HEADER_EXPIRES,
    1706             :                                            dat));
    1707             :     ksh->signature_expires
    1708           0 :       = GNUNET_TIME_timestamp_min (m,
    1709             :                                    ksh->signature_expires);
    1710             :   }
    1711             :   /* Set cache control headers: our response varies depending on these headers */
    1712           0 :   GNUNET_break (MHD_YES ==
    1713             :                 MHD_add_response_header (response,
    1714             :                                          MHD_HTTP_HEADER_VARY,
    1715             :                                          MHD_HTTP_HEADER_ACCEPT_ENCODING));
    1716             :   /* Information is always public, revalidate after 1 hour */
    1717           0 :   GNUNET_break (MHD_YES ==
    1718             :                 MHD_add_response_header (response,
    1719             :                                          MHD_HTTP_HEADER_CACHE_CONTROL,
    1720             :                                          "public,max-age=3600"));
    1721           0 :   return GNUNET_OK;
    1722             : }
    1723             : 
    1724             : 
    1725             : /**
    1726             :  * Function called with wallet balance thresholds.
    1727             :  *
    1728             :  * @param[in,out] cls a `json **` where to put the array of json amounts discovered
    1729             :  * @param threshold another threshold amount to add
    1730             :  */
    1731             : static void
    1732           0 : wallet_threshold_cb (void *cls,
    1733             :                      const struct TALER_Amount *threshold)
    1734             : {
    1735           0 :   json_t **ret = cls;
    1736             : 
    1737           0 :   if (NULL == *ret)
    1738           0 :     *ret = json_array ();
    1739           0 :   GNUNET_assert (0 ==
    1740             :                  json_array_append_new (*ret,
    1741             :                                         TALER_JSON_from_amount (
    1742             :                                           threshold)));
    1743           0 : }
    1744             : 
    1745             : 
    1746             : /**
    1747             :  * Initialize @a krd using the given values for @a signkeys,
    1748             :  * @a recoup and @a denoms.
    1749             :  *
    1750             :  * @param[in,out] ksh key state handle we build @a krd for
    1751             :  * @param[in] denom_keys_hash hash over all the denomination keys in @a denoms
    1752             :  * @param last_cpd timestamp to use
    1753             :  * @param signkeys list of sign keys to return
    1754             :  * @param recoup list of revoked keys to return
    1755             :  * @param denoms list of denominations to return
    1756             :  * @param grouped_denominations list of grouped denominations to return
    1757             :  * @param[in] h_grouped XOR of all hashes in @a grouped_demoninations
    1758             :  * @return #GNUNET_OK on success
    1759             :  */
    1760             : static enum GNUNET_GenericReturnValue
    1761           0 : create_krd (struct TEH_KeyStateHandle *ksh,
    1762             :             const struct GNUNET_HashCode *denom_keys_hash,
    1763             :             struct GNUNET_TIME_Timestamp last_cpd,
    1764             :             json_t *signkeys,
    1765             :             json_t *recoup,
    1766             :             json_t *denoms,
    1767             :             json_t *grouped_denominations,
    1768             :             const struct GNUNET_HashCode *h_grouped)
    1769             : {
    1770             :   struct KeysResponseData krd;
    1771             :   struct TALER_ExchangePublicKeyP exchange_pub;
    1772             :   struct TALER_ExchangeSignatureP exchange_sig;
    1773             :   struct TALER_ExchangePublicKeyP grouped_exchange_pub;
    1774             :   struct TALER_ExchangeSignatureP grouped_exchange_sig;
    1775             :   json_t *keys;
    1776             : 
    1777           0 :   GNUNET_assert (! GNUNET_TIME_absolute_is_zero (last_cpd.abs_time));
    1778           0 :   GNUNET_assert (NULL != signkeys);
    1779           0 :   GNUNET_assert (NULL != recoup);
    1780           0 :   GNUNET_assert (NULL != denoms);
    1781           0 :   GNUNET_assert (NULL != grouped_denominations);
    1782           0 :   GNUNET_assert (NULL != h_grouped);
    1783           0 :   GNUNET_assert (NULL != ksh->auditors);
    1784           0 :   GNUNET_assert (NULL != TEH_currency);
    1785           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1786             :               "Creating /keys at cherry pick date %s\n",
    1787             :               GNUNET_TIME_timestamp2s (last_cpd));
    1788             : 
    1789             :   /* Sign hash over denomination keys */
    1790             :   {
    1791             :     enum TALER_ErrorCode ec;
    1792             : 
    1793           0 :     if (TALER_EC_NONE !=
    1794             :         (ec =
    1795           0 :            TALER_exchange_online_key_set_sign (
    1796             :              &TEH_keys_exchange_sign2_,
    1797             :              ksh,
    1798             :              last_cpd,
    1799             :              denom_keys_hash,
    1800             :              &exchange_pub,
    1801             :              &exchange_sig)))
    1802             :     {
    1803           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1804             :                   "Could not create key response data: cannot sign (%s)\n",
    1805             :                   TALER_ErrorCode_get_hint (ec));
    1806           0 :       return GNUNET_SYSERR;
    1807             :     }
    1808             :   }
    1809             : 
    1810             :   /* Sign grouped hash */
    1811             :   {
    1812             :     enum TALER_ErrorCode ec;
    1813             : 
    1814           0 :     if (TALER_EC_NONE !=
    1815             :         (ec =
    1816           0 :            TALER_exchange_online_key_set_sign (
    1817             :              &TEH_keys_exchange_sign2_,
    1818             :              ksh,
    1819             :              last_cpd,
    1820             :              h_grouped,
    1821             :              &grouped_exchange_pub,
    1822             :              &grouped_exchange_sig)))
    1823             :     {
    1824           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1825             :                   "Could not create key response data: cannot sign grouped hash (%s)\n",
    1826             :                   TALER_ErrorCode_get_hint (ec));
    1827           0 :       return GNUNET_SYSERR;
    1828             :     }
    1829             :   }
    1830             : 
    1831             :   /* both public keys really must be the same */
    1832           0 :   GNUNET_assert (0 ==
    1833             :                  memcmp (&grouped_exchange_pub,
    1834             :                          &exchange_pub,
    1835             :                          sizeof(exchange_pub)));
    1836             : 
    1837             :   {
    1838             :     const struct SigningKey *sk;
    1839             : 
    1840           0 :     sk = GNUNET_CONTAINER_multipeermap_get (
    1841           0 :       ksh->signkey_map,
    1842             :       (const struct GNUNET_PeerIdentity *) &exchange_pub);
    1843           0 :     ksh->signature_expires = GNUNET_TIME_timestamp_min (sk->meta.expire_sign,
    1844             :                                                         ksh->signature_expires);
    1845             :   }
    1846             : 
    1847           0 :   keys = GNUNET_JSON_PACK (
    1848             :     GNUNET_JSON_pack_string ("version",
    1849             :                              EXCHANGE_PROTOCOL_VERSION),
    1850             :     GNUNET_JSON_pack_string ("currency",
    1851             :                              TEH_currency),
    1852             :     GNUNET_JSON_pack_data_auto ("master_public_key",
    1853             :                                 &TEH_master_public_key),
    1854             :     GNUNET_JSON_pack_time_rel ("reserve_closing_delay",
    1855             :                                TEH_reserve_closing_delay),
    1856             :     GNUNET_JSON_pack_array_incref ("signkeys",
    1857             :                                    signkeys),
    1858             :     GNUNET_JSON_pack_array_incref ("recoup",
    1859             :                                    recoup),
    1860             :     GNUNET_JSON_pack_array_incref ("denoms",
    1861             :                                    denoms),
    1862             :     GNUNET_JSON_pack_array_incref ("denominations",
    1863             :                                    grouped_denominations),
    1864             :     GNUNET_JSON_pack_array_incref ("auditors",
    1865             :                                    ksh->auditors),
    1866             :     GNUNET_JSON_pack_array_incref ("global_fees",
    1867             :                                    ksh->global_fees),
    1868             :     GNUNET_JSON_pack_timestamp ("list_issue_date",
    1869             :                                 last_cpd),
    1870             :     GNUNET_JSON_pack_data_auto ("eddsa_pub",
    1871             :                                 &exchange_pub),
    1872             :     GNUNET_JSON_pack_data_auto ("eddsa_sig",
    1873             :                                 &exchange_sig),
    1874             :     GNUNET_JSON_pack_data_auto ("denominations_sig",
    1875             :                                 &grouped_exchange_sig));
    1876           0 :   GNUNET_assert (NULL != keys);
    1877             : 
    1878             :   /* Set wallet limit if KYC is configured */
    1879             :   {
    1880           0 :     json_t *wblwk = NULL;
    1881             : 
    1882           0 :     TALER_KYCLOGIC_kyc_iterate_thresholds (
    1883             :       TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE,
    1884             :       &wallet_threshold_cb,
    1885             :       &wblwk);
    1886           0 :     if (NULL != wblwk)
    1887           0 :       GNUNET_assert (
    1888             :         0 ==
    1889             :         json_object_set_new (
    1890             :           keys,
    1891             :           "wallet_balance_limit_without_kyc",
    1892             :           wblwk));
    1893             :   }
    1894             : 
    1895             :   /* Signal support for the configured, enabled extensions. */
    1896             :   {
    1897           0 :     json_t *extensions = json_object ();
    1898           0 :     bool has_extensions = false;
    1899             : 
    1900             :     /* Fill in the configurations of the enabled extensions */
    1901           0 :     for (const struct TALER_Extension *extension = TALER_extensions_get_head ();
    1902             :          NULL != extension;
    1903           0 :          extension = extension->next)
    1904             :     {
    1905             :       json_t *ext;
    1906             :       json_t *config_json;
    1907             :       int r;
    1908             : 
    1909             :       /* skip if not configured == disabled */
    1910           0 :       if (NULL == extension->config ||
    1911           0 :           NULL == extension->config_json)
    1912           0 :         continue;
    1913             : 
    1914             :       /* flag our findings so far */
    1915           0 :       has_extensions = true;
    1916             : 
    1917           0 :       GNUNET_assert (NULL != extension->config_json);
    1918             : 
    1919           0 :       config_json = json_copy (extension->config_json);
    1920           0 :       GNUNET_assert (NULL != config_json);
    1921             : 
    1922           0 :       ext = GNUNET_JSON_PACK (
    1923             :         GNUNET_JSON_pack_bool ("critical",
    1924             :                                extension->critical),
    1925             :         GNUNET_JSON_pack_string ("version",
    1926             :                                  extension->version),
    1927             :         GNUNET_JSON_pack_object_steal ("config",
    1928             :                                        config_json)
    1929             :         );
    1930           0 :       GNUNET_assert (NULL != ext);
    1931             : 
    1932           0 :       r = json_object_set_new (
    1933             :         extensions,
    1934           0 :         extension->name,
    1935             :         ext);
    1936           0 :       GNUNET_assert (0 == r);
    1937             :     }
    1938             : 
    1939             :     /* Update the keys object with the extensions and its signature */
    1940           0 :     if (has_extensions)
    1941             :     {
    1942             :       json_t *sig;
    1943             :       int r;
    1944             : 
    1945           0 :       r = json_object_set (
    1946             :         keys,
    1947             :         "extensions",
    1948             :         extensions);
    1949           0 :       GNUNET_assert (0 == r);
    1950             : 
    1951           0 :       sig = GNUNET_JSON_PACK (
    1952             :         GNUNET_JSON_pack_data_auto ("extensions_sig",
    1953             :                                     &TEH_extensions_sig));
    1954             : 
    1955           0 :       r = json_object_update (keys, sig);
    1956           0 :       GNUNET_assert (0 == r);
    1957             :     }
    1958             :     else
    1959             :     {
    1960           0 :       json_decref (extensions);
    1961             :     }
    1962             :   }
    1963             : 
    1964             : 
    1965             :   {
    1966             :     char *keys_json;
    1967             :     void *keys_jsonz;
    1968             :     size_t keys_jsonz_size;
    1969             :     int comp;
    1970             :     char etag[sizeof (struct GNUNET_HashCode) * 2];
    1971             : 
    1972             :     /* Convert /keys response to UTF8-String */
    1973           0 :     keys_json = json_dumps (keys,
    1974             :                             JSON_INDENT (2));
    1975           0 :     json_decref (keys);
    1976           0 :     GNUNET_assert (NULL != keys_json);
    1977             : 
    1978             :     /* Keep copy for later compression... */
    1979           0 :     keys_jsonz = GNUNET_strdup (keys_json);
    1980           0 :     keys_jsonz_size = strlen (keys_json);
    1981             : 
    1982             :     /* hash to compute etag */
    1983             :     {
    1984             :       struct GNUNET_HashCode ehash;
    1985             :       char *end;
    1986             : 
    1987           0 :       GNUNET_CRYPTO_hash (keys_jsonz,
    1988             :                           keys_jsonz_size,
    1989             :                           &ehash);
    1990           0 :       end = GNUNET_STRINGS_data_to_string (&ehash,
    1991             :                                            sizeof (ehash),
    1992             :                                            etag,
    1993             :                                            sizeof (etag));
    1994           0 :       *end = '\0';
    1995             :     }
    1996             : 
    1997             :     /* Create uncompressed response */
    1998             :     krd.response_uncompressed
    1999           0 :       = MHD_create_response_from_buffer (keys_jsonz_size,
    2000             :                                          keys_json,
    2001             :                                          MHD_RESPMEM_MUST_FREE);
    2002           0 :     GNUNET_assert (NULL != krd.response_uncompressed);
    2003           0 :     GNUNET_assert (GNUNET_OK ==
    2004             :                    setup_general_response_headers (ksh,
    2005             :                                                    krd.response_uncompressed));
    2006           0 :     GNUNET_break (MHD_YES ==
    2007             :                   MHD_add_response_header (krd.response_uncompressed,
    2008             :                                            MHD_HTTP_HEADER_ETAG,
    2009             :                                            etag));
    2010             :     /* Also compute compressed version of /keys response */
    2011           0 :     comp = TALER_MHD_body_compress (&keys_jsonz,
    2012             :                                     &keys_jsonz_size);
    2013             :     krd.response_compressed
    2014           0 :       = MHD_create_response_from_buffer (keys_jsonz_size,
    2015             :                                          keys_jsonz,
    2016             :                                          MHD_RESPMEM_MUST_FREE);
    2017           0 :     GNUNET_assert (NULL != krd.response_compressed);
    2018             :     /* If the response is actually compressed, set the
    2019             :        respective header. */
    2020           0 :     GNUNET_assert ( (MHD_YES != comp) ||
    2021             :                     (MHD_YES ==
    2022             :                      MHD_add_response_header (krd.response_compressed,
    2023             :                                               MHD_HTTP_HEADER_CONTENT_ENCODING,
    2024             :                                               "deflate")) );
    2025           0 :     GNUNET_assert (GNUNET_OK ==
    2026             :                    setup_general_response_headers (ksh,
    2027             :                                                    krd.response_compressed));
    2028           0 :     GNUNET_break (MHD_YES ==
    2029             :                   MHD_add_response_header (krd.response_compressed,
    2030             :                                            MHD_HTTP_HEADER_ETAG,
    2031             :                                            etag));
    2032           0 :     krd.etag = GNUNET_strdup (etag);
    2033             :   }
    2034           0 :   krd.cherry_pick_date = last_cpd;
    2035           0 :   GNUNET_array_append (ksh->krd_array,
    2036             :                        ksh->krd_array_length,
    2037             :                        krd);
    2038           0 :   return GNUNET_OK;
    2039             : }
    2040             : 
    2041             : 
    2042             : /**
    2043             :  * Update the "/keys" responses in @a ksh, computing the detailed replies.
    2044             :  *
    2045             :  * This function is to recompute all (including cherry-picked) responses we
    2046             :  * might want to return, based on the state already in @a ksh.
    2047             :  *
    2048             :  * @param[in,out] ksh state handle to update
    2049             :  * @return #GNUNET_OK on success
    2050             :  */
    2051             : static enum GNUNET_GenericReturnValue
    2052           0 : finish_keys_response (struct TEH_KeyStateHandle *ksh)
    2053             : {
    2054             :   json_t *recoup;
    2055             :   struct SignKeyCtx sctx;
    2056           0 :   json_t *denoms = NULL;
    2057           0 :   json_t *grouped_denominations = NULL;
    2058             :   struct GNUNET_TIME_Timestamp last_cpd;
    2059             :   struct GNUNET_CONTAINER_Heap *heap;
    2060           0 :   struct GNUNET_HashContext *hash_context = NULL;
    2061           0 :   struct GNUNET_HashCode grouped_hash_xor = {0};
    2062             : 
    2063           0 :   sctx.signkeys = json_array ();
    2064           0 :   GNUNET_assert (NULL != sctx.signkeys);
    2065           0 :   sctx.min_sk_frequency = GNUNET_TIME_UNIT_FOREVER_REL;
    2066           0 :   GNUNET_CONTAINER_multipeermap_iterate (ksh->signkey_map,
    2067             :                                          &add_sign_key_cb,
    2068             :                                          &sctx);
    2069           0 :   recoup = json_array ();
    2070           0 :   GNUNET_assert (NULL != recoup);
    2071           0 :   heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX);
    2072             :   {
    2073           0 :     struct DenomKeyCtx dkc = {
    2074             :       .recoup = recoup,
    2075             :       .heap = heap,
    2076             :       .min_dk_frequency = GNUNET_TIME_UNIT_FOREVER_REL,
    2077             :     };
    2078             : 
    2079           0 :     GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
    2080             :                                            &add_denom_key_cb,
    2081             :                                            &dkc);
    2082             :     ksh->rekey_frequency
    2083           0 :       = GNUNET_TIME_relative_min (dkc.min_dk_frequency,
    2084             :                                   sctx.min_sk_frequency);
    2085             :   }
    2086             : 
    2087           0 :   denoms = json_array ();
    2088           0 :   GNUNET_assert (NULL != denoms);
    2089           0 :   hash_context = GNUNET_CRYPTO_hash_context_start ();
    2090             : 
    2091           0 :   grouped_denominations = json_array ();
    2092           0 :   GNUNET_assert (NULL != grouped_denominations);
    2093             : 
    2094           0 :   last_cpd = GNUNET_TIME_UNIT_ZERO_TS;
    2095             : 
    2096             :   // FIXME: This block contains the implementation of the DEPRECATED
    2097             :   // "denom_pubs" array along with the new grouped "denominations".
    2098             :   // "denom_pubs" Will be removed sooner or later.
    2099             :   {
    2100             :     struct TEH_DenominationKey *dk;
    2101             :     struct GNUNET_CONTAINER_MultiHashMap *denominations_by_group;
    2102             :     /* groupData is the value we store for each group meta-data */
    2103             :     struct groupData
    2104             :     {
    2105             :       /**
    2106             :        * The json blob with the group meta-data and list of denominations
    2107             :        */
    2108             :       json_t *json;
    2109             : 
    2110             :       /**
    2111             :        * xor of all hashes of denominations in that group
    2112             :        */
    2113             :       struct GNUNET_HashCode hash_xor;
    2114             :     };
    2115             : 
    2116             :     denominations_by_group =
    2117           0 :       GNUNET_CONTAINER_multihashmap_create (1024,
    2118             :                                             GNUNET_NO /* NO, because keys are only on the stack */);
    2119             : 
    2120             : 
    2121             :     /* heap = min heap, sorted by start time */
    2122           0 :     while (NULL != (dk = GNUNET_CONTAINER_heap_remove_root (heap)))
    2123             :     {
    2124           0 :       if (GNUNET_TIME_timestamp_cmp (last_cpd,
    2125             :                                      !=,
    2126           0 :                                      dk->meta.start) &&
    2127           0 :           (! GNUNET_TIME_absolute_is_zero (last_cpd.abs_time)) )
    2128             :       {
    2129             :         /*
    2130             :          * This is not the first entry in the heap (because last_cpd !=
    2131             :          * GNUNET_TIME_UNIT_ZERO_TS) and the previous entry had a different
    2132             :          * start time.  Therefore, we create a new entry in ksh.
    2133             :          */
    2134             :         struct GNUNET_HashCode hc;
    2135             : 
    2136           0 :         GNUNET_CRYPTO_hash_context_finish (
    2137             :           GNUNET_CRYPTO_hash_context_copy (hash_context),
    2138             :           &hc);
    2139             : 
    2140           0 :         if (GNUNET_OK !=
    2141           0 :             create_krd (ksh,
    2142             :                         &hc,
    2143             :                         last_cpd,
    2144             :                         sctx.signkeys,
    2145             :                         recoup,
    2146             :                         denoms,
    2147             :                         grouped_denominations,
    2148             :                         &grouped_hash_xor))
    2149             :         {
    2150           0 :           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    2151             :                       "Failed to generate key response data for %s\n",
    2152             :                       GNUNET_TIME_timestamp2s (last_cpd));
    2153           0 :           GNUNET_CRYPTO_hash_context_abort (hash_context);
    2154             :           /* drain heap before destroying it */
    2155           0 :           while (NULL != (dk = GNUNET_CONTAINER_heap_remove_root (heap)))
    2156             :             /* intentionally empty */;
    2157           0 :           GNUNET_CONTAINER_heap_destroy (heap);
    2158           0 :           json_decref (denoms);
    2159           0 :           json_decref (grouped_denominations);
    2160           0 :           json_decref (sctx.signkeys);
    2161           0 :           json_decref (recoup);
    2162           0 :           return GNUNET_SYSERR;
    2163             :         }
    2164             :       }
    2165             : 
    2166           0 :       last_cpd = dk->meta.start;
    2167             : 
    2168             :       {
    2169             :         json_t *denom;
    2170             : 
    2171             :         denom =
    2172           0 :           GNUNET_JSON_PACK (
    2173             :             GNUNET_JSON_pack_data_auto ("master_sig",
    2174             :                                         &dk->master_sig),
    2175             :             GNUNET_JSON_pack_timestamp ("stamp_start",
    2176             :                                         dk->meta.start),
    2177             :             GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
    2178             :                                         dk->meta.expire_withdraw),
    2179             :             GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
    2180             :                                         dk->meta.expire_deposit),
    2181             :             GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
    2182             :                                         dk->meta.expire_legal),
    2183             :             TALER_JSON_pack_denom_pub ("denom_pub",
    2184             :                                        &dk->denom_pub),
    2185             :             TALER_JSON_pack_amount ("value",
    2186             :                                     &dk->meta.value),
    2187             :             TALER_JSON_PACK_DENOM_FEES ("fee",
    2188             :                                         &dk->meta.fees));
    2189             : 
    2190           0 :         GNUNET_CRYPTO_hash_context_read (hash_context,
    2191           0 :                                          &dk->h_denom_pub,
    2192             :                                          sizeof (struct GNUNET_HashCode));
    2193             : 
    2194           0 :         GNUNET_assert (
    2195             :           0 ==
    2196             :           json_array_append_new (
    2197             :             denoms,
    2198             :             denom));
    2199             : 
    2200             :       }
    2201             : 
    2202             :       /*
    2203             :        * Group the denominations by {cipher, value, fees, age_mask}.
    2204             :        *
    2205             :        * For each group we save the group meta-data and the list of
    2206             :        * denominations in this group as a json-blob in the multihashmap
    2207             :        * denominations_by_group.
    2208             :        */
    2209             :       {
    2210             :         static const char *denoms_key = "denoms";
    2211             :         struct groupData *group;
    2212             :         json_t *list;
    2213             :         json_t *entry;
    2214             :         struct GNUNET_HashCode key;
    2215           0 :         struct TALER_DenominationGroup meta = {
    2216           0 :           .cipher = dk->denom_pub.cipher,
    2217             :           .value = dk->meta.value,
    2218             :           .fees = dk->meta.fees,
    2219             :           .age_mask = dk->meta.age_mask,
    2220             :         };
    2221             : 
    2222           0 :         memset (&meta.hash, 0, sizeof(meta.hash));
    2223             : 
    2224             :         /* Search the group/JSON-blob for the key */
    2225           0 :         GNUNET_CRYPTO_hash (&meta, sizeof(meta), &key);
    2226             : 
    2227             :         group =
    2228           0 :           (struct groupData *) GNUNET_CONTAINER_multihashmap_get (
    2229             :             denominations_by_group,
    2230             :             &key);
    2231             : 
    2232           0 :         if (NULL == group)
    2233             :         {
    2234             :           /* There is no group for this meta-data yet, so we create a new group */
    2235           0 :           bool age_restricted = meta.age_mask.bits != 0;
    2236             :           char *cipher;
    2237             : 
    2238           0 :           group = GNUNET_new (struct groupData);
    2239           0 :           memset (group, 0, sizeof(*group));
    2240             : 
    2241           0 :           switch (meta.cipher)
    2242             :           {
    2243           0 :           case TALER_DENOMINATION_RSA:
    2244           0 :             cipher = age_restricted ? "RSA+age_restricted" : "RSA";
    2245           0 :             break;
    2246           0 :           case TALER_DENOMINATION_CS:
    2247           0 :             cipher = age_restricted ? "CS+age_restricted" : "CS";
    2248           0 :             break;
    2249           0 :           default:
    2250           0 :             GNUNET_assert (false);
    2251             :           }
    2252             : 
    2253           0 :           group->json = GNUNET_JSON_PACK (
    2254             :             GNUNET_JSON_pack_string ("cipher", cipher),
    2255             :             TALER_JSON_PACK_DENOM_FEES ("fee", &meta.fees),
    2256             :             TALER_JSON_pack_amount ("value", &meta.value));
    2257           0 :           GNUNET_assert (NULL != group->json);
    2258             : 
    2259           0 :           if (age_restricted)
    2260             :           {
    2261           0 :             int r = json_object_set (group->json,
    2262             :                                      "age_mask",
    2263           0 :                                      json_integer (meta.age_mask.bits));
    2264           0 :             GNUNET_assert (0 == r);
    2265             :           }
    2266             : 
    2267             :           /* Create a new array for the denominations in this group */
    2268           0 :           list = json_array ();
    2269           0 :           GNUNET_assert (NULL != list);
    2270           0 :           GNUNET_assert (0 ==
    2271             :                          json_object_set (group->json, denoms_key, list));
    2272             : 
    2273           0 :           GNUNET_assert (
    2274             :             GNUNET_OK ==
    2275             :             GNUNET_CONTAINER_multihashmap_put (denominations_by_group,
    2276             :                                                &key,
    2277             :                                                group,
    2278             :                                                GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    2279             :         }
    2280             : 
    2281             :         /* Now that we have found/created the right group, add the
    2282             :            denomination to the list */
    2283             :         {
    2284             :           struct GNUNET_JSON_PackSpec key_spec;
    2285             : 
    2286           0 :           switch (meta.cipher)
    2287             :           {
    2288           0 :           case TALER_DENOMINATION_RSA:
    2289             :             key_spec =
    2290           0 :               GNUNET_JSON_pack_rsa_public_key ("rsa_pub",
    2291           0 :                                                dk->denom_pub.details.
    2292             :                                                rsa_public_key);
    2293           0 :             break;
    2294           0 :           case TALER_DENOMINATION_CS:
    2295             :             key_spec =
    2296           0 :               GNUNET_JSON_pack_data_varsize ("cs_pub",
    2297           0 :                                              &dk->denom_pub.details.
    2298             :                                              cs_public_key,
    2299             :                                              sizeof (dk->denom_pub.details.
    2300             :                                                      cs_public_key));
    2301           0 :             break;
    2302           0 :           default:
    2303           0 :             GNUNET_assert (false);
    2304             :           }
    2305             : 
    2306           0 :           entry = GNUNET_JSON_PACK (
    2307             :             GNUNET_JSON_pack_data_auto ("master_sig",
    2308             :                                         &dk->master_sig),
    2309             :             GNUNET_JSON_pack_timestamp ("stamp_start",
    2310             :                                         dk->meta.start),
    2311             :             GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
    2312             :                                         dk->meta.expire_withdraw),
    2313             :             GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
    2314             :                                         dk->meta.expire_deposit),
    2315             :             GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
    2316             :                                         dk->meta.expire_legal),
    2317             :             key_spec
    2318             :             );
    2319           0 :           GNUNET_assert (NULL != entry);
    2320             :         }
    2321             : 
    2322             :         /* Build up the running xor of all hashes of the denominations in this
    2323             :            group */
    2324           0 :         GNUNET_CRYPTO_hash_xor (&dk->h_denom_pub.hash,
    2325           0 :                                 &group->hash_xor,
    2326             :                                 &group->hash_xor);
    2327             : 
    2328             :         /* Finally, add the denomination to the list of denominations in this
    2329             :            group */
    2330           0 :         list = json_object_get (group->json, denoms_key);
    2331           0 :         GNUNET_assert (NULL != list);
    2332           0 :         GNUNET_assert (true == json_is_array (list));
    2333           0 :         GNUNET_assert (0 ==
    2334             :                        json_array_append_new (list, entry));
    2335             :       }
    2336             :     } /* loop over heap ends */
    2337             : 
    2338             :     /* Create the JSON-array of grouped denominations */
    2339           0 :     if (0 <
    2340           0 :         GNUNET_CONTAINER_multihashmap_size (denominations_by_group))
    2341             :     {
    2342             :       struct GNUNET_CONTAINER_MultiHashMapIterator *iter;
    2343           0 :       struct groupData *group = NULL;
    2344             : 
    2345             :       iter =
    2346           0 :         GNUNET_CONTAINER_multihashmap_iterator_create (denominations_by_group);
    2347             : 
    2348           0 :       while (GNUNET_OK ==
    2349           0 :              GNUNET_CONTAINER_multihashmap_iterator_next (iter,
    2350             :                                                           NULL,
    2351             :                                                           (const
    2352             :                                                            void **) &group))
    2353             :       {
    2354             :         /* Add the XOR over all hashes of denominations in this group to the group */
    2355           0 :         GNUNET_assert (0 ==
    2356             :                        json_object_set (
    2357             :                          group->json,
    2358             :                          "hash",
    2359             :                          GNUNET_JSON_PACK (
    2360             :                            GNUNET_JSON_pack_data_auto (NULL,
    2361             :                                                        &group->hash_xor))));
    2362             : 
    2363             :         /* Add this group to the array */
    2364           0 :         GNUNET_assert (0 ==
    2365             :                        json_array_append_new (
    2366             :                          grouped_denominations,
    2367             :                          group->json));
    2368             : 
    2369             :         /* Build the running XOR over all hash(_xor) */
    2370           0 :         GNUNET_CRYPTO_hash_xor (&group->hash_xor,
    2371             :                                 &grouped_hash_xor,
    2372             :                                 &grouped_hash_xor);
    2373             : 
    2374           0 :         GNUNET_free (group);
    2375             :       }
    2376             : 
    2377           0 :       GNUNET_CONTAINER_multihashmap_iterator_destroy (iter);
    2378           0 :       GNUNET_CONTAINER_multihashmap_destroy (denominations_by_group);
    2379             : 
    2380             :     }
    2381             :   }
    2382             : 
    2383           0 :   GNUNET_CONTAINER_heap_destroy (heap);
    2384           0 :   if (! GNUNET_TIME_absolute_is_zero (last_cpd.abs_time))
    2385             :   {
    2386             :     struct GNUNET_HashCode hc;
    2387             : 
    2388           0 :     GNUNET_CRYPTO_hash_context_finish (hash_context,
    2389             :                                        &hc);
    2390           0 :     if (GNUNET_OK !=
    2391           0 :         create_krd (ksh,
    2392             :                     &hc,
    2393             :                     last_cpd,
    2394             :                     sctx.signkeys,
    2395             :                     recoup,
    2396             :                     denoms,
    2397             :                     grouped_denominations,
    2398             :                     &grouped_hash_xor))
    2399             :     {
    2400           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    2401             :                   "Failed to generate key response data for %s\n",
    2402             :                   GNUNET_TIME_timestamp2s (last_cpd));
    2403           0 :       json_decref (denoms);
    2404           0 :       json_decref (sctx.signkeys);
    2405           0 :       json_decref (recoup);
    2406           0 :       return GNUNET_SYSERR;
    2407             :     }
    2408           0 :     ksh->management_only = false;
    2409             :   }
    2410             :   else
    2411             :   {
    2412           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    2413             :                 "No denomination keys available. Refusing to generate /keys response.\n");
    2414           0 :     GNUNET_CRYPTO_hash_context_abort (hash_context);
    2415             :   }
    2416           0 :   json_decref (sctx.signkeys);
    2417           0 :   json_decref (recoup);
    2418           0 :   json_decref (denoms);
    2419           0 :   return GNUNET_OK;
    2420             : }
    2421             : 
    2422             : 
    2423             : /**
    2424             :  * Called with information about global fees.
    2425             :  *
    2426             :  * @param cls `struct TEH_KeyStateHandle *` we are building
    2427             :  * @param fees the global fees we charge
    2428             :  * @param purse_timeout when do purses time out
    2429             :  * @param kyc_timeout when do reserves without KYC time out
    2430             :  * @param history_expiration how long are account histories preserved
    2431             :  * @param purse_account_limit how many purses are free per account
    2432             :  * @param start_date from when are these fees valid (start date)
    2433             :  * @param end_date until when are these fees valid (end date, exclusive)
    2434             :  * @param master_sig master key signature affirming that this is the correct
    2435             :  *                   fee (of purpose #TALER_SIGNATURE_MASTER_GLOBAL_FEES)
    2436             :  */
    2437             : static void
    2438           0 : global_fee_info_cb (
    2439             :   void *cls,
    2440             :   const struct TALER_GlobalFeeSet *fees,
    2441             :   struct GNUNET_TIME_Relative purse_timeout,
    2442             :   struct GNUNET_TIME_Relative kyc_timeout,
    2443             :   struct GNUNET_TIME_Relative history_expiration,
    2444             :   uint32_t purse_account_limit,
    2445             :   struct GNUNET_TIME_Timestamp start_date,
    2446             :   struct GNUNET_TIME_Timestamp end_date,
    2447             :   const struct TALER_MasterSignatureP *master_sig)
    2448             : {
    2449           0 :   struct TEH_KeyStateHandle *ksh = cls;
    2450             :   struct TEH_GlobalFee *gf;
    2451             : 
    2452           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2453             :               "Found global fees with %u purses\n",
    2454             :               purse_account_limit);
    2455           0 :   gf = GNUNET_new (struct TEH_GlobalFee);
    2456           0 :   gf->start_date = start_date;
    2457           0 :   gf->end_date = end_date;
    2458           0 :   gf->fees = *fees;
    2459           0 :   gf->purse_timeout = purse_timeout;
    2460           0 :   gf->kyc_timeout = kyc_timeout;
    2461           0 :   gf->history_expiration = history_expiration;
    2462           0 :   gf->purse_account_limit = purse_account_limit;
    2463           0 :   gf->master_sig = *master_sig;
    2464           0 :   GNUNET_CONTAINER_DLL_insert (ksh->gf_head,
    2465             :                                ksh->gf_tail,
    2466             :                                gf);
    2467           0 :   GNUNET_assert (
    2468             :     0 ==
    2469             :     json_array_append_new (
    2470             :       ksh->global_fees,
    2471             :       GNUNET_JSON_PACK (
    2472             :         GNUNET_JSON_pack_timestamp ("start_date",
    2473             :                                     start_date),
    2474             :         GNUNET_JSON_pack_timestamp ("end_date",
    2475             :                                     end_date),
    2476             :         TALER_JSON_PACK_GLOBAL_FEES (fees),
    2477             :         GNUNET_JSON_pack_time_rel ("history_expiration",
    2478             :                                    history_expiration),
    2479             :         GNUNET_JSON_pack_time_rel ("account_kyc_timeout",
    2480             :                                    kyc_timeout),
    2481             :         GNUNET_JSON_pack_time_rel ("purse_timeout",
    2482             :                                    purse_timeout),
    2483             :         GNUNET_JSON_pack_uint64 ("purse_account_limit",
    2484             :                                  purse_account_limit),
    2485             :         GNUNET_JSON_pack_data_auto ("master_sig",
    2486             :                                     master_sig))));
    2487           0 : }
    2488             : 
    2489             : 
    2490             : /**
    2491             :  * Create a key state.
    2492             :  *
    2493             :  * @param[in] hs helper state to (re)use, NULL if not available
    2494             :  * @param management_only if we should NOT run 'finish_keys_response()'
    2495             :  *                  because we only need the state for the /management/keys API
    2496             :  * @return NULL on error (i.e. failed to access database)
    2497             :  */
    2498             : static struct TEH_KeyStateHandle *
    2499           0 : build_key_state (struct HelperState *hs,
    2500             :                  bool management_only)
    2501             : {
    2502             :   struct TEH_KeyStateHandle *ksh;
    2503             :   enum GNUNET_DB_QueryStatus qs;
    2504             : 
    2505           0 :   ksh = GNUNET_new (struct TEH_KeyStateHandle);
    2506           0 :   ksh->signature_expires = GNUNET_TIME_UNIT_FOREVER_TS;
    2507           0 :   ksh->reload_time = GNUNET_TIME_timestamp_get ();
    2508             :   /* We must use the key_generation from when we STARTED the process! */
    2509           0 :   ksh->key_generation = key_generation;
    2510           0 :   if (NULL == hs)
    2511             :   {
    2512           0 :     ksh->helpers = GNUNET_new (struct HelperState);
    2513           0 :     if (GNUNET_OK !=
    2514           0 :         setup_key_helpers (ksh->helpers))
    2515             :     {
    2516           0 :       GNUNET_free (ksh->helpers);
    2517           0 :       GNUNET_assert (NULL == ksh->management_keys_reply);
    2518           0 :       GNUNET_free (ksh);
    2519           0 :       return NULL;
    2520             :     }
    2521             :   }
    2522             :   else
    2523             :   {
    2524           0 :     ksh->helpers = hs;
    2525             :   }
    2526           0 :   ksh->denomkey_map = GNUNET_CONTAINER_multihashmap_create (1024,
    2527             :                                                             GNUNET_YES);
    2528           0 :   ksh->signkey_map = GNUNET_CONTAINER_multipeermap_create (32,
    2529             :                                                            GNUNET_NO /* MUST be NO! */);
    2530           0 :   ksh->auditors = json_array ();
    2531           0 :   GNUNET_assert (NULL != ksh->auditors);
    2532             :   /* NOTE: fetches master-signed signkeys, but ALSO those that were revoked! */
    2533           0 :   GNUNET_break (GNUNET_OK ==
    2534             :                 TEH_plugin->preflight (TEH_plugin->cls));
    2535           0 :   if (NULL != ksh->global_fees)
    2536           0 :     json_decref (ksh->global_fees);
    2537           0 :   ksh->global_fees = json_array ();
    2538           0 :   qs = TEH_plugin->get_global_fees (TEH_plugin->cls,
    2539             :                                     &global_fee_info_cb,
    2540             :                                     ksh);
    2541           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2542             :               "Loading global fees from DB: %d\n",
    2543             :               qs);
    2544           0 :   if (qs < 0)
    2545             :   {
    2546           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
    2547           0 :     GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
    2548           0 :     destroy_key_state (ksh,
    2549             :                        true);
    2550           0 :     return NULL;
    2551             :   }
    2552           0 :   qs = TEH_plugin->iterate_denominations (TEH_plugin->cls,
    2553             :                                           &denomination_info_cb,
    2554             :                                           ksh);
    2555           0 :   if (qs < 0)
    2556             :   {
    2557           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
    2558           0 :     GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs);
    2559           0 :     destroy_key_state (ksh,
    2560             :                        true);
    2561           0 :     return NULL;
    2562             :   }
    2563             :   /* NOTE: ONLY fetches non-revoked AND master-signed signkeys! */
    2564           0 :   qs = TEH_plugin->iterate_active_signkeys (TEH_plugin->cls,
    2565             :                                             &signkey_info_cb,
    2566             :                                             ksh);
    2567           0 :   if (qs < 0)
    2568             :   {
    2569           0 :     GNUNET_break (0);
    2570           0 :     destroy_key_state (ksh,
    2571             :                        true);
    2572           0 :     return NULL;
    2573             :   }
    2574           0 :   qs = TEH_plugin->iterate_auditor_denominations (TEH_plugin->cls,
    2575             :                                                   &auditor_denom_cb,
    2576             :                                                   ksh);
    2577           0 :   if (qs < 0)
    2578             :   {
    2579           0 :     GNUNET_break (0);
    2580           0 :     destroy_key_state (ksh,
    2581             :                        true);
    2582           0 :     return NULL;
    2583             :   }
    2584           0 :   qs = TEH_plugin->iterate_active_auditors (TEH_plugin->cls,
    2585             :                                             &auditor_info_cb,
    2586             :                                             ksh);
    2587           0 :   if (qs < 0)
    2588             :   {
    2589           0 :     GNUNET_break (0);
    2590           0 :     destroy_key_state (ksh,
    2591             :                        true);
    2592           0 :     return NULL;
    2593             :   }
    2594             : 
    2595           0 :   if (management_only)
    2596             :   {
    2597           0 :     ksh->management_only = true;
    2598           0 :     return ksh;
    2599             :   }
    2600             : 
    2601           0 :   if (GNUNET_OK !=
    2602           0 :       finish_keys_response (ksh))
    2603             :   {
    2604           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    2605             :                 "Could not finish /keys response (likely no signing keys available yet)\n");
    2606           0 :     destroy_key_state (ksh,
    2607             :                        true);
    2608           0 :     return NULL;
    2609             :   }
    2610             : 
    2611           0 :   return ksh;
    2612             : }
    2613             : 
    2614             : 
    2615             : void
    2616           0 : TEH_keys_update_states ()
    2617             : {
    2618           0 :   struct GNUNET_DB_EventHeaderP es = {
    2619           0 :     .size = htons (sizeof (es)),
    2620           0 :     .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED),
    2621             :   };
    2622             : 
    2623           0 :   TEH_plugin->event_notify (TEH_plugin->cls,
    2624             :                             &es,
    2625             :                             NULL,
    2626             :                             0);
    2627           0 :   key_generation++;
    2628           0 :   TEH_resume_keys_requests (false);
    2629           0 : }
    2630             : 
    2631             : 
    2632             : struct TEH_KeyStateHandle *
    2633           0 : TEH_keys_get_state2 (bool management_only)
    2634             : {
    2635             :   struct TEH_KeyStateHandle *old_ksh;
    2636             :   struct TEH_KeyStateHandle *ksh;
    2637             : 
    2638           0 :   old_ksh = key_state;
    2639           0 :   if (NULL == old_ksh)
    2640             :   {
    2641           0 :     ksh = build_key_state (NULL,
    2642             :                            management_only);
    2643           0 :     if (NULL == ksh)
    2644           0 :       return NULL;
    2645           0 :     key_state = ksh;
    2646           0 :     return ksh;
    2647             :   }
    2648           0 :   if ( (old_ksh->key_generation < key_generation) ||
    2649           0 :        (GNUNET_TIME_absolute_is_past (old_ksh->signature_expires.abs_time)) )
    2650             :   {
    2651           0 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2652             :                 "Rebuilding /keys, generation upgrade from %llu to %llu\n",
    2653             :                 (unsigned long long) old_ksh->key_generation,
    2654             :                 (unsigned long long) key_generation);
    2655           0 :     ksh = build_key_state (old_ksh->helpers,
    2656             :                            management_only);
    2657           0 :     key_state = ksh;
    2658           0 :     old_ksh->helpers = NULL;
    2659           0 :     destroy_key_state (old_ksh,
    2660             :                        false);
    2661           0 :     return ksh;
    2662             :   }
    2663           0 :   sync_key_helpers (old_ksh->helpers);
    2664           0 :   return old_ksh;
    2665             : }
    2666             : 
    2667             : 
    2668             : struct TEH_KeyStateHandle *
    2669           0 : TEH_keys_get_state (void)
    2670             : {
    2671             :   struct TEH_KeyStateHandle *ksh;
    2672             : 
    2673           0 :   ksh = TEH_keys_get_state2 (false);
    2674           0 :   if (NULL == ksh)
    2675           0 :     return NULL;
    2676           0 :   if (ksh->management_only)
    2677             :   {
    2678           0 :     if (GNUNET_OK !=
    2679           0 :         finish_keys_response (ksh))
    2680           0 :       return NULL;
    2681             :   }
    2682           0 :   return ksh;
    2683             : }
    2684             : 
    2685             : 
    2686             : const struct TEH_GlobalFee *
    2687           0 : TEH_keys_global_fee_by_time (
    2688             :   struct TEH_KeyStateHandle *ksh,
    2689             :   struct GNUNET_TIME_Timestamp ts)
    2690             : {
    2691           0 :   for (const struct TEH_GlobalFee *gf = ksh->gf_head;
    2692             :        NULL != gf;
    2693           0 :        gf = gf->next)
    2694             :   {
    2695           0 :     if (GNUNET_TIME_timestamp_cmp (ts,
    2696             :                                    >=,
    2697           0 :                                    gf->start_date) &&
    2698           0 :         GNUNET_TIME_timestamp_cmp (ts,
    2699             :                                    <,
    2700             :                                    gf->end_date))
    2701           0 :       return gf;
    2702             :   }
    2703           0 :   return NULL;
    2704             : }
    2705             : 
    2706             : 
    2707             : struct TEH_DenominationKey *
    2708           0 : TEH_keys_denomination_by_hash (
    2709             :   const struct TALER_DenominationHashP *h_denom_pub,
    2710             :   struct MHD_Connection *conn,
    2711             :   MHD_RESULT *mret)
    2712             : {
    2713             :   struct TEH_KeyStateHandle *ksh;
    2714             : 
    2715           0 :   ksh = TEH_keys_get_state ();
    2716           0 :   if (NULL == ksh)
    2717             :   {
    2718           0 :     *mret = TALER_MHD_reply_with_error (conn,
    2719             :                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
    2720             :                                         TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
    2721             :                                         NULL);
    2722           0 :     return NULL;
    2723             :   }
    2724           0 :   return TEH_keys_denomination_by_hash2 (ksh,
    2725             :                                          h_denom_pub,
    2726             :                                          conn,
    2727             :                                          mret);
    2728             : }
    2729             : 
    2730             : 
    2731             : struct TEH_DenominationKey *
    2732           0 : TEH_keys_denomination_by_hash2 (
    2733             :   struct TEH_KeyStateHandle *ksh,
    2734             :   const struct TALER_DenominationHashP *h_denom_pub,
    2735             :   struct MHD_Connection *conn,
    2736             :   MHD_RESULT *mret)
    2737             : {
    2738             :   struct TEH_DenominationKey *dk;
    2739             : 
    2740           0 :   dk = GNUNET_CONTAINER_multihashmap_get (ksh->denomkey_map,
    2741             :                                           &h_denom_pub->hash);
    2742           0 :   if (NULL == dk)
    2743             :   {
    2744           0 :     if (NULL == conn)
    2745           0 :       return NULL;
    2746           0 :     *mret = TEH_RESPONSE_reply_unknown_denom_pub_hash (conn,
    2747             :                                                        h_denom_pub);
    2748           0 :     return NULL;
    2749             :   }
    2750           0 :   return dk;
    2751             : }
    2752             : 
    2753             : 
    2754             : enum TALER_ErrorCode
    2755           0 : TEH_keys_denomination_sign_withdraw (
    2756             :   const struct TALER_DenominationHashP *h_denom_pub,
    2757             :   const struct TALER_BlindedPlanchet *bp,
    2758             :   struct TALER_BlindedDenominationSignature *bs)
    2759             : {
    2760             :   struct TEH_KeyStateHandle *ksh;
    2761             :   struct HelperDenomination *hd;
    2762             : 
    2763           0 :   ksh = TEH_keys_get_state ();
    2764           0 :   if (NULL == ksh)
    2765           0 :     return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
    2766           0 :   hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
    2767             :                                           &h_denom_pub->hash);
    2768           0 :   if (NULL == hd)
    2769           0 :     return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
    2770           0 :   if (bp->cipher != hd->denom_pub.cipher)
    2771           0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    2772           0 :   switch (hd->denom_pub.cipher)
    2773             :   {
    2774           0 :   case TALER_DENOMINATION_RSA:
    2775           0 :     TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_RSA]++;
    2776             :     {
    2777           0 :       struct TALER_CRYPTO_RsaSignRequest rsr = {
    2778           0 :         .h_rsa = &hd->h_details.h_rsa,
    2779           0 :         .msg = bp->details.rsa_blinded_planchet.blinded_msg,
    2780           0 :         .msg_size = bp->details.rsa_blinded_planchet.blinded_msg_size
    2781             :       };
    2782             : 
    2783           0 :       return TALER_CRYPTO_helper_rsa_sign (
    2784           0 :         ksh->helpers->rsadh,
    2785             :         &rsr,
    2786             :         bs);
    2787             :     }
    2788           0 :   case TALER_DENOMINATION_CS:
    2789           0 :     TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_CS]++;
    2790           0 :     return TALER_CRYPTO_helper_cs_sign_withdraw (
    2791           0 :       ksh->helpers->csdh,
    2792           0 :       &hd->h_details.h_cs,
    2793             :       &bp->details.cs_blinded_planchet,
    2794             :       bs);
    2795           0 :   default:
    2796           0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    2797             :   }
    2798             : }
    2799             : 
    2800             : 
    2801             : enum TALER_ErrorCode
    2802           0 : TEH_keys_denomination_sign_melt (
    2803             :   const struct TALER_DenominationHashP *h_denom_pub,
    2804             :   const struct TALER_BlindedPlanchet *bp,
    2805             :   struct TALER_BlindedDenominationSignature *bs)
    2806             : {
    2807             :   struct TEH_KeyStateHandle *ksh;
    2808             :   struct HelperDenomination *hd;
    2809             : 
    2810           0 :   ksh = TEH_keys_get_state ();
    2811           0 :   if (NULL == ksh)
    2812           0 :     return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
    2813           0 :   hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
    2814             :                                           &h_denom_pub->hash);
    2815           0 :   if (NULL == hd)
    2816           0 :     return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
    2817           0 :   if (bp->cipher != hd->denom_pub.cipher)
    2818           0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    2819           0 :   switch (hd->denom_pub.cipher)
    2820             :   {
    2821           0 :   case TALER_DENOMINATION_RSA:
    2822           0 :     TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_RSA]++;
    2823             :     {
    2824           0 :       struct TALER_CRYPTO_RsaSignRequest rsr = {
    2825           0 :         .h_rsa = &hd->h_details.h_rsa,
    2826           0 :         .msg = bp->details.rsa_blinded_planchet.blinded_msg,
    2827           0 :         .msg_size = bp->details.rsa_blinded_planchet.blinded_msg_size
    2828             :       };
    2829             : 
    2830           0 :       return TALER_CRYPTO_helper_rsa_sign (
    2831           0 :         ksh->helpers->rsadh,
    2832             :         &rsr,
    2833             :         bs);
    2834             :     }
    2835           0 :   case TALER_DENOMINATION_CS:
    2836           0 :     TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_CS]++;
    2837           0 :     return TALER_CRYPTO_helper_cs_sign_melt (
    2838           0 :       ksh->helpers->csdh,
    2839           0 :       &hd->h_details.h_cs,
    2840             :       &bp->details.cs_blinded_planchet,
    2841             :       bs);
    2842           0 :   default:
    2843           0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    2844             :   }
    2845             : }
    2846             : 
    2847             : 
    2848             : enum TALER_ErrorCode
    2849           0 : TEH_keys_denomination_cs_r_pub_melt (
    2850             :   const struct TALER_DenominationHashP *h_denom_pub,
    2851             :   const struct TALER_CsNonce *nonce,
    2852             :   struct TALER_DenominationCSPublicRPairP *r_pub)
    2853             : {
    2854             :   struct TEH_KeyStateHandle *ksh;
    2855             :   struct HelperDenomination *hd;
    2856             : 
    2857           0 :   ksh = TEH_keys_get_state ();
    2858           0 :   if (NULL == ksh)
    2859             :   {
    2860           0 :     return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
    2861             :   }
    2862           0 :   hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
    2863             :                                           &h_denom_pub->hash);
    2864           0 :   if (NULL == hd)
    2865             :   {
    2866           0 :     return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
    2867             :   }
    2868           0 :   if (TALER_DENOMINATION_CS != hd->denom_pub.cipher)
    2869             :   {
    2870           0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    2871             :   }
    2872             : 
    2873           0 :   return TALER_CRYPTO_helper_cs_r_derive_melt (ksh->helpers->csdh,
    2874           0 :                                                &hd->h_details.h_cs,
    2875             :                                                nonce,
    2876             :                                                r_pub);
    2877             : }
    2878             : 
    2879             : 
    2880             : enum TALER_ErrorCode
    2881           0 : TEH_keys_denomination_cs_r_pub_withdraw (
    2882             :   const struct TALER_DenominationHashP *h_denom_pub,
    2883             :   const struct TALER_CsNonce *nonce,
    2884             :   struct TALER_DenominationCSPublicRPairP *r_pub)
    2885             : {
    2886             :   struct TEH_KeyStateHandle *ksh;
    2887             :   struct HelperDenomination *hd;
    2888             : 
    2889           0 :   ksh = TEH_keys_get_state ();
    2890           0 :   if (NULL == ksh)
    2891             :   {
    2892           0 :     return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
    2893             :   }
    2894           0 :   hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
    2895             :                                           &h_denom_pub->hash);
    2896           0 :   if (NULL == hd)
    2897             :   {
    2898           0 :     return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
    2899             :   }
    2900           0 :   if (TALER_DENOMINATION_CS != hd->denom_pub.cipher)
    2901             :   {
    2902           0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    2903             :   }
    2904             : 
    2905           0 :   return TALER_CRYPTO_helper_cs_r_derive_withdraw (ksh->helpers->csdh,
    2906           0 :                                                    &hd->h_details.h_cs,
    2907             :                                                    nonce,
    2908             :                                                    r_pub);
    2909             : }
    2910             : 
    2911             : 
    2912             : void
    2913           0 : TEH_keys_denomination_revoke (const struct TALER_DenominationHashP *h_denom_pub)
    2914             : {
    2915             :   struct TEH_KeyStateHandle *ksh;
    2916             :   struct HelperDenomination *hd;
    2917             : 
    2918           0 :   ksh = TEH_keys_get_state ();
    2919           0 :   if (NULL == ksh)
    2920             :   {
    2921           0 :     GNUNET_break (0);
    2922           0 :     return;
    2923             :   }
    2924           0 :   hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
    2925             :                                           &h_denom_pub->hash);
    2926           0 :   if (NULL == hd)
    2927             :   {
    2928           0 :     GNUNET_break (0);
    2929           0 :     return;
    2930             :   }
    2931           0 :   switch (hd->denom_pub.cipher)
    2932             :   {
    2933           0 :   case TALER_DENOMINATION_RSA:
    2934           0 :     TALER_CRYPTO_helper_rsa_revoke (ksh->helpers->rsadh,
    2935           0 :                                     &hd->h_details.h_rsa);
    2936           0 :     TEH_keys_update_states ();
    2937           0 :     return;
    2938           0 :   case TALER_DENOMINATION_CS:
    2939           0 :     TALER_CRYPTO_helper_cs_revoke (ksh->helpers->csdh,
    2940           0 :                                    &hd->h_details.h_cs);
    2941           0 :     TEH_keys_update_states ();
    2942           0 :     return;
    2943           0 :   default:
    2944           0 :     GNUNET_break (0);
    2945           0 :     return;
    2946             :   }
    2947             : }
    2948             : 
    2949             : 
    2950             : enum TALER_ErrorCode
    2951           0 : TEH_keys_exchange_sign_ (
    2952             :   const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
    2953             :   struct TALER_ExchangePublicKeyP *pub,
    2954             :   struct TALER_ExchangeSignatureP *sig)
    2955             : {
    2956             :   struct TEH_KeyStateHandle *ksh;
    2957             : 
    2958           0 :   ksh = TEH_keys_get_state ();
    2959           0 :   if (NULL == ksh)
    2960             :   {
    2961             :     /* This *can* happen if the exchange's crypto helper is not running
    2962             :        or had some bad error. */
    2963           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2964             :                 "Cannot sign request, no valid signing keys available.\n");
    2965           0 :     return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
    2966             :   }
    2967           0 :   return TEH_keys_exchange_sign2_ (ksh,
    2968             :                                    purpose,
    2969             :                                    pub,
    2970             :                                    sig);
    2971             : }
    2972             : 
    2973             : 
    2974             : enum TALER_ErrorCode
    2975           0 : TEH_keys_exchange_sign2_ (
    2976             :   void *cls,
    2977             :   const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
    2978             :   struct TALER_ExchangePublicKeyP *pub,
    2979             :   struct TALER_ExchangeSignatureP *sig)
    2980             : {
    2981           0 :   struct TEH_KeyStateHandle *ksh = cls;
    2982             :   enum TALER_ErrorCode ec;
    2983             : 
    2984           0 :   TEH_METRICS_num_signatures[TEH_MT_SIGNATURE_EDDSA]++;
    2985           0 :   ec = TALER_CRYPTO_helper_esign_sign_ (ksh->helpers->esh,
    2986             :                                         purpose,
    2987             :                                         pub,
    2988             :                                         sig);
    2989           0 :   if (TALER_EC_NONE != ec)
    2990           0 :     return ec;
    2991             :   {
    2992             :     /* Here we check here that 'pub' is set to an exchange public key that is
    2993             :        actually signed by the master key! Otherwise, we happily continue to
    2994             :        use key material even if the offline signatures have not been made
    2995             :        yet! */
    2996             :     struct GNUNET_PeerIdentity pid;
    2997             :     struct SigningKey *sk;
    2998             : 
    2999           0 :     pid.public_key = pub->eddsa_pub;
    3000           0 :     sk = GNUNET_CONTAINER_multipeermap_get (ksh->signkey_map,
    3001             :                                             &pid);
    3002           0 :     if (NULL == sk)
    3003             :     {
    3004             :       /* just to be safe, zero out the (valid) signature, as the key
    3005             :          should not or no longer be used */
    3006           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    3007             :                   "Cannot sign, offline key signatures are missing!\n");
    3008           0 :       memset (sig,
    3009             :               0,
    3010             :               sizeof (*sig));
    3011           0 :       return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    3012             :     }
    3013             :   }
    3014           0 :   return ec;
    3015             : }
    3016             : 
    3017             : 
    3018             : void
    3019           0 : TEH_keys_exchange_revoke (const struct TALER_ExchangePublicKeyP *exchange_pub)
    3020             : {
    3021             :   struct TEH_KeyStateHandle *ksh;
    3022             : 
    3023           0 :   ksh = TEH_keys_get_state ();
    3024           0 :   if (NULL == ksh)
    3025             :   {
    3026           0 :     GNUNET_break (0);
    3027           0 :     return;
    3028             :   }
    3029           0 :   TALER_CRYPTO_helper_esign_revoke (ksh->helpers->esh,
    3030             :                                     exchange_pub);
    3031           0 :   TEH_keys_update_states ();
    3032             : }
    3033             : 
    3034             : 
    3035             : /**
    3036             :  * Comparator used for a binary search by cherry_pick_date for @a key in the
    3037             :  * `struct KeysResponseData` array. See libc's qsort() and bsearch() functions.
    3038             :  *
    3039             :  * @param key pointer to a `struct GNUNET_TIME_Timestamp`
    3040             :  * @param value pointer to a `struct KeysResponseData` array entry
    3041             :  * @return 0 if time matches, -1 if key is smaller, 1 if key is larger
    3042             :  */
    3043             : static int
    3044           0 : krd_search_comparator (const void *key,
    3045             :                        const void *value)
    3046             : {
    3047           0 :   const struct GNUNET_TIME_Timestamp *kd = key;
    3048           0 :   const struct KeysResponseData *krd = value;
    3049             : 
    3050           0 :   if (GNUNET_TIME_timestamp_cmp (*kd,
    3051             :                                  >,
    3052             :                                  krd->cherry_pick_date))
    3053           0 :     return -1;
    3054           0 :   if (GNUNET_TIME_timestamp_cmp (*kd,
    3055             :                                  <,
    3056             :                                  krd->cherry_pick_date))
    3057           0 :     return 1;
    3058           0 :   return 0;
    3059             : }
    3060             : 
    3061             : 
    3062             : MHD_RESULT
    3063           0 : TEH_keys_get_handler (struct TEH_RequestContext *rc,
    3064             :                       const char *const args[])
    3065             : {
    3066             :   struct GNUNET_TIME_Timestamp last_issue_date;
    3067             :   const char *etag;
    3068             : 
    3069           0 :   etag = MHD_lookup_connection_value (rc->connection,
    3070             :                                       MHD_HEADER_KIND,
    3071             :                                       MHD_HTTP_HEADER_IF_NONE_MATCH);
    3072             :   (void) args;
    3073             :   {
    3074             :     const char *have_cherrypick;
    3075             : 
    3076           0 :     have_cherrypick = MHD_lookup_connection_value (rc->connection,
    3077             :                                                    MHD_GET_ARGUMENT_KIND,
    3078             :                                                    "last_issue_date");
    3079           0 :     if (NULL != have_cherrypick)
    3080             :     {
    3081             :       unsigned long long cherrypickn;
    3082             : 
    3083           0 :       if (1 !=
    3084           0 :           sscanf (have_cherrypick,
    3085             :                   "%llu",
    3086             :                   &cherrypickn))
    3087             :       {
    3088           0 :         GNUNET_break_op (0);
    3089           0 :         return TALER_MHD_reply_with_error (rc->connection,
    3090             :                                            MHD_HTTP_BAD_REQUEST,
    3091             :                                            TALER_EC_GENERIC_PARAMETER_MALFORMED,
    3092             :                                            have_cherrypick);
    3093             :       }
    3094             :       /* The following multiplication may overflow; but this should not really
    3095             :          be a problem, as giving back 'older' data than what the client asks for
    3096             :          (given that the client asks for data in the distant future) is not
    3097             :          problematic */
    3098           0 :       last_issue_date = GNUNET_TIME_timestamp_from_s (cherrypickn);
    3099             :     }
    3100             :     else
    3101             :     {
    3102           0 :       last_issue_date = GNUNET_TIME_UNIT_ZERO_TS;
    3103             :     }
    3104             :   }
    3105             : 
    3106             :   {
    3107             :     struct TEH_KeyStateHandle *ksh;
    3108             :     const struct KeysResponseData *krd;
    3109             : 
    3110           0 :     ksh = TEH_keys_get_state ();
    3111           0 :     if (NULL == ksh)
    3112             :     {
    3113           0 :       if ( ( (SKR_LIMIT == skr_size) &&
    3114           0 :              (rc->connection == skr_connection) ) ||
    3115             :            TEH_suicide)
    3116             :       {
    3117           0 :         return TALER_MHD_reply_with_error (
    3118             :           rc->connection,
    3119             :           MHD_HTTP_SERVICE_UNAVAILABLE,
    3120             :           TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
    3121             :           TEH_suicide
    3122           0 :           ? "server terminating"
    3123             :           : "too many connections suspended waiting on /keys");
    3124             :       }
    3125           0 :       return suspend_request (rc->connection);
    3126             :     }
    3127           0 :     krd = bsearch (&last_issue_date,
    3128           0 :                    ksh->krd_array,
    3129           0 :                    ksh->krd_array_length,
    3130             :                    sizeof (struct KeysResponseData),
    3131             :                    &krd_search_comparator);
    3132           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    3133             :                 "Filtering /keys by cherry pick date %s found entry %u/%u\n",
    3134             :                 GNUNET_TIME_timestamp2s (last_issue_date),
    3135             :                 (unsigned int) (krd - ksh->krd_array),
    3136             :                 ksh->krd_array_length);
    3137           0 :     if ( (NULL == krd) &&
    3138           0 :          (ksh->krd_array_length > 0) )
    3139             :     {
    3140           0 :       if (! GNUNET_TIME_absolute_is_zero (last_issue_date.abs_time))
    3141           0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    3142             :                     "Client provided invalid cherry picking timestamp %s, returning full response\n",
    3143             :                     GNUNET_TIME_timestamp2s (last_issue_date));
    3144           0 :       krd = &ksh->krd_array[ksh->krd_array_length - 1];
    3145             :     }
    3146           0 :     if (NULL == krd)
    3147             :     {
    3148             :       /* Likely keys not ready *yet*.
    3149             :          Wait until they are. */
    3150           0 :       return suspend_request (rc->connection);
    3151             :     }
    3152           0 :     if ( (NULL != etag) &&
    3153           0 :          (0 == strcmp (etag,
    3154           0 :                        krd->etag)) )
    3155             :     {
    3156             :       MHD_RESULT ret;
    3157             :       struct MHD_Response *resp;
    3158             : 
    3159           0 :       resp = MHD_create_response_from_buffer (0,
    3160             :                                               NULL,
    3161             :                                               MHD_RESPMEM_PERSISTENT);
    3162           0 :       TALER_MHD_add_global_headers (resp);
    3163           0 :       GNUNET_break (GNUNET_OK ==
    3164             :                     setup_general_response_headers (ksh,
    3165             :                                                     resp));
    3166           0 :       GNUNET_break (MHD_YES ==
    3167             :                     MHD_add_response_header (resp,
    3168             :                                              MHD_HTTP_HEADER_ETAG,
    3169             :                                              krd->etag));
    3170           0 :       ret = MHD_queue_response (rc->connection,
    3171             :                                 MHD_HTTP_NOT_MODIFIED,
    3172             :                                 resp);
    3173           0 :       GNUNET_break (MHD_YES == ret);
    3174           0 :       MHD_destroy_response (resp);
    3175           0 :       return ret;
    3176             :     }
    3177           0 :     return MHD_queue_response (rc->connection,
    3178             :                                MHD_HTTP_OK,
    3179             :                                (MHD_YES ==
    3180           0 :                                 TALER_MHD_can_compress (rc->connection))
    3181             :                                ? krd->response_compressed
    3182             :                                : krd->response_uncompressed);
    3183             :   }
    3184             : }
    3185             : 
    3186             : 
    3187             : /**
    3188             :  * Load extension data, like fees, expiration times (!) and age restriction
    3189             :  * flags for the denomination type configured in section @a section_name.
    3190             :  * Before calling this function, the `start` and `validity_duration` times must
    3191             :  * already be initialized in @a meta.
    3192             :  *
    3193             :  * @param section_name section in the configuration to use
    3194             :  * @param[in,out] meta denomination type data to complete
    3195             :  * @return #GNUNET_OK on success
    3196             :  */
    3197             : static enum GNUNET_GenericReturnValue
    3198           0 : load_extension_data (const char *section_name,
    3199             :                      struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta)
    3200             : {
    3201             :   struct GNUNET_TIME_Relative deposit_duration;
    3202             :   struct GNUNET_TIME_Relative legal_duration;
    3203             : 
    3204           0 :   GNUNET_assert (! GNUNET_TIME_absolute_is_zero (meta->start.abs_time)); /* caller bug */
    3205           0 :   if (GNUNET_OK !=
    3206           0 :       GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
    3207             :                                            section_name,
    3208             :                                            "DURATION_SPEND",
    3209             :                                            &deposit_duration))
    3210             :   {
    3211           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    3212             :                                section_name,
    3213             :                                "DURATION_SPEND");
    3214           0 :     return GNUNET_SYSERR;
    3215             :   }
    3216           0 :   if (GNUNET_OK !=
    3217           0 :       GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
    3218             :                                            section_name,
    3219             :                                            "DURATION_LEGAL",
    3220             :                                            &legal_duration))
    3221             :   {
    3222           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    3223             :                                section_name,
    3224             :                                "DURATION_LEGAL");
    3225           0 :     return GNUNET_SYSERR;
    3226             :   }
    3227             :   meta->expire_deposit
    3228           0 :     = GNUNET_TIME_absolute_to_timestamp (
    3229             :         GNUNET_TIME_absolute_add (meta->expire_withdraw.abs_time,
    3230             :                                   deposit_duration));
    3231           0 :   meta->expire_legal = GNUNET_TIME_absolute_to_timestamp (
    3232             :     GNUNET_TIME_absolute_add (meta->expire_deposit.abs_time,
    3233             :                               legal_duration));
    3234           0 :   if (GNUNET_OK !=
    3235           0 :       TALER_config_get_amount (TEH_cfg,
    3236             :                                section_name,
    3237             :                                "VALUE",
    3238             :                                &meta->value))
    3239             :   {
    3240           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    3241             :                                "Need amount for option `%s' in section `%s'\n",
    3242             :                                "VALUE",
    3243             :                                section_name);
    3244           0 :     return GNUNET_SYSERR;
    3245             :   }
    3246           0 :   if (0 != strcasecmp (TEH_currency,
    3247           0 :                        meta->value.currency))
    3248             :   {
    3249           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    3250             :                 "Need denomination value in section `%s' to use currency `%s'\n",
    3251             :                 section_name,
    3252             :                 TEH_currency);
    3253           0 :     return GNUNET_SYSERR;
    3254             :   }
    3255           0 :   if (GNUNET_OK !=
    3256           0 :       TALER_config_get_denom_fees (TEH_cfg,
    3257             :                                    TEH_currency,
    3258             :                                    section_name,
    3259             :                                    &meta->fees))
    3260           0 :     return GNUNET_SYSERR;
    3261           0 :   meta->age_mask = load_age_mask (section_name);
    3262           0 :   return GNUNET_OK;
    3263             : }
    3264             : 
    3265             : 
    3266             : enum GNUNET_GenericReturnValue
    3267           0 : TEH_keys_load_fees (struct TEH_KeyStateHandle *ksh,
    3268             :                     const struct TALER_DenominationHashP *h_denom_pub,
    3269             :                     struct TALER_DenominationPublicKey *denom_pub,
    3270             :                     struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta)
    3271             : {
    3272             :   struct HelperDenomination *hd;
    3273             :   enum GNUNET_GenericReturnValue ok;
    3274             : 
    3275           0 :   hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
    3276             :                                           &h_denom_pub->hash);
    3277           0 :   if (NULL == hd)
    3278             :   {
    3279           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    3280             :                 "Denomination %s not known\n",
    3281             :                 GNUNET_h2s (&h_denom_pub->hash));
    3282           0 :     return GNUNET_NO;
    3283             :   }
    3284           0 :   meta->start = hd->start_time;
    3285           0 :   meta->expire_withdraw = GNUNET_TIME_absolute_to_timestamp (
    3286             :     GNUNET_TIME_absolute_add (meta->start.abs_time,
    3287             :                               hd->validity_duration));
    3288           0 :   ok = load_extension_data (hd->section_name,
    3289             :                             meta);
    3290           0 :   if (GNUNET_OK == ok)
    3291             :   {
    3292           0 :     GNUNET_assert (TALER_DENOMINATION_INVALID != hd->denom_pub.cipher);
    3293           0 :     TALER_denom_pub_deep_copy (denom_pub,
    3294           0 :                                &hd->denom_pub);
    3295             :   }
    3296             :   else
    3297             :   {
    3298           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    3299             :                 "No fees for `%s', voiding key\n",
    3300             :                 hd->section_name);
    3301           0 :     memset (denom_pub,
    3302             :             0,
    3303             :             sizeof (*denom_pub));
    3304             :   }
    3305           0 :   return ok;
    3306             : }
    3307             : 
    3308             : 
    3309             : enum GNUNET_GenericReturnValue
    3310           0 : TEH_keys_get_timing (const struct TALER_ExchangePublicKeyP *exchange_pub,
    3311             :                      struct TALER_EXCHANGEDB_SignkeyMetaData *meta)
    3312             : {
    3313             :   struct TEH_KeyStateHandle *ksh;
    3314             :   struct HelperSignkey *hsk;
    3315             :   struct GNUNET_PeerIdentity pid;
    3316             : 
    3317           0 :   ksh = TEH_keys_get_state2 (true);
    3318           0 :   if (NULL == ksh)
    3319             :   {
    3320           0 :     GNUNET_break (0);
    3321           0 :     return GNUNET_SYSERR;
    3322             :   }
    3323             : 
    3324           0 :   pid.public_key = exchange_pub->eddsa_pub;
    3325           0 :   hsk = GNUNET_CONTAINER_multipeermap_get (ksh->helpers->esign_keys,
    3326             :                                            &pid);
    3327           0 :   meta->start = hsk->start_time;
    3328             : 
    3329           0 :   meta->expire_sign = GNUNET_TIME_absolute_to_timestamp (
    3330             :     GNUNET_TIME_absolute_add (meta->start.abs_time,
    3331             :                               hsk->validity_duration));
    3332           0 :   meta->expire_legal = GNUNET_TIME_absolute_to_timestamp (
    3333             :     GNUNET_TIME_absolute_add (meta->expire_sign.abs_time,
    3334             :                               signkey_legal_duration));
    3335           0 :   return GNUNET_OK;
    3336             : }
    3337             : 
    3338             : 
    3339             : /**
    3340             :  * Closure for #add_future_denomkey_cb and #add_future_signkey_cb.
    3341             :  */
    3342             : struct FutureBuilderContext
    3343             : {
    3344             :   /**
    3345             :    * Our key state.
    3346             :    */
    3347             :   struct TEH_KeyStateHandle *ksh;
    3348             : 
    3349             :   /**
    3350             :    * Array of denomination keys.
    3351             :    */
    3352             :   json_t *denoms;
    3353             : 
    3354             :   /**
    3355             :    * Array of signing keys.
    3356             :    */
    3357             :   json_t *signkeys;
    3358             : 
    3359             : };
    3360             : 
    3361             : 
    3362             : /**
    3363             :  * Function called on all of our current and future denomination keys
    3364             :  * known to the helper process. Filters out those that are current
    3365             :  * and adds the remaining denomination keys (with their configuration
    3366             :  * data) to the JSON array.
    3367             :  *
    3368             :  * @param cls the `struct FutureBuilderContext *`
    3369             :  * @param h_denom_pub hash of the denomination public key
    3370             :  * @param value a `struct HelperDenomination`
    3371             :  * @return #GNUNET_OK (continue to iterate)
    3372             :  */
    3373             : static enum GNUNET_GenericReturnValue
    3374           0 : add_future_denomkey_cb (void *cls,
    3375             :                         const struct GNUNET_HashCode *h_denom_pub,
    3376             :                         void *value)
    3377             : {
    3378           0 :   struct FutureBuilderContext *fbc = cls;
    3379           0 :   struct HelperDenomination *hd = value;
    3380             :   struct TEH_DenominationKey *dk;
    3381           0 :   struct TALER_EXCHANGEDB_DenominationKeyMetaData meta = {0};
    3382             : 
    3383           0 :   dk = GNUNET_CONTAINER_multihashmap_get (fbc->ksh->denomkey_map,
    3384             :                                           h_denom_pub);
    3385           0 :   if (NULL != dk)
    3386           0 :     return GNUNET_OK; /* skip: this key is already active! */
    3387           0 :   if (GNUNET_TIME_relative_is_zero (hd->validity_duration))
    3388           0 :     return GNUNET_OK; /* this key already expired! */
    3389           0 :   meta.start = hd->start_time;
    3390           0 :   meta.expire_withdraw = GNUNET_TIME_absolute_to_timestamp (
    3391             :     GNUNET_TIME_absolute_add (meta.start.abs_time,
    3392             :                               hd->validity_duration));
    3393           0 :   if (GNUNET_OK !=
    3394           0 :       load_extension_data (hd->section_name,
    3395             :                            &meta))
    3396             :   {
    3397             :     /* Woops, couldn't determine fee structure!? */
    3398           0 :     return GNUNET_OK;
    3399             :   }
    3400           0 :   GNUNET_assert (
    3401             :     0 ==
    3402             :     json_array_append_new (
    3403             :       fbc->denoms,
    3404             :       GNUNET_JSON_PACK (
    3405             :         TALER_JSON_pack_amount ("value",
    3406             :                                 &meta.value),
    3407             :         GNUNET_JSON_pack_timestamp ("stamp_start",
    3408             :                                     meta.start),
    3409             :         GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
    3410             :                                     meta.expire_withdraw),
    3411             :         GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
    3412             :                                     meta.expire_deposit),
    3413             :         GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
    3414             :                                     meta.expire_legal),
    3415             :         TALER_JSON_pack_denom_pub ("denom_pub",
    3416             :                                    &hd->denom_pub),
    3417             :         TALER_JSON_PACK_DENOM_FEES ("fee",
    3418             :                                     &meta.fees),
    3419             :         GNUNET_JSON_pack_data_auto ("denom_secmod_sig",
    3420             :                                     &hd->sm_sig),
    3421             :         GNUNET_JSON_pack_string ("section_name",
    3422             :                                  hd->section_name))));
    3423           0 :   return GNUNET_OK;
    3424             : }
    3425             : 
    3426             : 
    3427             : /**
    3428             :  * Function called on all of our current and future exchange signing keys
    3429             :  * known to the helper process. Filters out those that are current
    3430             :  * and adds the remaining signing keys (with their configuration
    3431             :  * data) to the JSON array.
    3432             :  *
    3433             :  * @param cls the `struct FutureBuilderContext *`
    3434             :  * @param pid actually the exchange public key (type disguised)
    3435             :  * @param value a `struct HelperDenomination`
    3436             :  * @return #GNUNET_OK (continue to iterate)
    3437             :  */
    3438             : static enum GNUNET_GenericReturnValue
    3439           0 : add_future_signkey_cb (void *cls,
    3440             :                        const struct GNUNET_PeerIdentity *pid,
    3441             :                        void *value)
    3442             : {
    3443           0 :   struct FutureBuilderContext *fbc = cls;
    3444           0 :   struct HelperSignkey *hsk = value;
    3445             :   struct SigningKey *sk;
    3446             :   struct GNUNET_TIME_Timestamp stamp_expire;
    3447             :   struct GNUNET_TIME_Timestamp legal_end;
    3448             : 
    3449           0 :   sk = GNUNET_CONTAINER_multipeermap_get (fbc->ksh->signkey_map,
    3450             :                                           pid);
    3451           0 :   if (NULL != sk)
    3452           0 :     return GNUNET_OK; /* skip: this key is already active */
    3453           0 :   if (GNUNET_TIME_relative_is_zero (hsk->validity_duration))
    3454           0 :     return GNUNET_OK; /* this key already expired! */
    3455           0 :   stamp_expire = GNUNET_TIME_absolute_to_timestamp (
    3456             :     GNUNET_TIME_absolute_add (hsk->start_time.abs_time,
    3457             :                               hsk->validity_duration));
    3458           0 :   legal_end = GNUNET_TIME_absolute_to_timestamp (
    3459             :     GNUNET_TIME_absolute_add (stamp_expire.abs_time,
    3460             :                               signkey_legal_duration));
    3461           0 :   GNUNET_assert (0 ==
    3462             :                  json_array_append_new (
    3463             :                    fbc->signkeys,
    3464             :                    GNUNET_JSON_PACK (
    3465             :                      GNUNET_JSON_pack_data_auto ("key",
    3466             :                                                  &hsk->exchange_pub),
    3467             :                      GNUNET_JSON_pack_timestamp ("stamp_start",
    3468             :                                                  hsk->start_time),
    3469             :                      GNUNET_JSON_pack_timestamp ("stamp_expire",
    3470             :                                                  stamp_expire),
    3471             :                      GNUNET_JSON_pack_timestamp ("stamp_end",
    3472             :                                                  legal_end),
    3473             :                      GNUNET_JSON_pack_data_auto ("signkey_secmod_sig",
    3474             :                                                  &hsk->sm_sig))));
    3475           0 :   return GNUNET_OK;
    3476             : }
    3477             : 
    3478             : 
    3479             : MHD_RESULT
    3480           0 : TEH_keys_management_get_keys_handler (const struct TEH_RequestHandler *rh,
    3481             :                                       struct MHD_Connection *connection)
    3482             : {
    3483             :   struct TEH_KeyStateHandle *ksh;
    3484             :   json_t *reply;
    3485             : 
    3486             :   (void) rh;
    3487           0 :   ksh = TEH_keys_get_state2 (true);
    3488           0 :   if (NULL == ksh)
    3489             :   {
    3490           0 :     return TALER_MHD_reply_with_error (connection,
    3491             :                                        MHD_HTTP_SERVICE_UNAVAILABLE,
    3492             :                                        TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
    3493             :                                        "no key state");
    3494             :   }
    3495           0 :   sync_key_helpers (ksh->helpers);
    3496           0 :   if (NULL == ksh->management_keys_reply)
    3497             :   {
    3498           0 :     struct FutureBuilderContext fbc = {
    3499             :       .ksh = ksh,
    3500           0 :       .denoms = json_array (),
    3501           0 :       .signkeys = json_array ()
    3502             :     };
    3503             : 
    3504           0 :     if ( (GNUNET_is_zero (&denom_rsa_sm_pub)) &&
    3505           0 :          (GNUNET_is_zero (&denom_cs_sm_pub)) )
    3506             :     {
    3507           0 :       return TALER_MHD_reply_with_error (connection,
    3508             :                                          MHD_HTTP_BAD_GATEWAY,
    3509             :                                          TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE,
    3510             :                                          NULL);
    3511             :     }
    3512           0 :     if (GNUNET_is_zero (&esign_sm_pub))
    3513             :     {
    3514           0 :       return TALER_MHD_reply_with_error (connection,
    3515             :                                          MHD_HTTP_BAD_GATEWAY,
    3516             :                                          TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE,
    3517             :                                          NULL);
    3518             :     }
    3519             :     // then a secmod helper is not yet running and we should return an MHD_HTTP_BAD_GATEWAY!
    3520           0 :     GNUNET_assert (NULL != fbc.denoms);
    3521           0 :     GNUNET_assert (NULL != fbc.signkeys);
    3522           0 :     GNUNET_CONTAINER_multihashmap_iterate (ksh->helpers->denom_keys,
    3523             :                                            &add_future_denomkey_cb,
    3524             :                                            &fbc);
    3525           0 :     GNUNET_CONTAINER_multipeermap_iterate (ksh->helpers->esign_keys,
    3526             :                                            &add_future_signkey_cb,
    3527             :                                            &fbc);
    3528           0 :     reply = GNUNET_JSON_PACK (
    3529             :       GNUNET_JSON_pack_array_steal ("future_denoms",
    3530             :                                     fbc.denoms),
    3531             :       GNUNET_JSON_pack_array_steal ("future_signkeys",
    3532             :                                     fbc.signkeys),
    3533             :       GNUNET_JSON_pack_data_auto ("master_pub",
    3534             :                                   &TEH_master_public_key),
    3535             :       GNUNET_JSON_pack_data_auto ("denom_secmod_public_key",
    3536             :                                   &denom_rsa_sm_pub),
    3537             :       GNUNET_JSON_pack_data_auto ("denom_secmod_cs_public_key",
    3538             :                                   &denom_cs_sm_pub),
    3539             :       GNUNET_JSON_pack_data_auto ("signkey_secmod_public_key",
    3540             :                                   &esign_sm_pub));
    3541           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    3542             :                 "Returning GET /management/keys response:\n");
    3543           0 :     if (NULL == reply)
    3544           0 :       return TALER_MHD_reply_with_error (connection,
    3545             :                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
    3546             :                                          TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE,
    3547             :                                          NULL);
    3548           0 :     GNUNET_assert (NULL == ksh->management_keys_reply);
    3549           0 :     ksh->management_keys_reply = reply;
    3550             :   }
    3551             :   else
    3552             :   {
    3553           0 :     reply = ksh->management_keys_reply;
    3554             :   }
    3555           0 :   return TALER_MHD_reply_json (connection,
    3556             :                                reply,
    3557             :                                MHD_HTTP_OK);
    3558             : }
    3559             : 
    3560             : 
    3561             : /* end of taler-exchange-httpd_keys.c */

Generated by: LCOV version 1.14