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

Generated by: LCOV version 1.13