LCOV - code coverage report
Current view: top level - exchange - taler-exchange-httpd_keystate.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 450 594 75.8 %
Date: 2017-11-25 11:31:41 Functions: 30 33 90.9 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014-2017 GNUnet e.V.
       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_keystate.c
      18             :  * @brief management of our coin signing keys
      19             :  * @author Florian Dold
      20             :  * @author Benedikt Mueller
      21             :  * @author Christian Grothoff
      22             :  */
      23             : #include "platform.h"
      24             : #include <pthread.h>
      25             : #include "taler_json_lib.h"
      26             : #include "taler-exchange-httpd_keystate.h"
      27             : #include "taler-exchange-httpd_responses.h"
      28             : #include "taler_exchangedb_plugin.h"
      29             : 
      30             : 
      31             : /**
      32             :  * Taler protocol version in the format CURRENT:REVISION:AGE
      33             :  * as used by GNU libtool.  See
      34             :  * https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
      35             :  *
      36             :  * Please be very careful when updating and follow
      37             :  * https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info
      38             :  * precisely.  Note that this version has NOTHING to do with the
      39             :  * release version, and the format is NOT the same that semantic
      40             :  * versioning uses either.
      41             :  */
      42             : #define TALER_PROTOCOL_VERSION "1:0:1"
      43             : 
      44             : 
      45             : /**
      46             :  * Signatures of an auditor over a denomination key of this exchange.
      47             :  */
      48             : struct AuditorSignature
      49             : {
      50             :   /**
      51             :    * We store the signatures in a DLL.
      52             :    */
      53             :   struct AuditorSignature *prev;
      54             : 
      55             :   /**
      56             :    * We store the signatures in a DLL.
      57             :    */
      58             :   struct AuditorSignature *next;
      59             : 
      60             :   /**
      61             :    * A signature from the auditor.
      62             :    */
      63             :   struct TALER_AuditorSignatureP asig;
      64             : 
      65             :   /**
      66             :    * Public key of the auditor.
      67             :    */
      68             :   struct TALER_AuditorPublicKeyP apub;
      69             : 
      70             :   /**
      71             :    * URL of the auditor. Allocated at the end of this struct.
      72             :    */
      73             :   const char *auditor_url;
      74             : 
      75             : };
      76             : 
      77             : 
      78             : /**
      79             :  * Entry in sorted array of denomination keys.  Sorted by starting
      80             :  * "start" time (validity period) of the `struct
      81             :  * TALER_DenominationKeyValidityPS`.
      82             :  */
      83             : struct DenominationKeyEntry
      84             : {
      85             : 
      86             :   /**
      87             :    * Reference to the public key.
      88             :    * (Must also be in the `denomkey_map`).
      89             :    */
      90             :   const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
      91             : 
      92             :   /**
      93             :    * Head of DLL of signatures for this @e dki.
      94             :    */
      95             :   struct AuditorSignature *as_head;
      96             : 
      97             :   /**
      98             :    * Tail of DLL of signatures for this @e dki.
      99             :    */
     100             :   struct AuditorSignature *as_tail;
     101             : 
     102             :   /**
     103             :    * Hash of the public denomination key.
     104             :    */
     105             :   struct GNUNET_HashCode denom_key_hash;
     106             : 
     107             : };
     108             : 
     109             : 
     110             : /**
     111             :  * Entry in (sorted) array with possible pre-build responses for /keys.
     112             :  * We keep pre-build responses for the various (valid) cherry-picking
     113             :  * values around.
     114             :  */
     115             : struct KeysResponseData
     116             : {
     117             : 
     118             :   /**
     119             :    * Response to return if the client supports (gzip) compression.
     120             :    */
     121             :   struct MHD_Response *response_compressed;
     122             : 
     123             :   /**
     124             :    * Response to return if the client does not support compression.
     125             :    */
     126             :   struct MHD_Response *response_uncompressed;
     127             : 
     128             :   /**
     129             :    * Cherry-picking timestamp the client must have set for this
     130             :    * response to be valid.  0 if this is the "full" response.
     131             :    * The client's request must include this date or a higher one
     132             :    * for this response to be applicable.
     133             :    */
     134             :   struct GNUNET_TIME_Absolute cherry_pick_date;
     135             : 
     136             : };
     137             : 
     138             : 
     139             : /**
     140             :  * State we keep around while building an individual entry in the
     141             :  * `struct KeysResponseData` array, i.e. the global state for ONE of
     142             :  * the responses.
     143             :  */
     144             : struct ResponseBuilderContext
     145             : {
     146             : 
     147             :   /**
     148             :    * Hash context we used to combine the hashes of all denomination
     149             :    * keys into one big hash for signing.
     150             :    */
     151             :   struct GNUNET_HashContext *hash_context;
     152             : 
     153             :   /**
     154             :    * JSON array with denomination key information.
     155             :    */
     156             :   json_t *denom_keys_array;
     157             : 
     158             :   /**
     159             :    * JSON array with auditor information.
     160             :    */
     161             :   json_t *auditors_array;
     162             : 
     163             :   /**
     164             :    * Keys after what issue date do we care about?
     165             :    */
     166             :   struct GNUNET_TIME_Absolute last_issue_date;
     167             : 
     168             :   /**
     169             :    * Flag set to #GNUNET_SYSERR on internal errors
     170             :    */
     171             :   int error;
     172             : 
     173             : };
     174             : 
     175             : 
     176             : /**
     177             :  * State we keep around while building the `struct KeysResponseData`
     178             :  * array, i.e. the global state for all of the responses.
     179             :  */
     180             : struct ResponseFactoryContext
     181             : {
     182             : 
     183             :   /**
     184             :    * JSON array with revoked denomination keys.  Every response
     185             :    * always returns the full list (cherry picking does not apply
     186             :    * for key revocations, as we cannot sort those by issue date).
     187             :    */
     188             :   json_t *payback_array;
     189             : 
     190             :   /**
     191             :    * JSON array with signing keys.  Every response includes the full
     192             :    * list, as it should be quite short anyway, and for simplicity the
     193             :    * client only communicates the one time stamp of the last
     194             :    * denomination key it knows when cherry picking.
     195             :    */
     196             :   json_t *sign_keys_array;
     197             : 
     198             :   /**
     199             :    * Sorted array of denomination keys.  Length is @e denomkey_array_length.
     200             :    * Entries are sorted by the validity period's starting time.  All entries
     201             :    * must also be in the #denomkey_map.
     202             :    */
     203             :   struct DenominationKeyEntry *denomkey_array;
     204             : 
     205             :   /**
     206             :    * The main key state we are building everything for.
     207             :    */
     208             :   struct TEH_KS_StateHandle *key_state;
     209             : 
     210             :   /**
     211             :    * Length of the @e denomkey_array.
     212             :    */
     213             :   unsigned int denomkey_array_length;
     214             : 
     215             : };
     216             : 
     217             : 
     218             : 
     219             : /**
     220             :  * Snapshot of the (coin and signing) keys (including private keys) of
     221             :  * the exchange.  There can be multiple instances of this struct, as it is
     222             :  * reference counted and only destroyed once the last user is done
     223             :  * with it.  The current instance is acquired using
     224             :  * #TEH_KS_acquire().  Using this function increases the
     225             :  * reference count.  The contents of this structure (except for the
     226             :  * reference counter) should be considered READ-ONLY until it is
     227             :  * ultimately destroyed (as there can be many concurrent users).
     228             :  */
     229             : struct TEH_KS_StateHandle
     230             : {
     231             : 
     232             :   /**
     233             :    * Mapping from denomination keys to denomination key issue struct.
     234             :    * Used to lookup the key by hash.
     235             :    */
     236             :   struct GNUNET_CONTAINER_MultiHashMap *denomkey_map;
     237             : 
     238             :   /**
     239             :    * Mapping from revoked denomination keys to denomination key issue struct.
     240             :    * Used to lookup the key by hash.
     241             :    */
     242             :   struct GNUNET_CONTAINER_MultiHashMap *revoked_map;
     243             : 
     244             :   /**
     245             :    * Sorted array of responses to /keys (sorted by cherry-picking date) of
     246             :    * length @e krd_array_length;
     247             :    */
     248             :   struct KeysResponseData *krd_array;
     249             : 
     250             :   /**
     251             :    * When did we initiate the key reloading?
     252             :    */
     253             :   struct GNUNET_TIME_Absolute reload_time;
     254             : 
     255             :   /**
     256             :    * When is the next key invalid and we have to reload? (We also
     257             :    * reload on SIGUSR1.)
     258             :    */
     259             :   struct GNUNET_TIME_Absolute next_reload;
     260             : 
     261             :   /**
     262             :    * When does the first active denomination key expire (for deposit)?
     263             :    */
     264             :   struct GNUNET_TIME_Absolute min_dk_expire;
     265             : 
     266             :   /**
     267             :    * Exchange signing key that should be used currently.
     268             :    */
     269             :   struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP current_sign_key_issue;
     270             : 
     271             :   /**
     272             :    * Reference count.  The struct is released when the RC hits zero.
     273             :    */
     274             :   unsigned int refcnt;
     275             : 
     276             :   /**
     277             :    * Length of the @e krd_array.
     278             :    */
     279             :   unsigned int krd_array_length;
     280             : };
     281             : 
     282             : 
     283             : /* ************************** Clean up logic *********************** */
     284             : 
     285             : 
     286             : /**
     287             :  * Release memory used by @a rfc.
     288             :  *
     289             :  * @param rfc factory to release (but do not #GNUNET_free() rfc itself!)
     290             :  */
     291             : static void
     292           6 : destroy_response_factory (struct ResponseFactoryContext *rfc)
     293             : {
     294           6 :   if (NULL != rfc->payback_array)
     295             :   {
     296           6 :     json_decref (rfc->payback_array);
     297           6 :     rfc->payback_array = NULL;
     298             :   }
     299           6 :   if (NULL != rfc->sign_keys_array)
     300             :   {
     301           6 :     json_decref (rfc->sign_keys_array);
     302           6 :     rfc->sign_keys_array = NULL;
     303             :   }
     304          34 :   for (unsigned int i=0;i<rfc->denomkey_array_length;i++)
     305             :   {
     306          28 :     struct DenominationKeyEntry *dke = &rfc->denomkey_array[i];
     307             :     struct AuditorSignature *as;
     308             : 
     309          80 :     while (NULL != (as = dke->as_head))
     310             :     {
     311          24 :       GNUNET_CONTAINER_DLL_remove (dke->as_head,
     312             :                                    dke->as_tail,
     313             :                                    as);
     314          24 :       GNUNET_free (as);
     315             :     }
     316             :   }
     317           6 :   GNUNET_array_grow (rfc->denomkey_array,
     318             :                      rfc->denomkey_array_length,
     319             :                      0);
     320           6 : }
     321             : 
     322             : 
     323             : /**
     324             :  * Release memory used by @a rbc.
     325             :  */
     326             : static void
     327          17 : destroy_response_builder (struct ResponseBuilderContext *rbc)
     328             : {
     329          17 :   if (NULL != rbc->denom_keys_array)
     330             :   {
     331           0 :     json_decref (rbc->denom_keys_array);
     332           0 :     rbc->denom_keys_array = NULL;
     333             :   }
     334          17 :   if (NULL != rbc->auditors_array)
     335             :   {
     336           0 :     json_decref (rbc->auditors_array);
     337           0 :     rbc->auditors_array = NULL;
     338             :   }
     339          17 : }
     340             : 
     341             : 
     342             : /**
     343             :  * Iterator for freeing denomination keys.
     344             :  *
     345             :  * @param cls closure with the `struct TEH_KS_StateHandle`
     346             :  * @param key key for the denomination key
     347             :  * @param value coin details
     348             :  * @return #GNUNET_OK to continue to iterate,
     349             :  *  #GNUNET_NO to stop iteration with no error,
     350             :  *  #GNUNET_SYSERR to abort iteration with error!
     351             :  */
     352             : static int
     353          31 : free_denom_key (void *cls,
     354             :                 const struct GNUNET_HashCode *key,
     355             :                 void *value)
     356             : {
     357          31 :   struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki = value;
     358             : 
     359          31 :   GNUNET_CRYPTO_rsa_private_key_free (dki->denom_priv.rsa_private_key);
     360          31 :   GNUNET_CRYPTO_rsa_public_key_free (dki->denom_pub.rsa_public_key);
     361          31 :   GNUNET_free (dki);
     362          31 :   return GNUNET_OK;
     363             : }
     364             : 
     365             : 
     366             : /**
     367             :  * Release key state, free if necessary (if reference count gets to zero).
     368             :  * Internal method used when the mutex is already held.
     369             :  *
     370             :  * @param key_state the key state to release
     371             :  */
     372             : static void
     373          65 : ks_release (struct TEH_KS_StateHandle *key_state)
     374             : {
     375          65 :   GNUNET_assert (0 < key_state->refcnt);
     376          65 :   key_state->refcnt--;
     377          65 :   if (0 == key_state->refcnt)
     378             :   {
     379           6 :     if (NULL != key_state->denomkey_map)
     380             :     {
     381           6 :       GNUNET_CONTAINER_multihashmap_iterate (key_state->denomkey_map,
     382             :                                              &free_denom_key,
     383             :                                              key_state);
     384           6 :       GNUNET_CONTAINER_multihashmap_destroy (key_state->denomkey_map);
     385           6 :       key_state->denomkey_map = NULL;
     386             :     }
     387           6 :     if (NULL != key_state->revoked_map)
     388             :     {
     389           6 :       GNUNET_CONTAINER_multihashmap_iterate (key_state->revoked_map,
     390             :                                              &free_denom_key,
     391             :                                              key_state);
     392           6 :       GNUNET_CONTAINER_multihashmap_destroy (key_state->revoked_map);
     393           6 :       key_state->revoked_map = NULL;
     394             :     }
     395          23 :     for (unsigned int i=0;i<key_state->krd_array_length;i++)
     396             :     {
     397          17 :       struct KeysResponseData *krd = &key_state->krd_array[i];
     398             : 
     399          17 :       if (NULL != krd->response_compressed)
     400          17 :         MHD_destroy_response (krd->response_compressed);
     401          17 :       if (NULL != krd->response_uncompressed)
     402          17 :         MHD_destroy_response (krd->response_uncompressed);
     403             :     }
     404           6 :     GNUNET_array_grow (key_state->krd_array,
     405             :                        key_state->krd_array_length,
     406             :                        0);
     407           6 :     GNUNET_free (key_state);
     408             :   }
     409          65 : }
     410             : 
     411             : 
     412             : /* ************************* Signal logic ************************** */
     413             : 
     414             : /**
     415             :  * Pipe used for signaling reloading of our key state.
     416             :  */
     417             : static int reload_pipe[2];
     418             : 
     419             : 
     420             : /**
     421             :  * Handle a signal, writing relevant signal numbers to the pipe.
     422             :  *
     423             :  * @param signal_number the signal number
     424             :  */
     425             : static void
     426           6 : handle_signal (int signal_number)
     427             : {
     428             :   ssize_t res;
     429           6 :   char c = signal_number;
     430             : 
     431           6 :   res = write (reload_pipe[1],
     432             :                &c,
     433             :                1);
     434           6 :   if ( (res < 0) &&
     435           0 :        (EINTR != errno) )
     436             :   {
     437           0 :     GNUNET_break (0);
     438           0 :     return;
     439             :   }
     440           6 :   if (0 == res)
     441             :   {
     442           0 :     GNUNET_break (0);
     443           0 :     return;
     444             :   }
     445             : }
     446             : 
     447             : 
     448             : /* ************************** State builder ************************ */
     449             : 
     450             : 
     451             : /**
     452             :  * Convert the public part of a denomination key issue to a JSON
     453             :  * object.
     454             :  *
     455             :  * @param pk public key of the denomination key
     456             :  * @param dki the denomination key issue
     457             :  * @return a JSON object describing the denomination key isue (public part)
     458             :  */
     459             : static json_t *
     460          44 : denom_key_issue_to_json (const struct TALER_DenominationPublicKey *pk,
     461             :                          const struct TALER_EXCHANGEDB_DenominationKeyInformationP *dki)
     462             : {
     463             :   struct TALER_Amount value;
     464             :   struct TALER_Amount fee_withdraw;
     465             :   struct TALER_Amount fee_deposit;
     466             :   struct TALER_Amount fee_refresh;
     467             :   struct TALER_Amount fee_refund;
     468             : 
     469          44 :   TALER_amount_ntoh (&value,
     470             :                      &dki->properties.value);
     471          44 :   TALER_amount_ntoh (&fee_withdraw,
     472             :                      &dki->properties.fee_withdraw);
     473          44 :   TALER_amount_ntoh (&fee_deposit,
     474             :                      &dki->properties.fee_deposit);
     475          44 :   TALER_amount_ntoh (&fee_refresh,
     476             :                      &dki->properties.fee_refresh);
     477          44 :   TALER_amount_ntoh (&fee_refund,
     478             :                      &dki->properties.fee_refund);
     479             :   return
     480         132 :     json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}",
     481             :                "master_sig",
     482          44 :                GNUNET_JSON_from_data_auto (&dki->signature),
     483             :                "stamp_start",
     484             :                GNUNET_JSON_from_time_abs (GNUNET_TIME_absolute_ntoh (dki->properties.start)),
     485             :                "stamp_expire_withdraw",
     486             :                GNUNET_JSON_from_time_abs (GNUNET_TIME_absolute_ntoh (dki->properties.expire_withdraw)),
     487             :                "stamp_expire_deposit",
     488             :                GNUNET_JSON_from_time_abs (GNUNET_TIME_absolute_ntoh (dki->properties.expire_deposit)),
     489             :                "stamp_expire_legal",
     490             :                GNUNET_JSON_from_time_abs (GNUNET_TIME_absolute_ntoh (dki->properties.expire_legal)),
     491             :                "denom_pub",
     492          44 :                GNUNET_JSON_from_rsa_public_key (pk->rsa_public_key),
     493             :                "value",
     494             :                TALER_JSON_from_amount (&value),
     495             :                "fee_withdraw",
     496             :                TALER_JSON_from_amount (&fee_withdraw),
     497             :                "fee_deposit",
     498             :                TALER_JSON_from_amount (&fee_deposit),
     499             :                "fee_refresh",
     500             :                TALER_JSON_from_amount (&fee_refresh),
     501             :                "fee_refund",
     502             :                TALER_JSON_from_amount (&fee_refund));
     503             : }
     504             : 
     505             : 
     506             : /**
     507             :  * Store a copy of @a dki in @a map.
     508             :  *
     509             :  * @param map hash map to store @a dki in
     510             :  * @param dki information to store in @a map
     511             :  * @return #GNUNET_OK on success,
     512             :  *         #GNUNET_NO if such an entry already exists
     513             :  */
     514             : static int
     515          31 : store_in_map (struct GNUNET_CONTAINER_MultiHashMap *map,
     516             :               const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki)
     517             : {
     518             :   struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *d2;
     519             :   int res;
     520             : 
     521          31 :   d2 = GNUNET_new (struct TALER_EXCHANGEDB_DenominationKeyIssueInformation);
     522          31 :   d2->issue = dki->issue;
     523             :   d2->denom_priv.rsa_private_key
     524          31 :     = GNUNET_CRYPTO_rsa_private_key_dup (dki->denom_priv.rsa_private_key);
     525             :   d2->denom_pub.rsa_public_key
     526          31 :     = GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key);
     527          31 :   res = GNUNET_CONTAINER_multihashmap_put (map,
     528          31 :                                            &d2->issue.properties.denom_hash,
     529             :                                            d2,
     530             :                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
     531          31 :   if (GNUNET_OK != res)
     532             :   {
     533           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     534             :                 "Duplicate denomination key `%s'\n",
     535             :                 GNUNET_h2s (&d2->issue.properties.denom_hash));
     536           0 :     GNUNET_CRYPTO_rsa_private_key_free (d2->denom_priv.rsa_private_key);
     537           0 :     GNUNET_CRYPTO_rsa_public_key_free (d2->denom_pub.rsa_public_key);
     538           0 :     GNUNET_free (d2);
     539           0 :     return GNUNET_NO;
     540             :   }
     541          31 :   return GNUNET_OK;
     542             : }
     543             : 
     544             : 
     545             : /**
     546             :  * Closure for #add_revocations_transaction().
     547             :  */
     548             : struct AddRevocationContext
     549             : {
     550             :   /**
     551             :    * Denomination key that is revoked.
     552             :    */
     553             :   const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
     554             : 
     555             :   /**
     556             :    * Signature affirming the revocation.
     557             :    */
     558             :   const struct TALER_MasterSignatureP *revocation_master_sig;
     559             : };
     560             : 
     561             : 
     562             : /**
     563             :  * Get the relative time value that describes how
     564             :  * far in the future do we want to provide coin keys.
     565             :  *
     566             :  * @return the provide duration
     567             :  */
     568             : static struct GNUNET_TIME_Relative
     569          34 : TALER_EXCHANGE_conf_duration_provide ()
     570             : {
     571             :   struct GNUNET_TIME_Relative rel;
     572             : 
     573          34 :   if (GNUNET_OK !=
     574          34 :       GNUNET_CONFIGURATION_get_value_time (cfg,
     575             :                                            "exchange_keys",
     576             :                                            "lookahead_provide",
     577             :                                            &rel))
     578             :   {
     579           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     580             :                                "exchange_keys",
     581             :                                "lookahead_provide",
     582             :                                "time value required");
     583           0 :     GNUNET_assert (0);
     584             :   }
     585          34 :   return rel;
     586             : }
     587             : 
     588             : 
     589             : /**
     590             :  * Execute transaction to add revocations.
     591             :  *
     592             :  * @param cls closure with the `struct AddRevocationContext *`
     593             :  * @param connection NULL
     594             :  * @param session database session to use
     595             :  * @param[out] mhd_ret NULL
     596             :  * @return transaction status
     597             :  */
     598             : static enum GNUNET_DB_QueryStatus
     599           3 : add_revocations_transaction (void *cls,
     600             :                              struct MHD_Connection *connection,
     601             :                              struct TALER_EXCHANGEDB_Session *session,
     602             :                              int *mhd_ret)
     603             : {
     604           3 :   struct AddRevocationContext *arc = cls;
     605             : 
     606           6 :   return TEH_plugin->insert_denomination_revocation (TEH_plugin->cls,
     607             :                                                      session,
     608           3 :                                                      &arc->dki->issue.properties.denom_hash,
     609             :                                                      arc->revocation_master_sig);
     610             : }
     611             : 
     612             : 
     613             : /**
     614             :  * Execute transaction to add a denomination to the DB.
     615             :  *
     616             :  * @param cls closure with the `const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *`
     617             :  * @param connection NULL
     618             :  * @param session database session to use
     619             :  * @param[out] mhd_ret NULL
     620             :  * @return transaction status
     621             :  */
     622             : static enum GNUNET_DB_QueryStatus
     623          28 : add_denomination_transaction (void *cls,
     624             :                               struct MHD_Connection *connection,
     625             :                               struct TALER_EXCHANGEDB_Session *session,
     626             :                               int *mhd_ret)
     627             : {
     628          28 :   const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki = cls;
     629             :   enum GNUNET_DB_QueryStatus qs;
     630             :   struct TALER_EXCHANGEDB_DenominationKeyInformationP issue_exists;
     631             : 
     632          28 :   qs = TEH_plugin->get_denomination_info (TEH_plugin->cls,
     633             :                                           session,
     634             :                                           &dki->denom_pub,
     635             :                                           &issue_exists);
     636          28 :   if (0 > qs)
     637           0 :     return qs;
     638          28 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
     639          15 :     return qs;
     640          13 :   return TEH_plugin->insert_denomination_info (TEH_plugin->cls,
     641             :                                                session,
     642             :                                                &dki->denom_pub,
     643             :                                                &dki->issue);
     644             : }
     645             : 
     646             : 
     647             : /**
     648             :  * Iterator for (re)loading/initializing denomination keys.
     649             :  *
     650             :  * @param cls closure with a `struct ResponseFactoryContext *`
     651             :  * @param dki the denomination key issue
     652             :  * @param alias coin alias
     653             :  * @param revocation_master_sig non-NULL if @a dki was revoked
     654             :  * @return #GNUNET_OK to continue to iterate,
     655             :  *  #GNUNET_NO to stop iteration with no error,
     656             :  *  #GNUNET_SYSERR to abort iteration with error!
     657             :  */
     658             : static int
     659          31 : reload_keys_denom_iter (void *cls,
     660             :                         const char *alias,
     661             :                         const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki,
     662             :                         const struct TALER_MasterSignatureP *revocation_master_sig)
     663             : {
     664          31 :   struct ResponseFactoryContext *rfc = cls;
     665          31 :   struct TEH_KS_StateHandle *key_state = rfc->key_state;
     666             :   struct GNUNET_TIME_Absolute now;
     667             :   struct GNUNET_TIME_Absolute start;
     668             :   struct GNUNET_TIME_Absolute horizon;
     669             :   struct GNUNET_TIME_Absolute expire_deposit;
     670             :   int res;
     671             : 
     672          31 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     673             :               "Loading denomination key `%s' (%s)\n",
     674             :               alias,
     675             :               GNUNET_h2s (&dki->issue.properties.denom_hash));
     676          31 :   now = GNUNET_TIME_absolute_get ();
     677          31 :   expire_deposit = GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_deposit);
     678          31 :   if (expire_deposit.abs_value_us < now.abs_value_us)
     679             :   {
     680           0 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     681             :                 "Skipping expired denomination key `%s'\n",
     682             :                 alias);
     683           0 :     return GNUNET_OK;
     684             :   }
     685          31 :   if (0 != memcmp (&dki->issue.properties.master,
     686             :                    &TEH_master_public_key,
     687             :                    sizeof (struct TALER_MasterPublicKeyP)))
     688             :   {
     689           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     690             :                 "Master key in denomination key file `%s' does not match! Skipping it.\n",
     691             :                 alias);
     692           0 :     return GNUNET_OK;
     693             :   }
     694             : 
     695          31 :   if (NULL != revocation_master_sig)
     696             :   {
     697             :     struct AddRevocationContext arc;
     698             : 
     699           3 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     700             :                 "Adding denomination key `%s' (%s) to revocation set\n",
     701             :                 alias,
     702             :                 GNUNET_h2s (&dki->issue.properties.denom_hash));
     703           3 :     res = store_in_map (key_state->revoked_map,
     704             :                         dki);
     705           3 :     if (GNUNET_NO == res)
     706           0 :       return GNUNET_OK;
     707             :     /* Try to insert DKI into DB until we succeed; note that if the DB
     708             :        failure is persistent, we need to die, as we cannot continue
     709             :        without the DKI being in the DB). */
     710           3 :     arc.dki = dki;
     711           3 :     arc.revocation_master_sig = revocation_master_sig;
     712           3 :     if (GNUNET_OK !=
     713           3 :         TEH_DB_run_transaction (NULL,
     714             :                                 NULL,
     715             :                                 &add_revocations_transaction,
     716             :                                 &arc))
     717             :     {
     718           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     719             :                   "Giving up, this is fatal. Committing suicide via SIGTERM.\n");
     720           0 :       handle_signal (SIGTERM);
     721           0 :       return GNUNET_SYSERR;
     722             :     }
     723           3 :     GNUNET_assert (0 ==
     724             :                    json_array_append_new (rfc->payback_array,
     725             :                                           GNUNET_JSON_from_data_auto (&dki->issue.properties.denom_hash)));
     726           3 :     return GNUNET_OK;
     727             :   }
     728          28 :   horizon = GNUNET_TIME_relative_to_absolute (TALER_EXCHANGE_conf_duration_provide ());
     729          28 :   start = GNUNET_TIME_absolute_ntoh (dki->issue.properties.start);
     730          28 :   if (start.abs_value_us > horizon.abs_value_us)
     731             :   {
     732           0 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     733             :                 "Skipping future denomination key `%s' (%s), validity starts at %s\n",
     734             :                 alias,
     735             :                 GNUNET_h2s (&dki->issue.properties.denom_hash),
     736             :                 GNUNET_STRINGS_absolute_time_to_string (start));
     737           0 :     return GNUNET_OK;
     738             :   }
     739             : 
     740          28 :   if (GNUNET_OK !=
     741          28 :       TEH_DB_run_transaction (NULL,
     742             :                               NULL,
     743             :                               &add_denomination_transaction,
     744             :                               (void *) dki))
     745             :   {
     746           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     747             :                 "Could not persist denomination key %s in DB. Committing suicide via SIGTERM.\n",
     748             :                 GNUNET_h2s (&dki->issue.properties.denom_hash));
     749           0 :     handle_signal (SIGTERM);
     750           0 :     return GNUNET_SYSERR;
     751             :   }
     752             : 
     753          28 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     754             :               "Adding denomination key `%s' (%s) to active set\n",
     755             :               alias,
     756             :               GNUNET_h2s (&dki->issue.properties.denom_hash));
     757          28 :   res = store_in_map (key_state->denomkey_map,
     758             :                       dki);
     759          28 :   if (GNUNET_NO == res)
     760           0 :     return GNUNET_OK;
     761          28 :   key_state->min_dk_expire = GNUNET_TIME_absolute_min (key_state->min_dk_expire,
     762             :                                                        expire_deposit);
     763          28 :   return GNUNET_OK;
     764             : }
     765             : 
     766             : 
     767             : /**
     768             :  * Convert the public part of a sign key issue to a JSON object.
     769             :  *
     770             :  * @param ski the sign key issue
     771             :  * @return a JSON object describing the sign key issue (public part)
     772             :  */
     773             : static json_t *
     774           6 : sign_key_issue_to_json (const struct TALER_ExchangeSigningKeyValidityPS *ski)
     775             : {
     776             :   return
     777          12 :     json_pack ("{s:o, s:o, s:o, s:o, s:o}",
     778             :                "stamp_start",
     779             :                GNUNET_JSON_from_time_abs (GNUNET_TIME_absolute_ntoh (ski->start)),
     780             :                "stamp_expire",
     781             :                GNUNET_JSON_from_time_abs (GNUNET_TIME_absolute_ntoh (ski->expire)),
     782             :                "stamp_end",
     783             :                GNUNET_JSON_from_time_abs (GNUNET_TIME_absolute_ntoh (ski->end)),
     784             :                "master_sig",
     785           6 :                GNUNET_JSON_from_data_auto (&ski->signature),
     786             :                "key",
     787           6 :                GNUNET_JSON_from_data_auto (&ski->signkey_pub));
     788             : }
     789             : 
     790             : 
     791             : /**
     792             :  * Iterator for sign keys.  Adds current and near-future signing keys
     793             :  * to the `sign_keys_array` and stores the current one in the
     794             :  * `key_state`.
     795             :  *
     796             :  * @param cls closure with the `struct ResponseFactoryContext *`
     797             :  * @param filename name of the file the key came from
     798             :  * @param ski the sign key issue
     799             :  * @return #GNUNET_OK to continue to iterate,
     800             :  *  #GNUNET_NO to stop iteration with no error,
     801             :  *  #GNUNET_SYSERR to abort iteration with error!
     802             :  */
     803             : static int
     804           6 : reload_keys_sign_iter (void *cls,
     805             :                        const char *filename,
     806             :                        const struct TALER_EXCHANGEDB_PrivateSigningKeyInformationP *ski)
     807             : {
     808           6 :   struct ResponseFactoryContext *rfc = cls;
     809           6 :   struct TEH_KS_StateHandle *key_state = rfc->key_state;
     810             :   struct GNUNET_TIME_Absolute now;
     811             :   struct GNUNET_TIME_Absolute horizon;
     812             : 
     813           6 :   horizon = GNUNET_TIME_relative_to_absolute (TALER_EXCHANGE_conf_duration_provide ());
     814          12 :   if (GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us >
     815           6 :       horizon.abs_value_us)
     816             :   {
     817           0 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     818             :                 "Skipping future signing key `%s'\n",
     819             :                 filename);
     820           0 :     return GNUNET_OK;
     821             :   }
     822           6 :   now = GNUNET_TIME_absolute_get ();
     823          12 :   if (GNUNET_TIME_absolute_ntoh (ski->issue.expire).abs_value_us <
     824           6 :       now.abs_value_us)
     825             :   {
     826           0 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     827             :                 "Skipping expired signing key `%s'\n",
     828             :                 filename);
     829           0 :     return GNUNET_OK;
     830             :   }
     831             : 
     832           6 :   if (0 != memcmp (&ski->issue.master_public_key,
     833             :                    &TEH_master_public_key,
     834             :                    sizeof (struct TALER_MasterPublicKeyP)))
     835             :   {
     836           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     837             :                 "Master key in signing key file `%s' does not match! Skipping it.\n",
     838             :                 filename);
     839           0 :     return GNUNET_OK;
     840             :   }
     841             : 
     842             :   /* The signkey is valid at this time, check if it's more recent than
     843             :      what we have so far! */
     844          12 :   if ( (GNUNET_TIME_absolute_ntoh (key_state->current_sign_key_issue.issue.start).abs_value_us <
     845          12 :         GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us) &&
     846           6 :        (GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us <
     847           6 :         now.abs_value_us) )
     848             :   {
     849             :     /* We use the most recent one, if it is valid now (not just in the near future) */
     850           6 :     key_state->current_sign_key_issue = *ski;
     851             :   }
     852           6 :   GNUNET_assert (0 ==
     853             :                  json_array_append_new (rfc->sign_keys_array,
     854             :                                         sign_key_issue_to_json (&ski->issue)));
     855             : 
     856           6 :   return GNUNET_OK;
     857             : }
     858             : 
     859             : 
     860             : /**
     861             :  * @brief Iterator called with auditor information.
     862             :  * Check that the @a mpub actually matches this exchange, and then
     863             :  * add the auditor information to our /keys response (if it is
     864             :  * (still) applicable).
     865             :  *
     866             :  * @param cls closure with the `struct ResponseFactoryContext *`
     867             :  * @param apub the auditor's public key
     868             :  * @param auditor_url URL of the auditor
     869             :  * @param mpub the exchange's public key (as expected by the auditor)
     870             :  * @param dki_len length of @a dki and @a asigs
     871             :  * @param asigs array with the auditor's signatures, of length @a dki_len
     872             :  * @param dki array of denomination coin data signed by the auditor
     873             :  * @return #GNUNET_OK to continue to iterate,
     874             :  *  #GNUNET_NO to stop iteration with no error,
     875             :  *  #GNUNET_SYSERR to abort iteration with error!
     876             :  */
     877             : static int
     878           6 : reload_auditor_iter (void *cls,
     879             :                      const struct TALER_AuditorPublicKeyP *apub,
     880             :                      const char *auditor_url,
     881             :                      const struct TALER_MasterPublicKeyP *mpub,
     882             :                      unsigned int dki_len,
     883             :                      const struct TALER_AuditorSignatureP *asigs,
     884             :                      const struct TALER_DenominationKeyValidityPS *dki)
     885             : {
     886           6 :   struct ResponseFactoryContext *rfc = cls;
     887           6 :   struct TEH_KS_StateHandle *key_state = rfc->key_state;
     888             : 
     889             :   /* Check if the signature is at least for this exchange. */
     890           6 :   if (0 != memcmp (&mpub->eddsa_pub,
     891             :                    &TEH_master_public_key,
     892             :                    sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
     893             :   {
     894           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     895             :                 "Auditing information provided for a different exchange, ignored\n");
     896           0 :     return GNUNET_OK;
     897             :   }
     898             :   /* Filter the auditor information for those for which the
     899             :      keys actually match the denomination keys that are active right now */
     900          33 :   for (unsigned int i=0;i<dki_len;i++)
     901             :   {
     902             :     int matched;
     903             : 
     904          27 :     if (GNUNET_YES !=
     905          27 :         GNUNET_CONTAINER_multihashmap_contains (key_state->denomkey_map,
     906          27 :                                                 &dki[i].denom_hash))
     907             :     {
     908           3 :       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     909             :                   "Found auditor signature for DK `%s', but key is not in active map\n",
     910             :                   GNUNET_h2s (&dki[i].denom_hash));
     911           3 :       continue;
     912             :     }
     913          24 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     914             :                 "Found auditor signature for DK `%s'\n",
     915             :                 GNUNET_h2s (&dki[i].denom_hash));
     916             :     /* Note: the array is sorted, we could theoretically
     917             :        speed this up using a binary search. */
     918          24 :     matched = GNUNET_NO;
     919          77 :     for (unsigned int j=0;j<rfc->denomkey_array_length;j++)
     920             :     {
     921          77 :       struct DenominationKeyEntry *dke = &rfc->denomkey_array[j];
     922             :       struct AuditorSignature *as;
     923             : 
     924          77 :       if (0 !=
     925          77 :           memcmp (&dki[i].denom_hash,
     926          77 :                   &dke->dki->issue.properties.denom_hash,
     927             :                   sizeof (struct GNUNET_HashCode)))
     928          53 :         continue;
     929          24 :       if (0 !=
     930          24 :           memcmp (&dki[i],
     931          24 :                   &dke->dki->issue.properties,
     932             :                   sizeof (struct TALER_DenominationKeyValidityPS)))
     933             :       {
     934             :         /* if the hash is the same, the properties should also match! */
     935           0 :         GNUNET_break (0);
     936           0 :         continue;
     937             :       }
     938          24 :       as = GNUNET_malloc (sizeof (struct AuditorSignature) +
     939             :                           strlen (auditor_url) + 1);
     940          24 :       as->asig = asigs[i];
     941          24 :       as->apub = *apub;
     942          24 :       as->auditor_url = (const char *) &as[1];
     943          24 :       memcpy (&as[1],
     944             :               auditor_url,
     945          24 :               strlen (auditor_url) + 1);
     946          24 :       GNUNET_CONTAINER_DLL_insert (dke->as_head,
     947             :                                    dke->as_tail,
     948             :                                    as);
     949          24 :       matched = GNUNET_YES;
     950          24 :       break;
     951             :     }
     952          24 :     if (GNUNET_NO == matched)
     953             :     {
     954           0 :       GNUNET_break (0);
     955           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     956             :                   "DK `%s' is in active map, but not in array!?\n",
     957             :                   GNUNET_h2s (&dki[i].denom_hash));
     958             :     }
     959             :   }
     960           6 :   return GNUNET_OK;
     961             : }
     962             : 
     963             : 
     964             : /**
     965             :  * Initialize the `denomkey_array`.  We are called once per
     966             :  * array index, which is tracked in `denomkey_array_length` (the
     967             :  * array will be of sufficient size).  Set the pointer to the
     968             :  * denomination key and increment the `denomkey_array_length`.
     969             :  *
     970             :  * @param cls a `struct ResponseFactoryContext`
     971             :  * @param denom_hash hash of a denomination key
     972             :  * @param value a `struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *`
     973             :  * @return #GNUNET_OK
     974             :  */
     975             : static int
     976          28 : initialize_denomkey_array (void *cls,
     977             :                            const struct GNUNET_HashCode *denom_hash,
     978             :                            void *value)
     979             : {
     980          28 :   struct ResponseFactoryContext *rfc = cls;
     981          28 :   struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki = value;
     982             : 
     983          28 :   rfc->denomkey_array[rfc->denomkey_array_length].denom_key_hash = *denom_hash;
     984          28 :   rfc->denomkey_array[rfc->denomkey_array_length++].dki = dki;
     985          28 :   return GNUNET_OK;
     986             : }
     987             : 
     988             : 
     989             : /**
     990             :  * Comparator used to sort the `struct DenominationKeyEntry` array
     991             :  * by the validity period's starting time of the keys.
     992             :  *
     993             :  * @param k1 a `struct DenominationKeyEntry *`
     994             :  * @param k2 a `struct DenominationKeyEntry *`
     995             :  * @return -1 if k1 starts before k2,
     996             :  *          1 if k2 starts before k1,
     997             :  *          0 if they start at the same time
     998             :  */
     999             : static int
    1000          36 : denomkey_array_sort_comparator (const void *k1,
    1001             :                                 const void *k2)
    1002             : {
    1003          36 :   const struct DenominationKeyEntry *dke1 = k1;
    1004          36 :   const struct DenominationKeyEntry *dke2 = k2;
    1005          36 :   struct GNUNET_TIME_Absolute d1
    1006          36 :     = GNUNET_TIME_absolute_ntoh (dke1->dki->issue.properties.start);
    1007          36 :   struct GNUNET_TIME_Absolute d2
    1008          36 :     = GNUNET_TIME_absolute_ntoh (dke2->dki->issue.properties.start);
    1009             : 
    1010          36 :   if (d1.abs_value_us < d2.abs_value_us)
    1011           9 :     return -1;
    1012          27 :   if (d1.abs_value_us > d2.abs_value_us)
    1013           8 :     return  1;
    1014          19 :   return 0;
    1015             : }
    1016             : 
    1017             : 
    1018             : /**
    1019             :  * Produce HTTP "Date:" header.
    1020             :  *
    1021             :  * @param at time to write to @a date
    1022             :  * @param[out] date where to write the header, with
    1023             :  *        at least 128 bytes available space.
    1024             :  */
    1025             : static void
    1026          68 : get_date_string (struct GNUNET_TIME_Absolute at,
    1027             :                  char *date)
    1028             : {
    1029             :   static const char *const days[] =
    1030             :     { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
    1031             :   static const char *const mons[] =
    1032             :     { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
    1033             :     "Nov", "Dec"
    1034             :   };
    1035             :   struct tm now;
    1036             :   time_t t;
    1037             : #if !defined(HAVE_C11_GMTIME_S) && !defined(HAVE_W32_GMTIME_S) && !defined(HAVE_GMTIME_R)
    1038             :   struct tm* pNow;
    1039             : #endif
    1040             : 
    1041          68 :   date[0] = 0;
    1042          68 :   t = (time_t) (at.abs_value_us / 1000LL / 1000LL);
    1043             : #if defined(HAVE_C11_GMTIME_S)
    1044             :   if (NULL == gmtime_s (&t, &now))
    1045             :     return;
    1046             : #elif defined(HAVE_W32_GMTIME_S)
    1047             :   if (0 != gmtime_s (&now, &t))
    1048             :     return;
    1049             : #elif defined(HAVE_GMTIME_R)
    1050             :   if (NULL == gmtime_r(&t, &now))
    1051             :     return;
    1052             : #else
    1053          68 :   pNow = gmtime(&t);
    1054          68 :   if (NULL == pNow)
    1055           0 :     return;
    1056          68 :   now = *pNow;
    1057             : #endif
    1058         476 :   sprintf (date,
    1059             :            "%3s, %02u %3s %04u %02u:%02u:%02u GMT",
    1060          68 :            days[now.tm_wday % 7],
    1061          68 :            (unsigned int) now.tm_mday,
    1062          68 :            mons[now.tm_mon % 12],
    1063          68 :            (unsigned int) (1900 + now.tm_year),
    1064          68 :            (unsigned int) now.tm_hour,
    1065          68 :            (unsigned int) now.tm_min,
    1066          68 :            (unsigned int) now.tm_sec);
    1067             : }
    1068             : 
    1069             : 
    1070             : /**
    1071             :  * Add the headers we want to set for every /keys response.
    1072             :  *
    1073             :  * @param key_state the key state to use
    1074             :  * @param[in,out] response the response to modify
    1075             :  * @return #GNUNET_OK on success
    1076             :  */
    1077             : static int
    1078          34 : setup_general_response_headers (const struct TEH_KS_StateHandle *key_state,
    1079             :                                 struct MHD_Response *response)
    1080             : {
    1081             :   char dat[128];
    1082             : 
    1083          34 :   TEH_RESPONSE_add_global_headers (response);
    1084          34 :   GNUNET_break (MHD_YES ==
    1085             :                 MHD_add_response_header (response,
    1086             :                                          MHD_HTTP_HEADER_CONTENT_TYPE,
    1087             :                                          "application/json"));
    1088          34 :   get_date_string (key_state->reload_time,
    1089             :                    dat);
    1090          34 :   GNUNET_break (MHD_YES ==
    1091             :                 MHD_add_response_header (response,
    1092             :                                          MHD_HTTP_HEADER_LAST_MODIFIED,
    1093             :                                          dat));
    1094          34 :   if (0 != key_state->next_reload.abs_value_us)
    1095             :   {
    1096          34 :     get_date_string (key_state->next_reload,
    1097             :                      dat);
    1098          34 :     GNUNET_break (MHD_YES ==
    1099             :                   MHD_add_response_header (response,
    1100             :                                            MHD_HTTP_HEADER_EXPIRES,
    1101             :                                            dat));
    1102             :   }
    1103          34 :   return GNUNET_OK;
    1104             : }
    1105             : 
    1106             : 
    1107             : /**
    1108             :  * Information about an auditor to be added.
    1109             :  */
    1110             : struct AuditorEntry
    1111             : {
    1112             :   /**
    1113             :    * URL of the auditor (allocated still as part of a
    1114             :    * `struct AuditorSignature`, do not free!).
    1115             :    */
    1116             :   const char *auditor_url;
    1117             : 
    1118             :   /**
    1119             :    * Public key of the auditor (allocated still as part of a
    1120             :    * `struct AuditorSignature`, do not free!).
    1121             :    */
    1122             :   const struct TALER_AuditorPublicKeyP *apub;
    1123             : 
    1124             :   /**
    1125             :    * Array of denomination keys and auditor signatures.
    1126             :    */
    1127             :   json_t *ar;
    1128             : 
    1129             : };
    1130             : 
    1131             : 
    1132             : /**
    1133             :  * Convert auditor entries from the hash map to entries
    1134             :  * in the auditor array, free the auditor entry as well.
    1135             :  *
    1136             :  * @param cls a `struct ResponseBuilderContext *`
    1137             :  * @param key unused
    1138             :  * @param value a `struct AuditorEntry` to add to the `auditors_array`
    1139             :  * @return #GNUNET_OK (to continue to iterate)
    1140             :  */
    1141             : static int
    1142          11 : add_auditor_entry (void *cls,
    1143             :                    const struct GNUNET_HashCode *key,
    1144             :                    void *value)
    1145             : {
    1146          11 :   struct ResponseBuilderContext *rbc = cls;
    1147          11 :   struct AuditorEntry *ae = value;
    1148             :   json_t *ao;
    1149             : 
    1150          11 :   ao = json_pack ("{s:o, s:s, s:o}",
    1151             :                   "denomination_keys", ae->ar,
    1152             :                   "auditor_url", ae->auditor_url,
    1153          11 :                   "auditor_pub", GNUNET_JSON_from_data_auto (ae->apub));
    1154          11 :   GNUNET_assert (NULL != ao);
    1155          11 :   GNUNET_assert (0 ==
    1156             :                  json_array_append_new (rbc->auditors_array,
    1157             :                                         ao));
    1158          11 :   GNUNET_free (ae);
    1159          11 :   return GNUNET_OK;
    1160             : }
    1161             : 
    1162             : 
    1163             : /**
    1164             :  * Initialize @a krd for the given @a cherry_pick_date using
    1165             :  * the key data in @a rfc.  This function actually builds the
    1166             :  * respective JSON replies (compressed and uncompressed).
    1167             :  *
    1168             :  * @param rfc factory with key material
    1169             :  * @param[out] krd response object to initialize
    1170             :  * @param denom_off offset in the @a rfc's `denomkey_array` at which
    1171             :  *        keys beyond the @a cherry_pick_date are stored
    1172             :  * @param cherry_pick_date cut-off date to use
    1173             :  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
    1174             :  */
    1175             : static int
    1176          17 : build_keys_response (const struct ResponseFactoryContext *rfc,
    1177             :                      struct KeysResponseData *krd,
    1178             :                      unsigned int denom_off,
    1179             :                      struct GNUNET_TIME_Absolute cherry_pick_date)
    1180             : {
    1181             :   struct ResponseBuilderContext rbc;
    1182             :   json_t *keys;
    1183             :   struct TALER_ExchangeKeySetPS ks;
    1184             :   struct TALER_ExchangeSignatureP sig;
    1185             :   char *keys_json;
    1186             :   void *keys_jsonz;
    1187             :   size_t keys_jsonz_size;
    1188             :   int comp;
    1189             : 
    1190          17 :   krd->cherry_pick_date = cherry_pick_date;
    1191             : 
    1192             :   /* Initialize `rbc` */
    1193          17 :   memset (&rbc,
    1194             :           0,
    1195             :           sizeof (rbc));
    1196          17 :   rbc.denom_keys_array = json_array ();
    1197          17 :   if (NULL == rbc.denom_keys_array)
    1198             :   {
    1199           0 :     GNUNET_break (0);
    1200           0 :     return GNUNET_SYSERR;
    1201             :   }
    1202          17 :   rbc.auditors_array = json_array ();
    1203          17 :   if (NULL == rbc.auditors_array)
    1204             :   {
    1205           0 :     destroy_response_builder (&rbc);
    1206           0 :     GNUNET_break (0);
    1207           0 :     return GNUNET_SYSERR;
    1208             :   }
    1209          17 :   rbc.hash_context = GNUNET_CRYPTO_hash_context_start ();
    1210             : 
    1211             :   /* Go over relevant denomination keys. */
    1212             :   {
    1213             :     struct GNUNET_CONTAINER_MultiHashMap *auditors;
    1214             : 
    1215          17 :     auditors = GNUNET_CONTAINER_multihashmap_create (4,
    1216             :                                                      GNUNET_NO);
    1217          61 :     for (unsigned int i=denom_off;i<rfc->denomkey_array_length;i++)
    1218             :     {
    1219             :       /* Add denomination key to the response */
    1220          44 :       const struct DenominationKeyEntry *dke
    1221          44 :         = &rfc->denomkey_array[i];
    1222          44 :       const struct GNUNET_HashCode *denom_key_hash
    1223             :         = &dke->denom_key_hash;
    1224             : 
    1225          44 :       GNUNET_CRYPTO_hash_context_read (rbc.hash_context,
    1226             :                                        denom_key_hash,
    1227             :                                        sizeof (struct GNUNET_HashCode));
    1228          44 :       if (0 !=
    1229          88 :           json_array_append_new (rbc.denom_keys_array,
    1230          44 :                                  denom_key_issue_to_json (&dke->dki->denom_pub,
    1231          44 :                                                           &dke->dki->issue)))
    1232             :       {
    1233           0 :         GNUNET_break (0);
    1234           0 :         destroy_response_builder (&rbc);
    1235           0 :         return GNUNET_SYSERR;
    1236             :       }
    1237             : 
    1238             :       /* Add auditor data */
    1239         126 :       for (const struct AuditorSignature *as = dke->as_head;
    1240             :            NULL != as;
    1241          38 :            as = as->next)
    1242             :       {
    1243             :         struct GNUNET_HashCode ahash;
    1244             :         struct AuditorEntry *ae;
    1245             : 
    1246          38 :         GNUNET_CRYPTO_hash (&as->apub,
    1247             :                             sizeof (as->apub),
    1248             :                             &ahash);
    1249          38 :         ae = GNUNET_CONTAINER_multihashmap_get (auditors,
    1250             :                                                 &ahash);
    1251          38 :         if (NULL == ae)
    1252             :         {
    1253          11 :           ae = GNUNET_new (struct AuditorEntry);
    1254          11 :           ae->auditor_url = as->auditor_url;
    1255          11 :           ae->ar = json_array ();
    1256          11 :           ae->apub = &as->apub;
    1257          11 :           GNUNET_assert (GNUNET_YES ==
    1258             :                          GNUNET_CONTAINER_multihashmap_put (auditors,
    1259             :                                                             &ahash,
    1260             :                                                             ae,
    1261             :                                                             GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    1262             :         }
    1263          38 :         GNUNET_assert (0 ==
    1264             :                        json_array_append_new (ae->ar,
    1265             :                                               json_pack ("{s:o, s:o}",
    1266             :                                                          "denom_pub_h",
    1267             :                                                          GNUNET_JSON_from_data_auto (denom_key_hash),
    1268             :                                                          "auditor_sig",
    1269             :                                                          GNUNET_JSON_from_data_auto (&as->asig))));
    1270             :       }
    1271             :     }
    1272             : 
    1273          17 :     GNUNET_CONTAINER_multihashmap_iterate (auditors,
    1274             :                                            &add_auditor_entry,
    1275             :                                            &rbc);
    1276          17 :     GNUNET_CONTAINER_multihashmap_destroy (auditors);
    1277             :   }
    1278             : 
    1279             :   /* Sign hash over denomination keys */
    1280          17 :   ks.purpose.size = htonl (sizeof (ks));
    1281          17 :   ks.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_KEY_SET);
    1282          17 :   ks.list_issue_date = GNUNET_TIME_absolute_hton (rfc->key_state->reload_time);
    1283          17 :   GNUNET_CRYPTO_hash_context_finish (rbc.hash_context,
    1284             :                                      &ks.hc);
    1285          17 :   rbc.hash_context = NULL;
    1286          17 :   GNUNET_assert (GNUNET_OK ==
    1287             :                  GNUNET_CRYPTO_eddsa_sign (&rfc->key_state->current_sign_key_issue.signkey_priv.eddsa_priv,
    1288             :                                            &ks.purpose,
    1289             :                                            &sig.eddsa_signature));
    1290             : 
    1291             :   /* Build /keys response */
    1292          51 :   keys = json_pack ("{s:s, s:o, s:O, s:O, s:o, s:o, s:o, s:o, s:o}",
    1293             :                     "version", TALER_PROTOCOL_VERSION,
    1294             :                     "master_public_key", GNUNET_JSON_from_data_auto (&TEH_master_public_key),
    1295             :                     "signkeys", rfc->sign_keys_array,
    1296             :                     "payback", rfc->payback_array,
    1297             :                     "denoms", rbc.denom_keys_array,
    1298             :                     "auditors", rbc.auditors_array,
    1299          17 :                     "list_issue_date", GNUNET_JSON_from_time_abs (rfc->key_state->reload_time),
    1300          17 :                     "eddsa_pub", GNUNET_JSON_from_data_auto (&rfc->key_state->current_sign_key_issue.issue.signkey_pub),
    1301             :                     "eddsa_sig", GNUNET_JSON_from_data_auto (&sig));
    1302          17 :   if (NULL == keys)
    1303             :   {
    1304           0 :     destroy_response_builder (&rbc);
    1305           0 :     GNUNET_break (0);
    1306           0 :     return GNUNET_SYSERR;
    1307             :   }
    1308          17 :   rbc.denom_keys_array = NULL;
    1309          17 :   rbc.auditors_array = NULL;
    1310          17 :   destroy_response_builder (&rbc);
    1311             : 
    1312             :   /* Convert /keys response to UTF8-String */
    1313          17 :   keys_json = json_dumps (keys,
    1314             :                           JSON_INDENT (2));
    1315          17 :   json_decref (keys);
    1316          17 :   if (NULL == keys_json)
    1317             :   {
    1318           0 :     GNUNET_break (0);
    1319           0 :     return GNUNET_SYSERR;
    1320             :   }
    1321             :   /* Keep copy for later compression... */
    1322          17 :   keys_jsonz = GNUNET_strdup (keys_json);
    1323          17 :   keys_jsonz_size = strlen (keys_json);
    1324             : 
    1325             :   /* Create uncompressed response */
    1326             :   krd->response_uncompressed
    1327          17 :     = MHD_create_response_from_buffer (keys_jsonz_size,
    1328             :                                        keys_json,
    1329             :                                        MHD_RESPMEM_MUST_FREE);
    1330          17 :   if (NULL == krd->response_uncompressed)
    1331             :   {
    1332           0 :     GNUNET_break (0);
    1333           0 :     GNUNET_free (keys_json);
    1334           0 :     GNUNET_free (keys_jsonz);
    1335           0 :     return GNUNET_SYSERR;
    1336             :   }
    1337          17 :   if (GNUNET_OK !=
    1338          17 :       setup_general_response_headers (rfc->key_state,
    1339             :                                       krd->response_uncompressed))
    1340             :   {
    1341           0 :     GNUNET_break (0);
    1342           0 :     GNUNET_free (keys_jsonz);
    1343           0 :     return GNUNET_SYSERR;
    1344             :   }
    1345             : 
    1346             :   /* Also compute compressed version of /keys response */
    1347          17 :   comp = TEH_RESPONSE_body_compress (&keys_jsonz,
    1348             :                                      &keys_jsonz_size);
    1349             :   krd->response_compressed
    1350          17 :     = MHD_create_response_from_buffer (keys_jsonz_size,
    1351             :                                        keys_jsonz,
    1352             :                                        MHD_RESPMEM_MUST_FREE);
    1353          17 :   if (NULL == krd->response_compressed)
    1354             :   {
    1355           0 :     GNUNET_break (0);
    1356           0 :     GNUNET_free (keys_jsonz);
    1357           0 :     return GNUNET_SYSERR;
    1358             :   }
    1359             :   /* If the response is actually compressed, set the
    1360             :      respective header. */
    1361          34 :   if ( (MHD_YES == comp) &&
    1362             :        (MHD_YES !=
    1363          17 :         MHD_add_response_header (krd->response_compressed,
    1364             :                                  MHD_HTTP_HEADER_CONTENT_ENCODING,
    1365             :                                  "deflate")) )
    1366             :   {
    1367           0 :     GNUNET_break (0);
    1368           0 :     return GNUNET_SYSERR;
    1369             :   }
    1370          17 :   if (GNUNET_OK !=
    1371          17 :       setup_general_response_headers (rfc->key_state,
    1372             :                                       krd->response_compressed))
    1373             :   {
    1374           0 :     GNUNET_break (0);
    1375           0 :     return GNUNET_SYSERR;
    1376             :   }
    1377          17 :   return GNUNET_OK;
    1378             : }
    1379             : 
    1380             : 
    1381             : /**
    1382             :  * Actual "main" logic that builds the state which this module
    1383             :  * evolves around.  This function will import the key data from
    1384             :  * the exchangedb module and convert it into (1) internally used
    1385             :  * lookup tables, and (2) HTTP responses to be returned from
    1386             :  * /keys.
    1387             :  *
    1388             :  * @return NULL on error (usually pretty fatal...)
    1389             :  */
    1390             : static struct TEH_KS_StateHandle *
    1391           6 : make_fresh_key_state ()
    1392             : {
    1393             :   struct TEH_KS_StateHandle *key_state;
    1394             :   struct ResponseFactoryContext rfc;
    1395             :   struct GNUNET_TIME_Absolute last;
    1396             :   unsigned int off;
    1397             : 
    1398           6 :   memset (&rfc,
    1399             :           0,
    1400             :           sizeof (rfc));
    1401           6 :   rfc.payback_array = json_array ();
    1402           6 :   if (NULL == rfc.payback_array)
    1403             :   {
    1404           0 :     GNUNET_break (0);
    1405           0 :     return NULL;
    1406             :   }
    1407           6 :   rfc.sign_keys_array = json_array ();
    1408           6 :   if (NULL == rfc.sign_keys_array)
    1409             :   {
    1410           0 :     GNUNET_break (0);
    1411           0 :     json_decref (rfc.payback_array);
    1412           0 :     return NULL;
    1413             :   }
    1414             : 
    1415           6 :   key_state = GNUNET_new (struct TEH_KS_StateHandle);
    1416           6 :   rfc.key_state = key_state;
    1417           6 :   key_state->min_dk_expire = GNUNET_TIME_UNIT_FOREVER_ABS;
    1418           6 :   key_state->denomkey_map = GNUNET_CONTAINER_multihashmap_create (32,
    1419             :                                                                   GNUNET_NO);
    1420           6 :   key_state->revoked_map = GNUNET_CONTAINER_multihashmap_create (4,
    1421             :                                                                  GNUNET_NO);
    1422           6 :   key_state->reload_time = GNUNET_TIME_absolute_get ();
    1423           6 :   GNUNET_TIME_round_abs (&key_state->reload_time);
    1424             : 
    1425           6 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1426             :               "Loading keys from `%s'\n",
    1427             :               TEH_exchange_directory);
    1428             :   /* Initialize the 'denomkey_map' and the 'revoked_map' and
    1429             :      'rfc.payback_array' */
    1430           6 :   if (-1 ==
    1431           6 :       TALER_EXCHANGEDB_denomination_keys_iterate (TEH_exchange_directory,
    1432             :                                                   &TEH_master_public_key,
    1433             :                                                   &reload_keys_denom_iter,
    1434             :                                                   &rfc))
    1435             :   {
    1436           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1437             :                 "Failed to load denomination keys from `%s'.\n",
    1438             :                 TEH_exchange_directory);
    1439           0 :     key_state->refcnt = 1;
    1440           0 :     ks_release (key_state);
    1441           0 :     json_decref (rfc.payback_array);
    1442           0 :     json_decref (rfc.sign_keys_array);
    1443           0 :     return NULL;
    1444             :   }
    1445           6 :   if (0 == GNUNET_CONTAINER_multihashmap_size (key_state->denomkey_map))
    1446             :   {
    1447           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1448             :                 "Have no denomination keys. Bad configuration.\n");
    1449           0 :     key_state->refcnt = 1;
    1450           0 :     ks_release (key_state);
    1451           0 :     destroy_response_factory (&rfc);
    1452           0 :     return NULL;
    1453             :   }
    1454             : 
    1455             :   /* Initialize `current_sign_key_issue` and `rfc.sign_keys_array` */
    1456           6 :   TALER_EXCHANGEDB_signing_keys_iterate (TEH_exchange_directory,
    1457             :                                          &reload_keys_sign_iter,
    1458             :                                          &rfc);
    1459           6 :   if (0 !=
    1460           6 :       memcmp (&key_state->current_sign_key_issue.issue.master_public_key,
    1461             :               &TEH_master_public_key,
    1462             :               sizeof (struct TALER_MasterPublicKeyP)))
    1463             :   {
    1464           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1465             :                 "Have no signing key. Bad configuration.\n");
    1466           0 :     key_state->refcnt = 1;
    1467           0 :     ks_release (key_state);
    1468           0 :     destroy_response_factory (&rfc);
    1469           0 :     return NULL;
    1470             :   }
    1471             : 
    1472             :   /* Initialize and sort the `denomkey_array` */
    1473             :   rfc.denomkey_array
    1474           6 :     = GNUNET_new_array (GNUNET_CONTAINER_multihashmap_size (key_state->denomkey_map),
    1475             :                         struct DenominationKeyEntry);
    1476           6 :   GNUNET_CONTAINER_multihashmap_iterate (key_state->denomkey_map,
    1477             :                                          &initialize_denomkey_array,
    1478             :                                          &rfc);
    1479           6 :   GNUNET_assert (rfc.denomkey_array_length ==
    1480             :                  GNUNET_CONTAINER_multihashmap_size (key_state->denomkey_map));
    1481           6 :   qsort (rfc.denomkey_array,
    1482           6 :          rfc.denomkey_array_length,
    1483             :          sizeof (struct DenominationKeyEntry),
    1484             :          &denomkey_array_sort_comparator);
    1485             : 
    1486             :   /* Complete `denomkey_array` by adding auditor signature data */
    1487           6 :   TALER_EXCHANGEDB_auditor_iterate (cfg,
    1488             :                                     &reload_auditor_iter,
    1489             :                                     &rfc);
    1490             :   /* Sanity check: do we have auditors for all denomination keys? */
    1491          34 :   for (unsigned int i=0;i<rfc.denomkey_array_length;i++)
    1492             :   {
    1493          28 :     const struct DenominationKeyEntry *dke
    1494          28 :       = &rfc.denomkey_array[i];
    1495             : 
    1496          28 :     if (NULL == dke->as_head)
    1497           4 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1498             :                   "Denomination key `%s' at %p not signed by any auditor!\n",
    1499             :                   GNUNET_h2s (&dke->denom_key_hash),
    1500             :                   dke);
    1501             :   }
    1502             :   
    1503             :   /* Determine size of `krd_array` by counting number of discrete
    1504             :      denomination key starting times. */
    1505           6 :   last = GNUNET_TIME_UNIT_ZERO_ABS;
    1506           6 :   key_state->krd_array_length = 0;
    1507           6 :   off = 1; /* reserve one slot for the "no keys" response */
    1508          34 :   for (unsigned int i=0;i<rfc.denomkey_array_length;i++)
    1509             :   {
    1510          28 :     const struct DenominationKeyEntry *dke
    1511          28 :       = &rfc.denomkey_array[i];
    1512          28 :     struct GNUNET_TIME_Absolute d
    1513          28 :       = GNUNET_TIME_absolute_ntoh (dke->dki->issue.properties.start);
    1514             : 
    1515          28 :     if (last.abs_value_us == d.abs_value_us)
    1516          17 :       continue;
    1517          11 :     last = d;
    1518          11 :     off++;
    1519             :   }
    1520             : 
    1521             :   /* Compute next automatic reload time */
    1522           6 :   key_state->next_reload =
    1523           6 :     GNUNET_TIME_absolute_min (GNUNET_TIME_absolute_ntoh (key_state->current_sign_key_issue.issue.expire),
    1524             :                               key_state->min_dk_expire);
    1525           6 :   GNUNET_assert (0 != key_state->next_reload.abs_value_us);
    1526             : 
    1527             : 
    1528             :   /* Initialize `krd_array` */
    1529           6 :   key_state->krd_array_length = off;
    1530             :   key_state->krd_array
    1531           6 :     = GNUNET_new_array (key_state->krd_array_length,
    1532             :                         struct KeysResponseData);
    1533           6 :   off = 0;
    1534           6 :   last = GNUNET_TIME_UNIT_ZERO_ABS;
    1535          34 :   for (unsigned int i=0;i<rfc.denomkey_array_length;i++)
    1536             :   {
    1537          28 :     const struct DenominationKeyEntry *dke
    1538          28 :       = &rfc.denomkey_array[i];
    1539          28 :     struct GNUNET_TIME_Absolute d
    1540          28 :       = GNUNET_TIME_absolute_ntoh (dke->dki->issue.properties.start);
    1541             : 
    1542          28 :     if (last.abs_value_us == d.abs_value_us)
    1543          17 :       continue;
    1544          11 :     if (GNUNET_OK !=
    1545          11 :         build_keys_response (&rfc,
    1546          11 :                              &key_state->krd_array[off++],
    1547             :                              i,
    1548             :                              last))
    1549             :     {
    1550             :       /* Fail hard, will be caught via test on `off` below */
    1551           0 :       GNUNET_break (0);
    1552           0 :       off = key_state->krd_array_length; /* flag as 'invalid' */
    1553           0 :       break;
    1554             :     }
    1555          11 :     last = d;
    1556             :   }
    1557             : 
    1558             :   /* Finally, build an `empty` response without denomination keys
    1559             :      for requests past the last known denomination key start date */
    1560          12 :   if ( (off + 1 < key_state->krd_array_length) ||
    1561             :        (GNUNET_OK !=
    1562          12 :         build_keys_response (&rfc,
    1563           6 :                              &key_state->krd_array[off++],
    1564             :                              rfc.denomkey_array_length,
    1565             :                              last)) )
    1566             :   {
    1567           0 :     GNUNET_break (0);
    1568           0 :     key_state->refcnt = 1;
    1569           0 :     ks_release (key_state);
    1570           0 :     destroy_response_factory (&rfc);
    1571           0 :     return NULL;
    1572             :   }
    1573             : 
    1574             :   /* Clean up intermediary state we don't need anymore and return
    1575             :      new key_state! */
    1576           6 :   destroy_response_factory (&rfc);
    1577           6 :   return key_state;
    1578             : }
    1579             : 
    1580             : 
    1581             : /* ************************** Persistent part ********************** */
    1582             : 
    1583             : /**
    1584             :  * Exchange key state.  This is the long-term, read-only internal global state,
    1585             :  * which the various threads "lock" to use in read-only ways.  We eventually
    1586             :  * create a completely new object "on the side" and then start to return
    1587             :  * the new read-only object to threads that ask. Once none of the threads
    1588             :  * use the previous object (RC drops to zero), we discard it.
    1589             :  *
    1590             :  * Thus, this instance should never be used directly, instead reserve
    1591             :  * access via #TEH_KS_acquire() and release it via #TEH_KS_release().
    1592             :  */
    1593             : static struct TEH_KS_StateHandle *internal_key_state;
    1594             : 
    1595             : /**
    1596             :  * Mutex protecting access to #internal_key_state.
    1597             :  */
    1598             : static pthread_mutex_t internal_key_state_mutex = PTHREAD_MUTEX_INITIALIZER;
    1599             : 
    1600             : 
    1601             : 
    1602             : /**
    1603             :  * Release key state, free if necessary (if reference count gets to zero).
    1604             :  *
    1605             :  * @param location name of the function in which the lock is acquired
    1606             :  * @param key_state the key state to release
    1607             :  */
    1608             : void
    1609          65 : TEH_KS_release_ (const char *location,
    1610             :                  struct TEH_KS_StateHandle *key_state)
    1611             : {
    1612          65 :   GNUNET_assert (0 == pthread_mutex_lock (&internal_key_state_mutex));
    1613          65 :   ks_release (key_state);
    1614          65 :   GNUNET_assert (0 == pthread_mutex_unlock (&internal_key_state_mutex));
    1615          65 : }
    1616             : 
    1617             : 
    1618             : /**
    1619             :  * Acquire the key state of the exchange.  Updates keys if necessary.
    1620             :  * For every call to #TEH_KS_acquire(), a matching call
    1621             :  * to #TEH_KS_release() must be made.
    1622             :  *
    1623             :  * @param location name of the function in which the lock is acquired
    1624             :  * @return the key state, NULL on error (usually pretty fatal)
    1625             :  */
    1626             : struct TEH_KS_StateHandle *
    1627          65 : TEH_KS_acquire_ (const char *location)
    1628             : {
    1629          65 :   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
    1630             :   struct TEH_KS_StateHandle *key_state;
    1631             : 
    1632          65 :   GNUNET_assert (0 == pthread_mutex_lock (&internal_key_state_mutex));
    1633         124 :   if ( (NULL != internal_key_state) &&
    1634          59 :        (internal_key_state->next_reload.abs_value_us <= now.abs_value_us) )
    1635             :   {
    1636           0 :     ks_release (internal_key_state);
    1637           0 :     internal_key_state = NULL;
    1638             :   }
    1639          65 :   if (NULL == internal_key_state)
    1640           6 :     internal_key_state = make_fresh_key_state ();
    1641          65 :   key_state = internal_key_state;
    1642          65 :   if (NULL != key_state)
    1643          65 :     key_state->refcnt++;
    1644          65 :   GNUNET_assert (0 == pthread_mutex_unlock (&internal_key_state_mutex));
    1645             : 
    1646          65 :   return key_state;
    1647             : }
    1648             : 
    1649             : 
    1650             : /**
    1651             :  * Look up the issue for a denom public key.
    1652             :  *
    1653             :  * @param key_state state to look in
    1654             :  * @param denom_pub denomination public key
    1655             :  * @param use purpose for which the key is being located
    1656             :  * @return the denomination key issue,
    1657             :  *         or NULL if denom_pub could not be found
    1658             :  */
    1659             : struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *
    1660         104 : TEH_KS_denomination_key_lookup (const struct TEH_KS_StateHandle *key_state,
    1661             :                                 const struct TALER_DenominationPublicKey *denom_pub,
    1662             :                                 enum TEH_KS_DenominationKeyUse use)
    1663             : {
    1664             :   struct GNUNET_HashCode hc;
    1665             :   struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
    1666             :   struct GNUNET_TIME_Absolute now;
    1667             :   const struct GNUNET_CONTAINER_MultiHashMap *map;
    1668             : 
    1669         104 :   GNUNET_CRYPTO_rsa_public_key_hash (denom_pub->rsa_public_key,
    1670             :                                      &hc);
    1671         104 :   map = (TEH_KS_DKU_PAYBACK == use) ? key_state->revoked_map : key_state->denomkey_map;
    1672         104 :   dki = GNUNET_CONTAINER_multihashmap_get (map,
    1673             :                                            &hc);
    1674         104 :   if (NULL == dki)
    1675           3 :     return NULL;
    1676         101 :   now = GNUNET_TIME_absolute_get ();
    1677         202 :   if (now.abs_value_us <
    1678         101 :       GNUNET_TIME_absolute_ntoh (dki->issue.properties.start).abs_value_us)
    1679             :   {
    1680           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1681             :                 "Not returning DKI for %s, as start time is in the future\n",
    1682             :                 GNUNET_h2s (&hc));
    1683           0 :     return NULL;
    1684             :   }
    1685         101 :   now = GNUNET_TIME_absolute_get ();
    1686         101 :   switch (use)
    1687             :   {
    1688             :   case TEH_KS_DKU_WITHDRAW:
    1689         150 :     if (now.abs_value_us >
    1690          75 :         GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_withdraw).abs_value_us)
    1691             :     {
    1692           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1693             :                   "Not returning DKI for %s, as time to create coins has passed\n",
    1694             :                   GNUNET_h2s (&hc));
    1695           0 :       return NULL;
    1696             :     }
    1697          75 :     break;
    1698             :   case TEH_KS_DKU_DEPOSIT:
    1699          46 :     if (now.abs_value_us >
    1700          23 :         GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_deposit).abs_value_us)
    1701             :     {
    1702           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1703             :                   "Not returning DKI for %s, as time to spend coin has passed\n",
    1704             :                   GNUNET_h2s (&hc));
    1705           0 :       return NULL;
    1706             :     }
    1707          23 :     break;
    1708             :   case TEH_KS_DKU_PAYBACK:
    1709           6 :     if (now.abs_value_us >
    1710           3 :         GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_deposit).abs_value_us)
    1711             :     {
    1712           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1713             :                   "Not returning DKI for %s, as time to payback coin has passed\n",
    1714             :                   GNUNET_h2s (&hc));
    1715           0 :       return NULL;
    1716             :     }
    1717           3 :     break;
    1718             :   }
    1719         101 :   return dki;
    1720             : }
    1721             : 
    1722             : 
    1723             : /**
    1724             :  * Call #handle_signal() to pass the received signal via
    1725             :  * the control pipe.
    1726             :  */
    1727             : static void
    1728           4 : handle_sigusr1 ()
    1729             : {
    1730           4 :   handle_signal (SIGUSR1);
    1731           4 : }
    1732             : 
    1733             : 
    1734             : /**
    1735             :  * Call #handle_signal() to pass the received signal via
    1736             :  * the control pipe.
    1737             :  */
    1738             : static void
    1739           0 : handle_sigint ()
    1740             : {
    1741           0 :   handle_signal (SIGINT);
    1742           0 : }
    1743             : 
    1744             : 
    1745             : /**
    1746             :  * Call #handle_signal() to pass the received signal via
    1747             :  * the control pipe.
    1748             :  */
    1749             : static void
    1750           2 : handle_sigterm ()
    1751             : {
    1752           2 :   handle_signal (SIGTERM);
    1753           2 : }
    1754             : 
    1755             : 
    1756             : /**
    1757             :  * Call #handle_signal() to pass the received signal via
    1758             :  * the control pipe.
    1759             :  */
    1760             : static void
    1761           0 : handle_sighup ()
    1762             : {
    1763           0 :   handle_signal (SIGHUP);
    1764           0 : }
    1765             : 
    1766             : 
    1767             : /**
    1768             :  * Call #handle_signal() to pass the received signal via
    1769             :  * the control pipe.
    1770             :  */
    1771             : static void
    1772           0 : handle_sigchld ()
    1773             : {
    1774           0 :   handle_signal (SIGCHLD);
    1775           0 : }
    1776             : 
    1777             : 
    1778             : /**
    1779             :  * Read signals from a pipe in a loop, and reload keys from disk if
    1780             :  * SIGUSR1 is received, terminate if SIGTERM/SIGINT is received, and
    1781             :  * restart if SIGHUP is received.
    1782             :  *
    1783             :  * @return #GNUNET_SYSERR on errors,
    1784             :  *         #GNUNET_OK to terminate normally
    1785             :  *         #GNUNET_NO to restart an update version of the binary
    1786             :  */
    1787             : int
    1788           2 : TEH_KS_loop (void)
    1789             : {
    1790             :   struct GNUNET_SIGNAL_Context *sigusr1;
    1791             :   struct GNUNET_SIGNAL_Context *sigterm;
    1792             :   struct GNUNET_SIGNAL_Context *sigint;
    1793             :   struct GNUNET_SIGNAL_Context *sighup;
    1794             :   struct GNUNET_SIGNAL_Context *sigchld;
    1795             :   int ret;
    1796             : 
    1797           2 :   if (0 != pipe (reload_pipe))
    1798             :   {
    1799           0 :     fprintf (stderr,
    1800             :              "Failed to create pipe.\n");
    1801           0 :     return GNUNET_SYSERR;
    1802             :   }
    1803           2 :   sigusr1 = GNUNET_SIGNAL_handler_install (SIGUSR1,
    1804             :                                            &handle_sigusr1);
    1805           2 :   sigterm = GNUNET_SIGNAL_handler_install (SIGTERM,
    1806             :                                            &handle_sigterm);
    1807           2 :   sigint = GNUNET_SIGNAL_handler_install (SIGINT,
    1808             :                                           &handle_sigint);
    1809           2 :   sighup = GNUNET_SIGNAL_handler_install (SIGHUP,
    1810             :                                           &handle_sighup);
    1811           2 :   sigchld = GNUNET_SIGNAL_handler_install (SIGCHLD,
    1812             :                                            &handle_sigchld);
    1813             : 
    1814           2 :   ret = 2;
    1815          10 :   while (2 == ret)
    1816             :   {
    1817             :     char c;
    1818             :     ssize_t res;
    1819             : 
    1820           6 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1821             :                 "(re-)loading keys\n");
    1822           6 :     if (NULL != internal_key_state)
    1823             :     {
    1824           4 :       TEH_KS_release (internal_key_state);
    1825           4 :       internal_key_state = NULL;
    1826             :     }
    1827             :     /* This will re-initialize 'internal_key_state' with
    1828             :        an initial refcnt of 1 */
    1829           6 :     if (NULL == TEH_KS_acquire ())
    1830             :     {
    1831           0 :       ret = GNUNET_SYSERR;
    1832           0 :       break;
    1833             :     }
    1834             : read_again:
    1835          12 :     errno = 0;
    1836          12 :     res = read (reload_pipe[0],
    1837             :                 &c,
    1838             :                 1);
    1839          12 :     if ((res < 0) && (EINTR != errno))
    1840             :     {
    1841           0 :       GNUNET_break (0);
    1842           0 :       ret = GNUNET_SYSERR;
    1843           0 :       break;
    1844             :     }
    1845          12 :     if (EINTR == errno)
    1846           6 :       goto read_again;
    1847           6 :     switch (c)
    1848             :     {
    1849             :     case SIGUSR1:
    1850             :       /* reload internal key state, we do this in the loop */
    1851           4 :       break;
    1852             :     case SIGTERM:
    1853             :     case SIGINT:
    1854             :       /* terminate */
    1855           2 :       ret = GNUNET_OK;
    1856           2 :       break;
    1857             :     case SIGHUP:
    1858             :       /* restart updated binary */
    1859           0 :       ret = GNUNET_NO;
    1860           0 :       break;
    1861             : #if HAVE_DEVELOPER
    1862             :     case SIGCHLD:
    1863             :       /* running in test-mode, test finished, terminate */
    1864           0 :       ret = GNUNET_OK;
    1865           0 :       break;
    1866             : #endif
    1867             :     default:
    1868             :       /* unexpected character */
    1869           0 :       GNUNET_break (0);
    1870           0 :       break;
    1871             :     }
    1872             :   }
    1873           2 :   if (NULL != internal_key_state)
    1874             :   {
    1875           2 :     TEH_KS_release (internal_key_state);
    1876           2 :     internal_key_state = NULL;
    1877             :   }
    1878           2 :   GNUNET_SIGNAL_handler_uninstall (sigusr1);
    1879           2 :   GNUNET_SIGNAL_handler_uninstall (sigterm);
    1880           2 :   GNUNET_SIGNAL_handler_uninstall (sigint);
    1881           2 :   GNUNET_SIGNAL_handler_uninstall (sighup);
    1882           2 :   GNUNET_SIGNAL_handler_uninstall (sigchld);
    1883           2 :   return ret;
    1884             : }
    1885             : 
    1886             : 
    1887             : /**
    1888             :  * Sign the message in @a purpose with the exchange's signing key.
    1889             :  *
    1890             :  * FIXME:
    1891             :  * - Change API to return status code and do not assert on TEH_KS_acquire()
    1892             :  *   failures, instead allow caller to handle it (i.e. by returning
    1893             :  *   #TALER_EC_EXCHANGE_BAD_CONFIGURATION to application).
    1894             :  *
    1895             :  * @param purpose the message to sign
    1896             :  * @param[out] pub set to the current public signing key of the exchange
    1897             :  * @param[out] sig signature over purpose using current signing key
    1898             :  * @return #GNUNET_OK on success, #GNUNET_SYSERR if we lack key material
    1899             :  */
    1900             : int
    1901          16 : TEH_KS_sign (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
    1902             :              struct TALER_ExchangePublicKeyP *pub,
    1903             :              struct TALER_ExchangeSignatureP *sig)
    1904             : 
    1905             : {
    1906             :   struct TEH_KS_StateHandle *key_state;
    1907             : 
    1908          16 :   key_state = TEH_KS_acquire ();
    1909          16 :   if (NULL == key_state)
    1910             :   {
    1911             :     /* This *can* happen if the exchange's keys are
    1912             :        not properly maintained. */
    1913           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1914             :                 _("Cannot sign request, no valid keys available\n"));
    1915           0 :     return GNUNET_SYSERR;
    1916             :   }
    1917          16 :   *pub = key_state->current_sign_key_issue.issue.signkey_pub;
    1918          16 :   GNUNET_assert (GNUNET_OK ==
    1919             :                  GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv.eddsa_priv,
    1920             :                                            purpose,
    1921             :                                            &sig->eddsa_signature));
    1922          16 :   TEH_KS_release (key_state);
    1923          16 :   return GNUNET_OK;
    1924             : }
    1925             : 
    1926             : 
    1927             : /**
    1928             :  * Comparator used for a binary search for @a key in the
    1929             :  * `struct KeysResponseData` array.
    1930             :  *
    1931             :  * @param key pointer to a `struct GNUNET_TIME_Absolute`
    1932             :  * @param value pointer to a `struct KeysResponseData` array entry
    1933             :  * @return 0 if time matches, -1 if key is smaller, 1 if key is larger
    1934             :  */
    1935             : static int
    1936           9 : krd_search_comparator (const void *key,
    1937             :                        const void *value)
    1938             : {
    1939           9 :   const struct GNUNET_TIME_Absolute *kd = key;
    1940           9 :   const struct KeysResponseData *krd = value;
    1941             : 
    1942           9 :   if (kd->abs_value_us > krd->cherry_pick_date.abs_value_us)
    1943           0 :     return 1;
    1944           9 :   if (kd->abs_value_us < krd->cherry_pick_date.abs_value_us)
    1945           4 :     return -1;
    1946           5 :   return 0;
    1947             : }
    1948             : 
    1949             : 
    1950             : /**
    1951             :  * Function to call to handle the request by sending
    1952             :  * back static data from the @a rh.
    1953             :  *
    1954             :  * @param rh context of the handler
    1955             :  * @param connection the MHD connection to handle
    1956             :  * @param[in,out] connection_cls the connection's closure (can be updated)
    1957             :  * @param upload_data upload data
    1958             :  * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
    1959             :  * @return MHD result code
    1960             :  */
    1961             : int
    1962           5 : TEH_KS_handler_keys (struct TEH_RequestHandler *rh,
    1963             :                      struct MHD_Connection *connection,
    1964             :                      void **connection_cls,
    1965             :                      const char *upload_data,
    1966             :                      size_t *upload_data_size)
    1967             : {
    1968             :   struct TEH_KS_StateHandle *key_state;
    1969             :   int ret;
    1970             :   const char *have;
    1971             :   struct GNUNET_TIME_Absolute last_issue_date;
    1972             :   const struct KeysResponseData *krd;
    1973             : 
    1974           5 :   have = MHD_lookup_connection_value (connection,
    1975             :                                       MHD_GET_ARGUMENT_KIND,
    1976             :                                       "last_issue_date");
    1977           5 :   if (NULL != have)
    1978             :   {
    1979             :     unsigned long long haven;
    1980             : 
    1981           1 :     if (1 !=
    1982           1 :         sscanf (have,
    1983             :                 "%llu",
    1984             :                 &haven))
    1985             :     {
    1986           0 :       GNUNET_break_op (0);
    1987           0 :       return TEH_RESPONSE_reply_arg_invalid (connection,
    1988             :                                              TALER_EC_KEYS_HAVE_NOT_NUMERIC,
    1989             :                                              "have");
    1990             :     }
    1991           1 :     last_issue_date.abs_value_us = (uint64_t) haven * 1000000LLU;
    1992             :   }
    1993             :   else
    1994             :   {
    1995           4 :     last_issue_date.abs_value_us = 0LLU;
    1996             :   }
    1997           5 :   key_state = TEH_KS_acquire ();
    1998           5 :   if (NULL == key_state)
    1999             :   {
    2000           0 :     TALER_LOG_ERROR ("Lacking keys to operate\n");
    2001           0 :     return TEH_RESPONSE_reply_internal_error (connection,
    2002             :                                               TALER_EC_EXCHANGE_BAD_CONFIGURATION,
    2003             :                                               "no keys");
    2004             :   }
    2005          10 :   krd = bsearch (&last_issue_date,
    2006           5 :                  key_state->krd_array,
    2007           5 :                  key_state->krd_array_length,
    2008             :                  sizeof (struct KeysResponseData),
    2009             :                  &krd_search_comparator);
    2010           5 :   if ( (NULL == krd) &&
    2011           0 :        (key_state->krd_array_length > 0) )
    2012             :   {
    2013           0 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2014             :                 "Client provided invalid cherry picking timestamp %s, returning full response\n",
    2015             :                 GNUNET_STRINGS_absolute_time_to_string (last_issue_date));
    2016           0 :     krd = &key_state->krd_array[0];
    2017             :   }
    2018           5 :   if (NULL == krd)
    2019             :   {
    2020             :     /* FIXME: should return 500 response instead... */
    2021           0 :     GNUNET_break (0);
    2022           0 :     return MHD_NO;
    2023             :   }
    2024          10 :   ret = MHD_queue_response (connection,
    2025           5 :                             rh->response_code,
    2026           5 :                             (MHD_YES == TEH_RESPONSE_can_compress (connection))
    2027             :                             ? krd->response_compressed
    2028             :                             : krd->response_uncompressed);
    2029           5 :   TEH_KS_release (key_state);
    2030           5 :   return ret;
    2031             : }
    2032             : 
    2033             : 
    2034             : /* end of taler-exchange-httpd_keystate.c */

Generated by: LCOV version 1.13