LCOV - code coverage report
Current view: top level - util - secmod_cs.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 77.2 % 821 634
Test Date: 2026-09-11 18:55:36 Functions: 95.1 % 41 39

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2014-2026 Taler Systems SA
       4              : 
       5              :   TALER is free software; you can redistribute it and/or modify it under the
       6              :   terms of the GNU 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 General Public License for more details.
      12              : 
      13              :   You should have received a copy of the GNU General Public License along with
      14              :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15              : */
      16              : /**
      17              :  * @file util/secmod_cs.c
      18              :  * @brief Standalone process to perform private key CS operations
      19              :  * @author Christian Grothoff
      20              :  *
      21              :  * Key design points:
      22              :  * - EVERY thread of the exchange will have its own pair of connections to the
      23              :  *   crypto helpers.  This way, every thread will also have its own /keys state
      24              :  *   and avoid the need to synchronize on those.
      25              :  * - auditor signatures and master signatures are to be kept in the exchange DB,
      26              :  *   and merged with the public keys of the helper by the exchange HTTPD!
      27              :  * - the main loop of the helper is SINGLE-THREADED, but there are
      28              :  *   threads for crypto-workers which do the signing in parallel, one per client.
      29              :  * - thread-safety: signing happens in parallel, thus when REMOVING private keys,
      30              :  *   we must ensure that all signers are done before we fully free() the
      31              :  *   private key. This is done by reference counting (as work is always
      32              :  *   assigned and collected by the main thread).
      33              :  */
      34              : #include "platform.h"
      35              : #include "taler/taler_util.h"
      36              : #include "secmod_cs.h"
      37              : #include <gcrypt.h>
      38              : #include <pthread.h>
      39              : #include <sys/eventfd.h>
      40              : #include "taler/taler_error_codes.h"
      41              : #include "taler/taler_signatures.h"
      42              : #include "secmod_common.h"
      43              : #include <poll.h>
      44              : 
      45              : 
      46              : /**
      47              :  * Information we keep per denomination.
      48              :  */
      49              : struct Denomination;
      50              : 
      51              : 
      52              : /**
      53              :  * One particular denomination key.
      54              :  */
      55              : struct DenominationKey
      56              : {
      57              : 
      58              :   /**
      59              :    * Kept in a DLL of the respective denomination. Sorted by anchor time.
      60              :    */
      61              :   struct DenominationKey *next;
      62              : 
      63              :   /**
      64              :    * Kept in a DLL of the respective denomination. Sorted by anchor time.
      65              :    */
      66              :   struct DenominationKey *prev;
      67              : 
      68              :   /**
      69              :    * Denomination this key belongs to.
      70              :    */
      71              :   struct Denomination *denom;
      72              : 
      73              :   /**
      74              :    * Name of the file this key is stored under.
      75              :    */
      76              :   char *filename;
      77              : 
      78              :   /**
      79              :    * The private key of the denomination.
      80              :    */
      81              :   struct GNUNET_CRYPTO_CsPrivateKey denom_priv;
      82              : 
      83              :   /**
      84              :    * The public key of the denomination.
      85              :    */
      86              :   struct GNUNET_CRYPTO_CsPublicKey denom_pub;
      87              : 
      88              :   /**
      89              :    * Message to transmit to clients to introduce this public key.
      90              :    */
      91              :   struct TALER_CRYPTO_CsKeyAvailableNotification *an;
      92              : 
      93              :   /**
      94              :    * Hash of this denomination's public key.
      95              :    */
      96              :   struct TALER_CsPubHashP h_cs;
      97              : 
      98              :   /**
      99              :    * Time at which this key is supposed to become valid.
     100              :    */
     101              :   struct GNUNET_TIME_Timestamp anchor_start;
     102              : 
     103              :   /**
     104              :    * Time at which this key is supposed to expire (exclusive).
     105              :    */
     106              :   struct GNUNET_TIME_Timestamp anchor_end;
     107              : 
     108              :   /**
     109              :    * Generation when this key was created or revoked.
     110              :    */
     111              :   uint64_t key_gen;
     112              : 
     113              :   /**
     114              :    * Reference counter. Counts the number of threads that are
     115              :    * using this key at this time.
     116              :    */
     117              :   unsigned int rc;
     118              : 
     119              :   /**
     120              :    * Flag set to true if this key has been purged and the memory
     121              :    * must be freed as soon as @e rc hits zero.
     122              :    */
     123              :   bool purge;
     124              : 
     125              : };
     126              : 
     127              : 
     128              : struct Denomination
     129              : {
     130              : 
     131              :   /**
     132              :    * Kept in a DLL. Sorted by #denomination_action_time().
     133              :    */
     134              :   struct Denomination *next;
     135              : 
     136              :   /**
     137              :    * Kept in a DLL. Sorted by #denomination_action_time().
     138              :    */
     139              :   struct Denomination *prev;
     140              : 
     141              :   /**
     142              :    * Head of DLL of actual keys of this denomination.
     143              :    */
     144              :   struct DenominationKey *keys_head;
     145              : 
     146              :   /**
     147              :    * Tail of DLL of actual keys of this denomination.
     148              :    */
     149              :   struct DenominationKey *keys_tail;
     150              : 
     151              :   /**
     152              :    * How long can coins be withdrawn (generated)?  Should be small
     153              :    * enough to limit how many coins will be signed into existence with
     154              :    * the same key, but large enough to still provide a reasonable
     155              :    * anonymity set.
     156              :    */
     157              :   struct GNUNET_TIME_Relative duration_withdraw;
     158              : 
     159              :   /**
     160              :    * Calendar interval the start of the validity period of our keys is
     161              :    * rounded down to (and the end of the validity period rounded up to).
     162              :    * #GNUNET_TIME_RI_NONE (the default) disables the rounding.  Donau sets
     163              :    * this to #GNUNET_TIME_RI_YEAR so that its keys are valid for exactly one
     164              :    * calendar year (starting January 1st UTC), even if the key was generated
     165              :    * in the middle of the year.
     166              :    */
     167              :   enum GNUNET_TIME_RounderInterval anchor_round;
     168              : 
     169              :   /**
     170              :    * What is the configuration section of this denomination type?  Also used
     171              :    * for the directory name where the denomination keys are stored.
     172              :    */
     173              :   char *section;
     174              : 
     175              : };
     176              : 
     177              : 
     178              : /**
     179              :  * A semaphore.
     180              :  */
     181              : struct Semaphore
     182              : {
     183              :   /**
     184              :    * Mutex for the semaphore.
     185              :    */
     186              :   pthread_mutex_t mutex;
     187              : 
     188              :   /**
     189              :    * Condition variable for the semaphore.
     190              :    */
     191              :   pthread_cond_t cv;
     192              : 
     193              :   /**
     194              :    * Counter of the semaphore.
     195              :    */
     196              :   unsigned int ctr;
     197              : };
     198              : 
     199              : 
     200              : /**
     201              :  * Job in a batch sign request.
     202              :  */
     203              : struct BatchJob;
     204              : 
     205              : /**
     206              :  * Handle for a thread that does work in batch signing.
     207              :  */
     208              : struct Worker
     209              : {
     210              :   /**
     211              :    * Kept in a DLL.
     212              :    */
     213              :   struct Worker *prev;
     214              : 
     215              :   /**
     216              :    * Kept in a DLL.
     217              :    */
     218              :   struct Worker *next;
     219              : 
     220              :   /**
     221              :    * Job this worker should do next.
     222              :    */
     223              :   struct BatchJob *job;
     224              : 
     225              :   /**
     226              :    * Semaphore to signal the worker that a job is available.
     227              :    */
     228              :   struct Semaphore sem;
     229              : 
     230              :   /**
     231              :    * Handle for this thread.
     232              :    */
     233              :   pthread_t pt;
     234              : 
     235              :   /**
     236              :    * Set to true if the worker should terminate.
     237              :    */
     238              :   bool do_shutdown;
     239              : };
     240              : 
     241              : 
     242              : /**
     243              :  * Job in a batch sign request.
     244              :  */
     245              : struct BatchJob
     246              : {
     247              : 
     248              :   /**
     249              :    * Thread doing the work.
     250              :    */
     251              :   struct Worker *worker;
     252              : 
     253              :   /**
     254              :    * Semaphore to signal that the job is finished.
     255              :    */
     256              :   struct Semaphore sem;
     257              : 
     258              :   /**
     259              :    * Computation status.
     260              :    */
     261              :   enum TALER_ErrorCode ec;
     262              : 
     263              :   /**
     264              :    * Which type of request is this?
     265              :    */
     266              :   enum { TYPE_SIGN, TYPE_RDERIVE } type;
     267              : 
     268              :   /**
     269              :    * Details depending on @e type.
     270              :    */
     271              :   union
     272              :   {
     273              : 
     274              :     /**
     275              :      * Details if @e type is TYPE_SIGN.
     276              :      */
     277              :     struct
     278              :     {
     279              :       /**
     280              :        * Request we are working on.
     281              :        */
     282              :       const struct TALER_CRYPTO_CsSignRequestMessage *sr;
     283              : 
     284              :       /**
     285              :        * Result with the signature.
     286              :        */
     287              :       struct GNUNET_CRYPTO_CsBlindSignature cs_answer;
     288              :     } sign;
     289              : 
     290              :     /**
     291              :      * Details if type is TYPE_RDERIVE.
     292              :      */
     293              :     struct
     294              :     {
     295              :       /**
     296              :        * Request we are answering.
     297              :        */
     298              :       const struct TALER_CRYPTO_CsRDeriveRequest *rdr;
     299              : 
     300              :       /**
     301              :        * Pair of points to return.
     302              :        */
     303              :       struct GNUNET_CRYPTO_CSPublicRPairP rpairp;
     304              : 
     305              :     } rderive;
     306              : 
     307              :   } details;
     308              : 
     309              : };
     310              : 
     311              : /**
     312              :  * Head of DLL of workers ready for more work.
     313              :  */
     314              : static struct Worker *worker_head;
     315              : 
     316              : /**
     317              :  * Tail of DLL of workers ready for more work.
     318              :  */
     319              : static struct Worker *worker_tail;
     320              : 
     321              : /**
     322              :  * Lock for manipulating the worker DLL.
     323              :  */
     324              : static pthread_mutex_t worker_lock = PTHREAD_MUTEX_INITIALIZER;
     325              : 
     326              : /**
     327              :  * Total number of workers that were started.
     328              :  */
     329              : static unsigned int workers;
     330              : 
     331              : /**
     332              :  * Semaphore used to grab a worker.
     333              :  */
     334              : static struct Semaphore worker_sem;
     335              : 
     336              : /**
     337              :  * Command-line options for various TALER_SECMOD_XXX_run() functions.
     338              :  */
     339              : static struct TALER_SECMOD_Options *globals;
     340              : 
     341              : /**
     342              :  * Where do we store the keys?
     343              :  */
     344              : static char *keydir;
     345              : 
     346              : /**
     347              :  * How much should coin creation (@e duration_withdraw) duration overlap
     348              :  * with the next denomination?  Basically, the starting time of two
     349              :  * denominations is always @e duration_withdraw - #overlap_duration apart.
     350              :  */
     351              : static struct GNUNET_TIME_Relative overlap_duration;
     352              : 
     353              : /**
     354              :  * How long into the future do we pre-generate keys?
     355              :  */
     356              : static struct GNUNET_TIME_Relative lookahead_sign;
     357              : 
     358              : /**
     359              :  * All of our denominations, in a DLL. Sorted?
     360              :  */
     361              : static struct Denomination *denom_head;
     362              : 
     363              : /**
     364              :  * All of our denominations, in a DLL. Sorted?
     365              :  */
     366              : static struct Denomination *denom_tail;
     367              : 
     368              : /**
     369              :  * Map of hashes of public (CS) keys to `struct DenominationKey *`
     370              :  * with the respective private keys.
     371              :  */
     372              : static struct GNUNET_CONTAINER_MultiHashMap *keys;
     373              : 
     374              : /**
     375              :  * Task run to generate new keys.
     376              :  */
     377              : static struct GNUNET_SCHEDULER_Task *keygen_task;
     378              : 
     379              : /**
     380              :  * Lock for the keys queue.
     381              :  */
     382              : static pthread_mutex_t keys_lock = PTHREAD_MUTEX_INITIALIZER;
     383              : 
     384              : /**
     385              :  * Current key generation.
     386              :  */
     387              : static uint64_t key_gen;
     388              : 
     389              : /**
     390              :  * Generate the announcement message for @a dk.
     391              :  *
     392              :  * @param[in,out] dk denomination key to generate the announcement for
     393              :  */
     394              : static void
     395          186 : generate_response (struct DenominationKey *dk)
     396              : {
     397          186 :   struct Denomination *denom = dk->denom;
     398          186 :   size_t nlen = strlen (denom->section) + 1;
     399              :   struct TALER_CRYPTO_CsKeyAvailableNotification *an;
     400              :   void *p;
     401              :   size_t tlen;
     402              :   struct GNUNET_TIME_Relative effective_duration;
     403              : 
     404              :   GNUNET_assert (sizeof(dk->denom_pub) < UINT16_MAX);
     405          186 :   GNUNET_assert (nlen < UINT16_MAX);
     406          186 :   tlen = nlen + sizeof (*an);
     407          186 :   GNUNET_assert (tlen < UINT16_MAX);
     408          186 :   an = GNUNET_malloc (tlen);
     409          186 :   an->header.size = htons ((uint16_t) tlen);
     410          186 :   an->header.type = htons (TALER_HELPER_CS_MT_AVAIL);
     411          186 :   an->section_name_len = htonl ((uint32_t) nlen);
     412          186 :   an->anchor_time = GNUNET_TIME_timestamp_hton (dk->anchor_start);
     413          186 :   effective_duration = GNUNET_TIME_absolute_get_difference (
     414              :     dk->anchor_start.abs_time,
     415              :     dk->anchor_end.abs_time);
     416          186 :   an->duration_withdraw = GNUNET_TIME_relative_hton (effective_duration);
     417          186 :   an->denom_pub = dk->denom_pub;
     418          186 :   TALER_exchange_secmod_cs_sign (&dk->h_cs,
     419          186 :                                  denom->section,
     420              :                                  dk->anchor_start,
     421              :                                  effective_duration,
     422              :                                  &TES_smpriv,
     423              :                                  &an->secm_sig);
     424          186 :   an->secm_pub = TES_smpub;
     425          186 :   p = (void *) &an[1];
     426          186 :   GNUNET_memcpy (p,
     427              :                  denom->section,
     428              :                  nlen);
     429          186 :   dk->an = an;
     430          186 : }
     431              : 
     432              : 
     433              : /**
     434              :  * Do the actual signing work.
     435              :  *
     436              :  * @param h_cs hash of key to sign with
     437              :  * @param planchet message to sign
     438              :  * @param for_melt true if for melting
     439              :  * @param[out] cs_sigp set to the CS signature
     440              :  * @return #TALER_EC_NONE on success
     441              :  */
     442              : static enum TALER_ErrorCode
     443         1128 : do_sign (const struct TALER_CsPubHashP *h_cs,
     444              :          const struct GNUNET_CRYPTO_CsBlindedMessage *planchet,
     445              :          bool for_melt,
     446              :          struct GNUNET_CRYPTO_CsBlindSignature *cs_sigp)
     447              : {
     448              :   struct GNUNET_CRYPTO_CsRSecret r[2];
     449              :   struct DenominationKey *dk;
     450              : 
     451         1128 :   GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
     452         1152 :   dk = GNUNET_CONTAINER_multihashmap_get (keys,
     453              :                                           &h_cs->hash);
     454         1152 :   if (NULL == dk)
     455              :   {
     456            3 :     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
     457            3 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     458              :                 "Signing request failed, denomination key %s unknown\n",
     459              :                 GNUNET_h2s (&h_cs->hash));
     460            3 :     return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
     461              :   }
     462         1149 :   if (dk->purge)
     463              :   {
     464              :     /* key was revoked, it must not be used for signing anymore */
     465            0 :     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
     466            0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     467              :                 "Signing request failed, denomination key %s was revoked\n",
     468              :                 GNUNET_h2s (&h_cs->hash));
     469            0 :     return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED;
     470              :   }
     471         1149 :   if (GNUNET_TIME_absolute_is_future (dk->anchor_start.abs_time))
     472              :   {
     473            0 :     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
     474            0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     475              :                 "Signing request failed, denomination key %s is not yet valid\n",
     476              :                 GNUNET_h2s (&h_cs->hash));
     477            0 :     return TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY;
     478              :   }
     479         1149 :   if (GNUNET_TIME_absolute_is_past (dk->anchor_end.abs_time))
     480              :   {
     481              :     /* it is too late; now, usually we should never get here
     482              :        as we delete upon expiration, so this is just conservative */
     483            0 :     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
     484            0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     485              :                 "Signing request failed, denomination key %s is expired (%llu)\n",
     486              :                 GNUNET_h2s (&h_cs->hash),
     487              :                 (unsigned long long) dk->anchor_end.abs_time.abs_value_us);
     488              :     /* usually we delete upon expiratoin, hence same EC */
     489            0 :     return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
     490              :   }
     491         1149 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     492              :               "Received request to sign over bytes with key %s\n",
     493              :               GNUNET_h2s (&h_cs->hash));
     494         1149 :   GNUNET_assert (dk->rc < UINT_MAX);
     495         1149 :   dk->rc++;
     496         1149 :   GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
     497         1149 :   GNUNET_CRYPTO_cs_r_derive (&planchet->nonce,
     498              :                              for_melt ? "rm" : "rw",
     499         1149 :                              &dk->denom_priv,
     500              :                              r);
     501         1149 :   GNUNET_CRYPTO_cs_sign_derive (&dk->denom_priv,
     502              :                                 r,
     503              :                                 planchet,
     504              :                                 cs_sigp);
     505         1146 :   GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
     506         1149 :   GNUNET_assert (dk->rc > 0);
     507         1149 :   dk->rc--;
     508         1149 :   GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
     509         1147 :   return TALER_EC_NONE;
     510              : }
     511              : 
     512              : 
     513              : /**
     514              :  * Generate error response that signing failed.
     515              :  *
     516              :  * @param client client to send response to
     517              :  * @param ec error code to include
     518              :  * @return #GNUNET_OK on success
     519              :  */
     520              : static enum GNUNET_GenericReturnValue
     521            3 : fail_sign (struct TES_Client *client,
     522              :            enum TALER_ErrorCode ec)
     523              : {
     524            3 :   struct TALER_CRYPTO_SignFailure sf = {
     525            3 :     .header.size = htons (sizeof (sf)),
     526            3 :     .header.type = htons (TALER_HELPER_CS_MT_RES_SIGN_FAILURE),
     527            3 :     .ec = htonl (ec)
     528              :   };
     529              : 
     530            3 :   return TES_transmit (client->csock,
     531              :                        &sf.header);
     532              : }
     533              : 
     534              : 
     535              : /**
     536              :  * Generate error response that deriving failed.
     537              :  *
     538              :  * @param client client to send response to
     539              :  * @param ec error code to include
     540              :  * @return #GNUNET_OK on success
     541              :  */
     542              : static enum GNUNET_GenericReturnValue
     543          621 : fail_derive (struct TES_Client *client,
     544              :              enum TALER_ErrorCode ec)
     545              : {
     546          621 :   struct TALER_CRYPTO_RDeriveFailure sf = {
     547          621 :     .header.size = htons (sizeof (sf)),
     548          621 :     .header.type = htons (TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE),
     549          621 :     .ec = htonl (ec)
     550              :   };
     551              : 
     552          621 :   return TES_transmit (client->csock,
     553              :                        &sf.header);
     554              : }
     555              : 
     556              : 
     557              : /**
     558              :  * Generate signature response.
     559              :  *
     560              :  * @param client client to send response to
     561              :  * @param cs_answer signature to send
     562              :  * @return #GNUNET_OK on success
     563              :  */
     564              : static enum GNUNET_GenericReturnValue
     565         1142 : send_signature (struct TES_Client *client,
     566              :                 const struct GNUNET_CRYPTO_CsBlindSignature *cs_answer)
     567              : {
     568              :   struct TALER_CRYPTO_SignResponse sres;
     569              : 
     570         1142 :   sres.header.size = htons (sizeof (sres));
     571         1142 :   sres.header.type = htons (TALER_HELPER_CS_MT_RES_SIGNATURE);
     572         1142 :   sres.b = htonl (cs_answer->b);
     573         1142 :   sres.cs_answer = cs_answer->s_scalar;
     574         1142 :   return TES_transmit (client->csock,
     575              :                        &sres.header);
     576              : }
     577              : 
     578              : 
     579              : /**
     580              :  * Handle @a client request @a sr to create signature. Create the
     581              :  * signature using the respective key and return the result to
     582              :  * the client.
     583              :  *
     584              :  * @param client the client making the request
     585              :  * @param sr the request details
     586              :  * @return #GNUNET_OK on success
     587              :  */
     588              : static enum GNUNET_GenericReturnValue
     589            0 : handle_sign_request (struct TES_Client *client,
     590              :                      const struct TALER_CRYPTO_CsSignRequestMessage *sr)
     591              : {
     592              :   struct GNUNET_CRYPTO_CsBlindSignature cs_answer;
     593            0 :   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
     594              :   enum TALER_ErrorCode ec;
     595              :   enum GNUNET_GenericReturnValue ret;
     596              : 
     597            0 :   ec = do_sign (&sr->h_cs,
     598              :                 &sr->message,
     599            0 :                 (0 != ntohl (sr->for_melt)),
     600              :                 &cs_answer);
     601            0 :   if (TALER_EC_NONE != ec)
     602              :   {
     603            0 :     return fail_sign (client,
     604              :                       ec);
     605              :   }
     606            0 :   ret = send_signature (client,
     607              :                         &cs_answer);
     608            0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     609              :               "Sent CS signature after %s\n",
     610              :               GNUNET_TIME_relative2s (
     611              :                 GNUNET_TIME_absolute_get_duration (now),
     612              :                 GNUNET_YES));
     613            0 :   return ret;
     614              : }
     615              : 
     616              : 
     617              : /**
     618              :  * Do the actual deriving work.
     619              :  *
     620              :  * @param h_cs key to sign with
     621              :  * @param nonce nonce to derive from
     622              :  * @param for_melt true if for melting
     623              :  * @param[out] rpairp set to the derived values
     624              :  * @return #TALER_EC_NONE on success
     625              :  */
     626              : static enum TALER_ErrorCode
     627          961 : do_derive (const struct TALER_CsPubHashP *h_cs,
     628              :            const struct GNUNET_CRYPTO_CsSessionNonce *nonce,
     629              :            bool for_melt,
     630              :            struct GNUNET_CRYPTO_CSPublicRPairP *rpairp)
     631              : {
     632              :   struct DenominationKey *dk;
     633              :   struct GNUNET_CRYPTO_CSPrivateRPairP r_priv;
     634              : 
     635          961 :   GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
     636          978 :   dk = GNUNET_CONTAINER_multihashmap_get (keys,
     637              :                                           &h_cs->hash);
     638          978 :   if (NULL == dk)
     639              :   {
     640            1 :     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
     641            1 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     642              :                 "R Derive request failed, denomination key %s unknown\n",
     643              :                 GNUNET_h2s (&h_cs->hash));
     644            1 :     return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
     645              :   }
     646          977 :   if (dk->purge)
     647              :   {
     648              :     /* key was revoked, it must not be used for deriving anymore */
     649            8 :     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
     650            8 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     651              :                 "R Derive request failed, denomination key %s was revoked\n",
     652              :                 GNUNET_h2s (&h_cs->hash));
     653            8 :     return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED;
     654              :   }
     655          969 :   if (GNUNET_TIME_absolute_is_future (dk->anchor_start.abs_time))
     656              :   {
     657          612 :     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
     658          612 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     659              :                 "R Derive request failed, denomination key %s is not yet valid\n",
     660              :                 GNUNET_h2s (&h_cs->hash));
     661          611 :     return TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY;
     662              :   }
     663          357 :   if (GNUNET_TIME_absolute_is_past (dk->anchor_end.abs_time))
     664              :   {
     665              :     /* it is too late; now, usually we should never get here
     666              :        as we delete upon expiration, so this is just conservative */
     667            0 :     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
     668            0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     669              :                 "Signing request failed, denomination key %s is expired (%llu)\n",
     670              :                 GNUNET_h2s (&h_cs->hash),
     671              :                 (unsigned long long) dk->anchor_end.abs_time.abs_value_us);
     672              :     /* usually we delete upon expiratoin, hence same EC */
     673            0 :     return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
     674              :   }
     675          357 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     676              :               "Received request to derive R with key %s\n",
     677              :               GNUNET_h2s (&h_cs->hash));
     678          357 :   GNUNET_assert (dk->rc < UINT_MAX);
     679          357 :   dk->rc++;
     680          357 :   GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
     681          357 :   GNUNET_CRYPTO_cs_r_derive (nonce,
     682              :                              for_melt ? "rm" : "rw",
     683          357 :                              &dk->denom_priv,
     684              :                              r_priv.r);
     685          357 :   GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
     686          357 :   GNUNET_assert (dk->rc > 0);
     687          357 :   dk->rc--;
     688          357 :   GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
     689          357 :   GNUNET_CRYPTO_cs_r_get_public (&r_priv.r[0],
     690              :                                  &rpairp->r_pub[0]);
     691          354 :   GNUNET_CRYPTO_cs_r_get_public (&r_priv.r[1],
     692              :                                  &rpairp->r_pub[1]);
     693          353 :   return TALER_EC_NONE;
     694              : }
     695              : 
     696              : 
     697              : /**
     698              :  * Generate derivation response.
     699              :  *
     700              :  * @param client client to send response to
     701              :  * @param r_pub public point value pair to send
     702              :  * @return #GNUNET_OK on success
     703              :  */
     704              : static enum GNUNET_GenericReturnValue
     705          357 : send_derivation (struct TES_Client *client,
     706              :                  const struct GNUNET_CRYPTO_CSPublicRPairP *r_pub)
     707              : {
     708          357 :   struct TALER_CRYPTO_RDeriveResponse rdr = {
     709          357 :     .header.size = htons (sizeof (rdr)),
     710          357 :     .header.type = htons (TALER_HELPER_CS_MT_RES_RDERIVE),
     711              :     .r_pub = *r_pub
     712              :   };
     713              : 
     714          357 :   return TES_transmit (client->csock,
     715              :                        &rdr.header);
     716              : }
     717              : 
     718              : 
     719              : /**
     720              :  * Initialize a semaphore @a sem with a value of @a val.
     721              :  *
     722              :  * @param[out] sem semaphore to initialize
     723              :  * @param val initial value of the semaphore
     724              :  */
     725              : static void
     726         2434 : sem_init (struct Semaphore *sem,
     727              :           unsigned int val)
     728              : {
     729         2434 :   GNUNET_assert (0 ==
     730              :                  pthread_mutex_init (&sem->mutex,
     731              :                                      NULL));
     732         2434 :   GNUNET_assert (0 ==
     733              :                  pthread_cond_init (&sem->cv,
     734              :                                     NULL));
     735         2436 :   sem->ctr = val;
     736         2436 : }
     737              : 
     738              : 
     739              : /**
     740              :  * Decrement semaphore, blocks until this is possible.
     741              :  *
     742              :  * @param[in,out] sem semaphore to decrement
     743              :  */
     744              : static void
     745         6897 : sem_down (struct Semaphore *sem)
     746              : {
     747         6897 :   GNUNET_assert (0 == pthread_mutex_lock (&sem->mutex));
     748        10432 :   while (0 == sem->ctr)
     749              :   {
     750         3506 :     pthread_cond_wait (&sem->cv,
     751              :                        &sem->mutex);
     752              :   }
     753         6926 :   sem->ctr--;
     754         6926 :   GNUNET_assert (0 == pthread_mutex_unlock (&sem->mutex));
     755         6937 : }
     756              : 
     757              : 
     758              : /**
     759              :  * Increment semaphore, blocks until this is possible.
     760              :  *
     761              :  * @param[in,out] sem semaphore to decrement
     762              :  */
     763              : static void
     764         6885 : sem_up (struct Semaphore *sem)
     765              : {
     766         6885 :   GNUNET_assert (0 == pthread_mutex_lock (&sem->mutex));
     767         6939 :   sem->ctr++;
     768         6939 :   pthread_cond_signal (&sem->cv);
     769         6909 :   GNUNET_assert (0 == pthread_mutex_unlock (&sem->mutex));
     770         6936 : }
     771              : 
     772              : 
     773              : /**
     774              :  * Release resources used by @a sem.
     775              :  *
     776              :  * @param[in] sem semaphore to release (except the memory itself)
     777              :  */
     778              : static void
     779         2439 : sem_done (struct Semaphore *sem)
     780              : {
     781         2439 :   GNUNET_break (0 == pthread_cond_destroy (&sem->cv));
     782         2444 :   GNUNET_break (0 == pthread_mutex_destroy (&sem->mutex));
     783         2443 : }
     784              : 
     785              : 
     786              : /**
     787              :  * Main logic of a worker thread. Grabs work, does it,
     788              :  * grabs more work.
     789              :  *
     790              :  * @param cls a `struct Worker *`
     791              :  * @returns cls
     792              :  */
     793              : static void *
     794          292 : worker (void *cls)
     795              : {
     796          292 :   struct Worker *w = cls;
     797              : 
     798              :   while (true)
     799              :   {
     800         2414 :     GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
     801         2422 :     GNUNET_CONTAINER_DLL_insert (worker_head,
     802              :                                  worker_tail,
     803              :                                  w);
     804         2422 :     GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
     805         2421 :     sem_up (&worker_sem);
     806         2419 :     sem_down (&w->sem);
     807         2406 :     if (w->do_shutdown)
     808          292 :       break;
     809              :     {
     810         2114 :       struct BatchJob *bj = w->job;
     811              : 
     812         2114 :       switch (bj->type)
     813              :       {
     814         1140 :       case TYPE_SIGN:
     815              :         {
     816         1140 :           const struct TALER_CRYPTO_CsSignRequestMessage *sr
     817              :             = bj->details.sign.sr;
     818              : 
     819         2289 :           bj->ec = do_sign (&sr->h_cs,
     820              :                             &sr->message,
     821         1140 :                             (0 != ntohl (sr->for_melt)),
     822              :                             &bj->details.sign.cs_answer);
     823         1149 :           break;
     824              :         }
     825          960 :       case TYPE_RDERIVE:
     826              :         {
     827          960 :           const struct TALER_CRYPTO_CsRDeriveRequest *rdr
     828              :             = bj->details.rderive.rdr;
     829         1934 :           bj->ec = do_derive (&rdr->h_cs,
     830              :                               &rdr->nonce,
     831          960 :                               (0 != ntohl (rdr->for_melt)),
     832              :                               &bj->details.rderive.rpairp);
     833          974 :           break;
     834              :         }
     835              :       }
     836         2137 :       sem_up (&bj->sem);
     837         2122 :       w->job = NULL;
     838              :     }
     839              :   }
     840          292 :   return w;
     841              : }
     842              : 
     843              : 
     844              : /**
     845              :  * Start batch job @a bj to sign @a sr.
     846              :  *
     847              :  * @param sr signature request to answer
     848              :  * @param[out] bj job data structure
     849              :  */
     850              : static void
     851         1143 : start_sign_job (const struct TALER_CRYPTO_CsSignRequestMessage *sr,
     852              :                 struct BatchJob *bj)
     853              : {
     854         1143 :   sem_init (&bj->sem,
     855              :             0);
     856         1140 :   bj->type = TYPE_SIGN;
     857         1140 :   bj->details.sign.sr = sr;
     858         1140 :   sem_down (&worker_sem);
     859         1150 :   GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
     860         1152 :   bj->worker = worker_head;
     861         1152 :   GNUNET_CONTAINER_DLL_remove (worker_head,
     862              :                                worker_tail,
     863              :                                bj->worker);
     864         1152 :   GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
     865         1152 :   bj->worker->job = bj;
     866         1152 :   sem_up (&bj->worker->sem);
     867         1150 : }
     868              : 
     869              : 
     870              : /**
     871              :  * Start batch job @a bj to derive @a rdr.
     872              :  *
     873              :  * @param rdr derivation request to answer
     874              :  * @param[out] bj job data structure
     875              :  */
     876              : static void
     877          978 : start_derive_job (const struct TALER_CRYPTO_CsRDeriveRequest *rdr,
     878              :                   struct BatchJob *bj)
     879              : {
     880          978 :   sem_init (&bj->sem,
     881              :             0);
     882          978 :   bj->type = TYPE_RDERIVE;
     883          978 :   bj->details.rderive.rdr = rdr;
     884          978 :   sem_down (&worker_sem);
     885          978 :   GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
     886          978 :   bj->worker = worker_head;
     887          978 :   GNUNET_CONTAINER_DLL_remove (worker_head,
     888              :                                worker_tail,
     889              :                                bj->worker);
     890          978 :   GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
     891          978 :   bj->worker->job = bj;
     892          978 :   sem_up (&bj->worker->sem);
     893          978 : }
     894              : 
     895              : 
     896              : /**
     897              :  * Finish a job @a bj for a @a client.
     898              :  *
     899              :  * @param client who made the request
     900              :  * @param[in,out] bj job to finish
     901              :  */
     902              : static void
     903         2125 : finish_job (struct TES_Client *client,
     904              :             struct BatchJob *bj)
     905              : {
     906         2125 :   sem_down (&bj->sem);
     907         2129 :   sem_done (&bj->sem);
     908         2129 :   switch (bj->type)
     909              :   {
     910         1149 :   case TYPE_SIGN:
     911         1149 :     if (TALER_EC_NONE != bj->ec)
     912              :     {
     913            3 :       fail_sign (client,
     914              :                  bj->ec);
     915            3 :       return;
     916              :     }
     917         1146 :     send_signature (client,
     918         1146 :                     &bj->details.sign.cs_answer);
     919         1138 :     break;
     920          978 :   case TYPE_RDERIVE:
     921          978 :     if (TALER_EC_NONE != bj->ec)
     922              :     {
     923          621 :       fail_derive (client,
     924              :                    bj->ec);
     925          621 :       return;
     926              :     }
     927          357 :     send_derivation (client,
     928          357 :                      &bj->details.rderive.rpairp);
     929          357 :     break;
     930              :   }
     931              : }
     932              : 
     933              : 
     934              : /**
     935              :  * Handle @a client request @a sr to create a batch of signature. Creates the
     936              :  * signatures using the respective key and return the results to the client.
     937              :  *
     938              :  * @param client the client making the request
     939              :  * @param bsr the request details
     940              :  * @return #GNUNET_OK on success
     941              :  */
     942              : static enum GNUNET_GenericReturnValue
     943          947 : handle_batch_sign_request (struct TES_Client *client,
     944              :                            const struct TALER_CRYPTO_BatchSignRequest *bsr)
     945              : {
     946          947 :   uint32_t bs = ntohl (bsr->batch_size);
     947          947 :   uint16_t size = ntohs (bsr->header.size) - sizeof (*bsr);
     948          947 :   const void *off = (const void *) &bsr[1];
     949          947 :   unsigned int idx = 0;
     950          947 :   bool failure = false;
     951              : 
     952          947 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     953              :               "Handling batch sign request of size %u\n",
     954              :               (unsigned int) bs);
     955          947 :   if (bs > TALER_MAX_COINS)
     956              :   {
     957            0 :     GNUNET_break_op (0);
     958            0 :     return GNUNET_SYSERR;
     959              :   }
     960          947 :   {
     961          947 :     struct BatchJob jobs[GNUNET_NZL (bs)];
     962              : 
     963         2094 :     while ( (idx < bs) &&
     964              :             (size >= sizeof (struct TALER_CRYPTO_CsSignRequestMessage)) )
     965              :     {
     966         1139 :       const struct TALER_CRYPTO_CsSignRequestMessage *sr = off;
     967         1139 :       uint16_t s = ntohs (sr->header.size);
     968              : 
     969         1139 :       if (s != sizeof (*sr))
     970              :       {
     971            0 :         failure = true;
     972            0 :         bs = idx;
     973            0 :         break;
     974              :       }
     975         1139 :       start_sign_job (sr,
     976         1139 :                       &jobs[idx++]);
     977         1147 :       off += s;
     978         1147 :       size -= s;
     979              :     }
     980          955 :     GNUNET_break_op (0 == size);
     981          954 :     bs = GNUNET_MIN (bs,
     982              :                      idx);
     983         2094 :     for (unsigned int i = 0; i<bs; i++)
     984         1147 :       finish_job (client,
     985              :                   &jobs[i]);
     986              :   }
     987          947 :   if (failure)
     988              :   {
     989            0 :     struct TALER_CRYPTO_SignFailure sf = {
     990            0 :       .header.size = htons (sizeof (sf)),
     991            0 :       .header.type = htons (TALER_HELPER_CS_MT_RES_BATCH_SIGN_FAILURE),
     992            0 :       .ec = htonl (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE)
     993              :     };
     994              : 
     995            0 :     GNUNET_break (0);
     996            0 :     return TES_transmit (client->csock,
     997              :                          &sf.header);
     998              :   }
     999          947 :   return GNUNET_OK;
    1000              : }
    1001              : 
    1002              : 
    1003              : /**
    1004              :  * Handle @a client request @a sr to create a batch of derivations. Creates the
    1005              :  * derivations using the respective key and return the results to the client.
    1006              :  *
    1007              :  * @param client the client making the request
    1008              :  * @param bdr the request details
    1009              :  * @return #GNUNET_OK on success
    1010              :  */
    1011              : static enum GNUNET_GenericReturnValue
    1012          157 : handle_batch_derive_request (struct TES_Client *client,
    1013              :                              const struct TALER_CRYPTO_BatchDeriveRequest *bdr)
    1014              : {
    1015          157 :   uint32_t bs = ntohl (bdr->batch_size);
    1016          157 :   uint16_t size = ntohs (bdr->header.size) - sizeof (*bdr);
    1017          157 :   const void *off = (const void *) &bdr[1];
    1018          157 :   unsigned int idx = 0;
    1019          157 :   bool failure = false;
    1020              : 
    1021          157 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1022              :               "Handling batch derivation request of size %u\n",
    1023              :               (unsigned int) bs);
    1024          157 :   if (bs > TALER_MAX_COINS)
    1025              :   {
    1026            0 :     GNUNET_break_op (0);
    1027            0 :     return GNUNET_SYSERR;
    1028              :   }
    1029          157 :   {
    1030          157 :     struct BatchJob jobs[GNUNET_NZL (bs)];
    1031              : 
    1032         1135 :     while ( (idx < bs) &&
    1033              :             (size >= sizeof (struct TALER_CRYPTO_CsRDeriveRequest)) )
    1034              :     {
    1035          978 :       const struct TALER_CRYPTO_CsRDeriveRequest *rdr = off;
    1036          978 :       uint16_t s = ntohs (rdr->header.size);
    1037              : 
    1038          978 :       if ( (s > size) ||
    1039              :            (s != sizeof (*rdr)) )
    1040              :       {
    1041            0 :         failure = true;
    1042            0 :         bs = idx;
    1043            0 :         break;
    1044              :       }
    1045          978 :       start_derive_job (rdr,
    1046          978 :                         &jobs[idx++]);
    1047          978 :       off += s;
    1048          978 :       size -= s;
    1049              :     }
    1050          157 :     GNUNET_break_op (0 == size);
    1051          157 :     bs = GNUNET_MIN (bs,
    1052              :                      idx);
    1053         1135 :     for (unsigned int i = 0; i<bs; i++)
    1054          978 :       finish_job (client,
    1055              :                   &jobs[i]);
    1056              :   }
    1057          157 :   if (failure)
    1058              :   {
    1059            0 :     GNUNET_break (0);
    1060            0 :     return fail_derive (client,
    1061              :                         TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE);
    1062              :   }
    1063          157 :   return GNUNET_OK;
    1064              : }
    1065              : 
    1066              : 
    1067              : /**
    1068              :  * Start worker thread for batch processing.
    1069              :  *
    1070              :  * @return #GNUNET_OK on success
    1071              :  */
    1072              : static enum GNUNET_GenericReturnValue
    1073          292 : start_worker (void)
    1074              : {
    1075              :   struct Worker *w;
    1076              : 
    1077          292 :   w = GNUNET_new (struct Worker);
    1078          292 :   sem_init (&w->sem,
    1079              :             0);
    1080          292 :   if (0 != pthread_create (&w->pt,
    1081              :                            NULL,
    1082              :                            &worker,
    1083              :                            w))
    1084              :   {
    1085            0 :     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
    1086              :                          "pthread_create");
    1087            0 :     GNUNET_free (w);
    1088            0 :     return GNUNET_SYSERR;
    1089              :   }
    1090          292 :   workers++;
    1091          292 :   return GNUNET_OK;
    1092              : }
    1093              : 
    1094              : 
    1095              : /**
    1096              :  * Stop all worker threads.
    1097              :  */
    1098              : static void
    1099           22 : stop_workers (void)
    1100              : {
    1101          314 :   while (workers > 0)
    1102              :   {
    1103              :     struct Worker *w;
    1104              :     void *result;
    1105              : 
    1106          292 :     sem_down (&worker_sem);
    1107          292 :     GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
    1108          292 :     w = worker_head;
    1109          292 :     GNUNET_CONTAINER_DLL_remove (worker_head,
    1110              :                                  worker_tail,
    1111              :                                  w);
    1112          292 :     GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
    1113          292 :     w->do_shutdown = true;
    1114          292 :     sem_up (&w->sem);
    1115          292 :     pthread_join (w->pt,
    1116              :                   &result);
    1117          292 :     GNUNET_assert (result == w);
    1118          292 :     sem_done (&w->sem);
    1119          292 :     GNUNET_free (w);
    1120          292 :     workers--;
    1121              :   }
    1122           22 : }
    1123              : 
    1124              : 
    1125              : /**
    1126              :  * Initialize key material for denomination key @a dk (also on disk).
    1127              :  *
    1128              :  * @param[in,out] dk denomination key to compute key material for
    1129              :  * @param position where in the DLL will the @a dk go
    1130              :  * @return #GNUNET_OK on success
    1131              :  */
    1132              : static enum GNUNET_GenericReturnValue
    1133           52 : setup_key (struct DenominationKey *dk,
    1134              :            struct DenominationKey *position)
    1135              : {
    1136           52 :   struct Denomination *denom = dk->denom;
    1137              :   struct GNUNET_CRYPTO_CsPrivateKey priv;
    1138              :   struct GNUNET_CRYPTO_CsPublicKey pub;
    1139              : 
    1140           52 :   GNUNET_CRYPTO_cs_private_key_generate (&priv);
    1141           52 :   GNUNET_CRYPTO_cs_private_key_get_public (&priv,
    1142              :                                            &pub);
    1143           52 :   GNUNET_CRYPTO_hash (&pub,
    1144              :                       sizeof (pub),
    1145              :                       &dk->h_cs.hash);
    1146           52 :   GNUNET_asprintf (
    1147              :     &dk->filename,
    1148              :     "%s/%s/%llu-%llu",
    1149              :     keydir,
    1150              :     denom->section,
    1151           52 :     (unsigned long long) (dk->anchor_start.abs_time.abs_value_us
    1152           52 :                           / GNUNET_TIME_UNIT_SECONDS.rel_value_us
    1153              :                           ),
    1154           52 :     (unsigned long long) (dk->anchor_end.abs_time.abs_value_us
    1155           52 :                           / GNUNET_TIME_UNIT_SECONDS.rel_value_us
    1156              :                           ));
    1157           52 :   if (GNUNET_OK !=
    1158           52 :       GNUNET_DISK_fn_write (dk->filename,
    1159              :                             &priv,
    1160              :                             sizeof(priv),
    1161              :                             GNUNET_DISK_PERM_USER_READ))
    1162              :   {
    1163            0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
    1164              :                               "write",
    1165              :                               dk->filename);
    1166            0 :     return GNUNET_SYSERR;
    1167              :   }
    1168           52 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1169              :               "Setup fresh private key %s at %s in `%s' (generation #%llu)\n",
    1170              :               GNUNET_h2s (&dk->h_cs.hash),
    1171              :               GNUNET_TIME_timestamp2s (dk->anchor_start),
    1172              :               dk->filename,
    1173              :               (unsigned long long) key_gen);
    1174           52 :   dk->denom_priv = priv;
    1175           52 :   dk->denom_pub = pub;
    1176           52 :   dk->key_gen = key_gen;
    1177           52 :   generate_response (dk);
    1178           52 :   if (GNUNET_OK !=
    1179           52 :       GNUNET_CONTAINER_multihashmap_put (
    1180              :         keys,
    1181           52 :         &dk->h_cs.hash,
    1182              :         dk,
    1183              :         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
    1184              :   {
    1185            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1186              :                 "Duplicate private key created! Terminating.\n");
    1187            0 :     GNUNET_free (dk->filename);
    1188            0 :     GNUNET_free (dk->an);
    1189            0 :     GNUNET_free (dk);
    1190            0 :     return GNUNET_SYSERR;
    1191              :   }
    1192           52 :   GNUNET_CONTAINER_DLL_insert_after (denom->keys_head,
    1193              :                                      denom->keys_tail,
    1194              :                                      position,
    1195              :                                      dk);
    1196           52 :   return GNUNET_OK;
    1197              : }
    1198              : 
    1199              : 
    1200              : /**
    1201              :  * The withdraw period of a key @a dk has expired. Purge it.
    1202              :  *
    1203              :  * @param[in] dk expired denomination key to purge
    1204              :  */
    1205              : static void
    1206            3 : purge_key (struct DenominationKey *dk)
    1207              : {
    1208            3 :   if (dk->purge)
    1209            0 :     return;
    1210            3 :   if (0 != unlink (dk->filename))
    1211            0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
    1212              :                               "unlink",
    1213              :                               dk->filename);
    1214            3 :   GNUNET_free (dk->filename);
    1215            3 :   dk->purge = true;
    1216            3 :   dk->key_gen = key_gen;
    1217              : }
    1218              : 
    1219              : 
    1220              : /**
    1221              :  * A @a client informs us that a key has been revoked.
    1222              :  * Check if the key is still in use, and if so replace (!)
    1223              :  * it with a fresh key.
    1224              :  *
    1225              :  * @param client the client making the request
    1226              :  * @param rr the revocation request
    1227              :  */
    1228              : static enum GNUNET_GenericReturnValue
    1229            3 : handle_revoke_request (struct TES_Client *client,
    1230              :                        const struct TALER_CRYPTO_CsRevokeRequest *rr)
    1231              : {
    1232              :   struct DenominationKey *dk;
    1233              :   struct DenominationKey *ndk;
    1234              :   struct Denomination *denom;
    1235              : 
    1236              :   (void) client;
    1237            3 :   GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
    1238            3 :   dk = GNUNET_CONTAINER_multihashmap_get (keys,
    1239              :                                           &rr->h_cs.hash);
    1240            3 :   if (NULL == dk)
    1241              :   {
    1242            0 :     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
    1243            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1244              :                 "Revocation request ignored, denomination key %s unknown\n",
    1245              :                 GNUNET_h2s (&rr->h_cs.hash));
    1246            0 :     return GNUNET_OK;
    1247              :   }
    1248            3 :   if (dk->purge)
    1249              :   {
    1250            0 :     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
    1251            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1252              :                 "Revocation request ignored, denomination key %s already revoked\n",
    1253              :                 GNUNET_h2s (&rr->h_cs.hash));
    1254            0 :     return GNUNET_OK;
    1255              :   }
    1256              : 
    1257            3 :   key_gen++;
    1258            3 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1259              :               "Revoking key %s, bumping generation to %llu\n",
    1260              :               GNUNET_h2s (&rr->h_cs.hash),
    1261              :               (unsigned long long) key_gen);
    1262            3 :   purge_key (dk);
    1263              : 
    1264              :   /* Setup replacement key */
    1265            3 :   denom = dk->denom;
    1266            3 :   ndk = GNUNET_new (struct DenominationKey);
    1267            3 :   ndk->denom = denom;
    1268            3 :   ndk->anchor_start = dk->anchor_start;
    1269            3 :   ndk->anchor_end = dk->anchor_end;
    1270            3 :   if (GNUNET_OK !=
    1271            3 :       setup_key (ndk,
    1272              :                  dk))
    1273              :   {
    1274            0 :     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
    1275            0 :     GNUNET_break (0);
    1276            0 :     GNUNET_SCHEDULER_shutdown ();
    1277            0 :     globals->global_ret = EXIT_FAILURE;
    1278            0 :     return GNUNET_SYSERR;
    1279              :   }
    1280            3 :   GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
    1281            3 :   TES_wake_clients ();
    1282            3 :   return GNUNET_OK;
    1283              : }
    1284              : 
    1285              : 
    1286              : /**
    1287              :  * Handle @a client request @a rdr to create signature. Create the
    1288              :  * signature using the respective key and return the result to
    1289              :  * the client.
    1290              :  *
    1291              :  * @param client the client making the request
    1292              :  * @param rdr the request details
    1293              :  * @return #GNUNET_OK on success
    1294              :  */
    1295              : static enum GNUNET_GenericReturnValue
    1296            0 : handle_r_derive_request (struct TES_Client *client,
    1297              :                          const struct TALER_CRYPTO_CsRDeriveRequest *rdr)
    1298              : {
    1299              :   struct GNUNET_CRYPTO_CSPublicRPairP r_pub;
    1300            0 :   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
    1301              :   enum TALER_ErrorCode ec;
    1302              :   enum GNUNET_GenericReturnValue ret;
    1303              : 
    1304            0 :   ec = do_derive (&rdr->h_cs,
    1305              :                   &rdr->nonce,
    1306            0 :                   (0 != ntohl (rdr->for_melt)),
    1307              :                   &r_pub);
    1308            0 :   if (TALER_EC_NONE != ec)
    1309              :   {
    1310            0 :     return fail_derive (client,
    1311              :                         ec);
    1312              :   }
    1313              : 
    1314            0 :   ret = send_derivation (client,
    1315              :                          &r_pub);
    1316            0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1317              :               "Sent CS Derived R after %s\n",
    1318              :               GNUNET_TIME_relative2s (
    1319              :                 GNUNET_TIME_absolute_get_duration (now),
    1320              :                 GNUNET_YES));
    1321            0 :   return ret;
    1322              : }
    1323              : 
    1324              : 
    1325              : /**
    1326              :  * Handle @a hdr message received from @a client.
    1327              :  *
    1328              :  * @param client the client that received the message
    1329              :  * @param hdr message that was received
    1330              :  * @return #GNUNET_OK on success
    1331              :  */
    1332              : static enum GNUNET_GenericReturnValue
    1333         1112 : cs_work_dispatch (struct TES_Client *client,
    1334              :                   const struct GNUNET_MessageHeader *hdr)
    1335              : {
    1336         1112 :   uint16_t msize = ntohs (hdr->size);
    1337              : 
    1338         1112 :   switch (ntohs (hdr->type))
    1339              :   {
    1340            0 :   case TALER_HELPER_CS_MT_REQ_SIGN:
    1341            0 :     if (msize < sizeof (struct TALER_CRYPTO_CsSignRequestMessage))
    1342              :     {
    1343            0 :       GNUNET_break_op (0);
    1344            0 :       return GNUNET_SYSERR;
    1345              :     }
    1346            0 :     return handle_sign_request (
    1347              :       client,
    1348              :       (const struct TALER_CRYPTO_CsSignRequestMessage *) hdr);
    1349            3 :   case TALER_HELPER_CS_MT_REQ_REVOKE:
    1350            3 :     if (msize != sizeof (struct TALER_CRYPTO_CsRevokeRequest))
    1351              :     {
    1352            0 :       GNUNET_break_op (0);
    1353            0 :       return GNUNET_SYSERR;
    1354              :     }
    1355            3 :     return handle_revoke_request (
    1356              :       client,
    1357              :       (const struct TALER_CRYPTO_CsRevokeRequest *) hdr);
    1358          951 :   case TALER_HELPER_CS_MT_REQ_BATCH_SIGN:
    1359          951 :     if (msize <= sizeof (struct TALER_CRYPTO_BatchSignRequest))
    1360              :     {
    1361            0 :       GNUNET_break_op (0);
    1362            0 :       return GNUNET_SYSERR;
    1363              :     }
    1364          951 :     return handle_batch_sign_request (
    1365              :       client,
    1366              :       (const struct TALER_CRYPTO_BatchSignRequest *) hdr);
    1367          157 :   case TALER_HELPER_CS_MT_REQ_BATCH_RDERIVE:
    1368          157 :     if (msize <= sizeof (struct TALER_CRYPTO_BatchDeriveRequest))
    1369              :     {
    1370            0 :       GNUNET_break_op (0);
    1371            0 :       return GNUNET_SYSERR;
    1372              :     }
    1373          157 :     return handle_batch_derive_request (
    1374              :       client,
    1375              :       (const struct TALER_CRYPTO_BatchDeriveRequest *) hdr);
    1376            0 :   case TALER_HELPER_CS_MT_REQ_RDERIVE:
    1377            0 :     if (msize != sizeof (struct TALER_CRYPTO_CsRDeriveRequest))
    1378              :     {
    1379            0 :       GNUNET_break_op (0);
    1380            0 :       return GNUNET_SYSERR;
    1381              :     }
    1382            0 :     return handle_r_derive_request (client,
    1383              :                                     (const struct
    1384              :                                      TALER_CRYPTO_CsRDeriveRequest *) hdr);
    1385            1 :   default:
    1386            1 :     GNUNET_break_op (0);
    1387            0 :     return GNUNET_SYSERR;
    1388              :   }
    1389              : }
    1390              : 
    1391              : 
    1392              : /**
    1393              :  * Send our initial key set to @a client together with the
    1394              :  * "sync" terminator.
    1395              :  *
    1396              :  * @param client the client to inform
    1397              :  * @return #GNUNET_OK on success
    1398              :  */
    1399              : static enum GNUNET_GenericReturnValue
    1400           30 : cs_client_init (struct TES_Client *client)
    1401              : {
    1402           30 :   size_t obs = 0;
    1403              :   char *buf;
    1404              : 
    1405           30 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1406              :               "Initializing new client %p\n",
    1407              :               client);
    1408           30 :   GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
    1409           30 :   for (struct Denomination *denom = denom_head;
    1410           95 :        NULL != denom;
    1411           65 :        denom = denom->next)
    1412              :   {
    1413           65 :     for (struct DenominationKey *dk = denom->keys_head;
    1414          304 :          NULL != dk;
    1415          239 :          dk = dk->next)
    1416              :     {
    1417          239 :       obs += ntohs (dk->an->header.size);
    1418              :     }
    1419              :   }
    1420           30 :   buf = GNUNET_malloc (obs);
    1421           30 :   obs = 0;
    1422           30 :   for (struct Denomination *denom = denom_head;
    1423           95 :        NULL != denom;
    1424           65 :        denom = denom->next)
    1425              :   {
    1426           65 :     for (struct DenominationKey *dk = denom->keys_head;
    1427          304 :          NULL != dk;
    1428          239 :          dk = dk->next)
    1429              :     {
    1430          239 :       GNUNET_memcpy (&buf[obs],
    1431              :                      dk->an,
    1432              :                      ntohs (dk->an->header.size));
    1433          239 :       obs += ntohs (dk->an->header.size);
    1434              :     }
    1435              :   }
    1436           30 :   client->key_gen = key_gen;
    1437           30 :   GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
    1438           30 :   if (GNUNET_OK !=
    1439           30 :       TES_transmit_raw (client->csock,
    1440              :                         obs,
    1441              :                         buf))
    1442              :   {
    1443            0 :     GNUNET_free (buf);
    1444            0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1445              :                 "Client %p must have disconnected\n",
    1446              :                 client);
    1447            0 :     return GNUNET_SYSERR;
    1448              :   }
    1449           30 :   GNUNET_free (buf);
    1450              :   {
    1451           30 :     struct GNUNET_MessageHeader synced = {
    1452           30 :       .type = htons (TALER_HELPER_CS_SYNCED),
    1453           30 :       .size = htons (sizeof (synced))
    1454              :     };
    1455              : 
    1456           30 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1457              :                 "Sending CS SYNCED message to %p\n",
    1458              :                 client);
    1459           30 :     if (GNUNET_OK !=
    1460           30 :         TES_transmit (client->csock,
    1461              :                       &synced))
    1462              :     {
    1463            0 :       GNUNET_break (0);
    1464            0 :       return GNUNET_SYSERR;
    1465              :     }
    1466              :   }
    1467           30 :   return GNUNET_OK;
    1468              : }
    1469              : 
    1470              : 
    1471              : /**
    1472              :  * Notify @a client about all changes to the keys since
    1473              :  * the last generation known to the @a client.
    1474              :  *
    1475              :  * @param client the client to notify
    1476              :  * @return #GNUNET_OK on success
    1477              :  */
    1478              : static enum GNUNET_GenericReturnValue
    1479           23 : cs_update_client_keys (struct TES_Client *client)
    1480              : {
    1481           23 :   size_t obs = 0;
    1482              :   char *buf;
    1483              :   enum GNUNET_GenericReturnValue ret;
    1484              : 
    1485           23 :   GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
    1486           23 :   for (struct Denomination *denom = denom_head;
    1487           81 :        NULL != denom;
    1488           58 :        denom = denom->next)
    1489              :   {
    1490           58 :     for (struct DenominationKey *key = denom->keys_head;
    1491          254 :          NULL != key;
    1492          196 :          key = key->next)
    1493              :     {
    1494          196 :       if (key->key_gen <= client->key_gen)
    1495          187 :         continue;
    1496            9 :       if (key->purge)
    1497            3 :         obs += sizeof (struct TALER_CRYPTO_CsKeyPurgeNotification);
    1498              :       else
    1499            6 :         obs += ntohs (key->an->header.size);
    1500              :     }
    1501              :   }
    1502           23 :   if (0 == obs)
    1503              :   {
    1504              :     /* nothing to do */
    1505           17 :     client->key_gen = key_gen;
    1506           17 :     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
    1507           17 :     return GNUNET_OK;
    1508              :   }
    1509            6 :   buf = GNUNET_malloc (obs);
    1510            6 :   obs = 0;
    1511            6 :   for (struct Denomination *denom = denom_head;
    1512           12 :        NULL != denom;
    1513            6 :        denom = denom->next)
    1514              :   {
    1515            6 :     for (struct DenominationKey *key = denom->keys_head;
    1516           42 :          NULL != key;
    1517           36 :          key = key->next)
    1518              :     {
    1519           36 :       if (key->key_gen <= client->key_gen)
    1520           27 :         continue;
    1521            9 :       if (key->purge)
    1522              :       {
    1523            3 :         struct TALER_CRYPTO_CsKeyPurgeNotification pn = {
    1524            3 :           .header.type = htons (TALER_HELPER_CS_MT_PURGE),
    1525            3 :           .header.size = htons (sizeof (pn)),
    1526              :           .h_cs = key->h_cs
    1527              :         };
    1528              : 
    1529            3 :         GNUNET_memcpy (&buf[obs],
    1530              :                        &pn,
    1531              :                        sizeof (pn));
    1532            3 :         GNUNET_assert (obs + sizeof (pn)
    1533              :                        > obs);
    1534            3 :         obs += sizeof (pn);
    1535              :       }
    1536              :       else
    1537              :       {
    1538            6 :         GNUNET_memcpy (&buf[obs],
    1539              :                        key->an,
    1540              :                        ntohs (key->an->header.size));
    1541            6 :         GNUNET_assert (obs + ntohs (key->an->header.size)
    1542              :                        > obs);
    1543            6 :         obs += ntohs (key->an->header.size);
    1544              :       }
    1545              :     }
    1546              :   }
    1547            6 :   client->key_gen = key_gen;
    1548            6 :   GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
    1549            6 :   ret = TES_transmit_raw (client->csock,
    1550              :                           obs,
    1551              :                           buf);
    1552            6 :   GNUNET_free (buf);
    1553            6 :   return ret;
    1554              : }
    1555              : 
    1556              : 
    1557              : /**
    1558              :  * Create a new denomination key (we do not have enough).
    1559              :  *
    1560              :  * @param[in,out] denom denomination key to create
    1561              :  * @param anchor_start when to start key signing validity
    1562              :  * @param anchor_end when to end key signing validity
    1563              :  * @return #GNUNET_OK on success
    1564              :  */
    1565              : static enum GNUNET_GenericReturnValue
    1566           49 : create_key (struct Denomination *denom,
    1567              :             struct GNUNET_TIME_Timestamp anchor_start,
    1568              :             struct GNUNET_TIME_Timestamp anchor_end)
    1569              : {
    1570              :   struct DenominationKey *dk;
    1571              : 
    1572           49 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1573              :               "Creating new key for `%s' with start date %s\n",
    1574              :               denom->section,
    1575              :               GNUNET_TIME_timestamp2s (anchor_start));
    1576           49 :   dk = GNUNET_new (struct DenominationKey);
    1577           49 :   dk->denom = denom;
    1578           49 :   dk->anchor_start = anchor_start;
    1579           49 :   dk->anchor_end = anchor_end;
    1580           49 :   if (GNUNET_OK !=
    1581           49 :       setup_key (dk,
    1582              :                  denom->keys_tail))
    1583              :   {
    1584            0 :     GNUNET_break (0);
    1585            0 :     GNUNET_free (dk);
    1586            0 :     GNUNET_SCHEDULER_shutdown ();
    1587            0 :     globals->global_ret = EXIT_FAILURE;
    1588            0 :     return GNUNET_SYSERR;
    1589              :   }
    1590           49 :   return GNUNET_OK;
    1591              : }
    1592              : 
    1593              : 
    1594              : /**
    1595              :  * Obtain the maximum withdraw duration of all denominations.
    1596              :  *
    1597              :  * Must only be called while the #keys_lock is held.
    1598              :  *
    1599              :  * @return maximum withdraw duration, zero if there are no denominations
    1600              :  */
    1601              : static struct GNUNET_TIME_Relative
    1602           52 : get_maximum_duration (void)
    1603              : {
    1604           52 :   struct GNUNET_TIME_Relative ret
    1605              :     = GNUNET_TIME_UNIT_ZERO;
    1606              : 
    1607           52 :   for (struct Denomination *denom = denom_head;
    1608          229 :        NULL != denom;
    1609          177 :        denom = denom->next)
    1610              :   {
    1611          177 :     ret = GNUNET_TIME_relative_max (ret,
    1612              :                                     denom->duration_withdraw);
    1613              :   }
    1614           52 :   return ret;
    1615              : }
    1616              : 
    1617              : 
    1618              : /**
    1619              :  * At what time do we need to next create keys if we just did?
    1620              :  *
    1621              :  * @return time when to next create keys if we just finished key generation
    1622              :  */
    1623              : static struct GNUNET_TIME_Absolute
    1624           15 : action_time (void)
    1625              : {
    1626           15 :   struct GNUNET_TIME_Relative md = get_maximum_duration ();
    1627           15 :   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
    1628              :   uint64_t mod;
    1629              : 
    1630           15 :   if (GNUNET_TIME_relative_is_zero (md))
    1631            0 :     return GNUNET_TIME_UNIT_FOREVER_ABS;
    1632           15 :   mod = now.abs_value_us % md.rel_value_us;
    1633           15 :   now.abs_value_us -= mod;
    1634           15 :   return GNUNET_TIME_absolute_add (now,
    1635              :                                    md);
    1636              : }
    1637              : 
    1638              : 
    1639              : /**
    1640              :  * Remove all denomination keys of @a denom that have expired.
    1641              :  *
    1642              :  * @param[in,out] denom denomination family to remove keys for
    1643              :  */
    1644              : static void
    1645          234 : remove_expired_denomination_keys (struct Denomination *denom)
    1646              : {
    1647          466 :   while ( (NULL != denom->keys_head) &&
    1648          226 :           GNUNET_TIME_absolute_is_past (
    1649          226 :             denom->keys_head->anchor_end.abs_time) )
    1650              :   {
    1651            6 :     struct DenominationKey *key = denom->keys_head;
    1652            6 :     struct DenominationKey *nxt = key->next;
    1653              : 
    1654            6 :     if (0 != key->rc)
    1655            0 :       break; /* later */
    1656            6 :     GNUNET_CONTAINER_DLL_remove (denom->keys_head,
    1657              :                                  denom->keys_tail,
    1658              :                                  key);
    1659            6 :     GNUNET_assert (GNUNET_OK ==
    1660              :                    GNUNET_CONTAINER_multihashmap_remove (
    1661              :                      keys,
    1662              :                      &key->h_cs.hash,
    1663              :                      key));
    1664           12 :     if ( (! key->purge) &&
    1665            6 :          (0 != unlink (key->filename)) )
    1666            0 :       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
    1667              :                                 "unlink",
    1668              :                                 key->filename);
    1669            6 :     GNUNET_free (key->filename);
    1670            6 :     GNUNET_free (key->an);
    1671            6 :     GNUNET_free (key);
    1672            6 :     key = nxt;
    1673              :   }
    1674          234 : }
    1675              : 
    1676              : 
    1677              : /**
    1678              :  * Obtain the end anchor to use at this point. Uses the
    1679              :  * #lookahead_sign and then rounds it up by the maximum
    1680              :  * duration of any denomination to arrive at a globally
    1681              :  * valid end-date.
    1682              :  *
    1683              :  * Must only be called while the #keys_lock is held.
    1684              :  *
    1685              :  * @return end anchor
    1686              :  */
    1687              : static struct GNUNET_TIME_Timestamp
    1688           37 : get_anchor_end (void)
    1689              : {
    1690           37 :   struct GNUNET_TIME_Relative md = get_maximum_duration ();
    1691              :   struct GNUNET_TIME_Absolute end
    1692           37 :     = GNUNET_TIME_relative_to_absolute (lookahead_sign);
    1693              :   uint64_t mod;
    1694              : 
    1695           37 :   if (GNUNET_TIME_relative_is_zero (md))
    1696           10 :     return GNUNET_TIME_UNIT_ZERO_TS;
    1697              :   /* Round up 'end' to a multiple of 'md' */
    1698           27 :   mod = end.abs_value_us % md.rel_value_us;
    1699           27 :   end.abs_value_us -= mod;
    1700           27 :   return GNUNET_TIME_absolute_to_timestamp (
    1701              :     GNUNET_TIME_absolute_add (end,
    1702              :                               md));
    1703              : }
    1704              : 
    1705              : 
    1706              : /**
    1707              :  * Create all denomination keys that are required for our
    1708              :  * desired lookahead and that we do not yet have.
    1709              :  *
    1710              :  * @param[in,out] opt our options
    1711              :  * @param[in,out] wake set to true if we should wake the clients
    1712              :  */
    1713              : static void
    1714           37 : create_missing_keys (struct TALER_SECMOD_Options *opt,
    1715              :                      bool *wake)
    1716              : {
    1717              :   struct GNUNET_TIME_Timestamp start;
    1718              :   struct GNUNET_TIME_Timestamp end;
    1719              : 
    1720           37 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1721              :               "Updating denominations ...\n");
    1722           37 :   start = opt->global_now;
    1723           37 :   GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
    1724           37 :   end = get_anchor_end ();
    1725           37 :   for (struct Denomination *denom = denom_head;
    1726          154 :        NULL != denom;
    1727          117 :        denom = denom->next)
    1728              :   {
    1729              :     struct GNUNET_TIME_Timestamp anchor_start;
    1730              :     struct GNUNET_TIME_Timestamp anchor_end;
    1731              :     struct GNUNET_TIME_Timestamp next_end;
    1732          117 :     bool finished = false;
    1733              : 
    1734          117 :     remove_expired_denomination_keys (denom);
    1735          117 :     if (NULL != denom->keys_tail)
    1736              :     {
    1737          103 :       anchor_start = denom->keys_tail->anchor_end;
    1738          103 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1739              :                   "Expanding keys of denomination `%s', last key %s valid for another %s\n",
    1740              :                   denom->section,
    1741              :                   GNUNET_h2s (&denom->keys_tail->h_cs.hash),
    1742              :                   GNUNET_TIME_relative2s (
    1743              :                     GNUNET_TIME_absolute_get_remaining (
    1744              :                       anchor_start.abs_time),
    1745              :                     true));
    1746              :     }
    1747              :     else
    1748              :     {
    1749           14 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1750              :                   "Starting keys of denomination `%s'\n",
    1751              :                   denom->section);
    1752              :       /* Round the very first anchor down to the configured calendar
    1753              :          interval; subsequent anchors inherit the alignment from the
    1754              :          (rounded up) end of the preceding key.  The UTC variants are used
    1755              :          so that the result does not depend on the time zone the secmod
    1756              :          happens to run in. */
    1757           14 :       anchor_start = GNUNET_TIME_absolute_to_timestamp (
    1758              :         GNUNET_TIME_round_down_utc (start.abs_time,
    1759              :                                     denom->anchor_round));
    1760              :     }
    1761          117 :     finished = GNUNET_TIME_timestamp_cmp (anchor_start,
    1762              :                                           >=,
    1763              :                                           end);
    1764          166 :     while (! finished)
    1765              :     {
    1766              :       /* Round the end of the validity period up to the configured calendar
    1767              :          interval.  As #GNUNET_TIME_UNIT_YEARS is 365 days, this is also what
    1768              :          keeps the anchors from drifting off the calendar boundary across leap
    1769              :          years.  Without ANCHOR_ROUND, all of this is a no-op. */
    1770           49 :       anchor_end = GNUNET_TIME_absolute_to_timestamp (
    1771              :         GNUNET_TIME_round_up_utc (
    1772              :           GNUNET_TIME_absolute_add (anchor_start.abs_time,
    1773              :                                     denom->duration_withdraw),
    1774              :           denom->anchor_round));
    1775           49 :       next_end = GNUNET_TIME_absolute_to_timestamp (
    1776              :         GNUNET_TIME_round_up_utc (
    1777              :           GNUNET_TIME_absolute_add (anchor_end.abs_time,
    1778              :                                     denom->duration_withdraw),
    1779              :           denom->anchor_round));
    1780           49 :       if (GNUNET_TIME_timestamp_cmp (next_end,
    1781              :                                      >,
    1782              :                                      end))
    1783              :       {
    1784              :         /* With ANCHOR_ROUND set the calendar interval already provides the
    1785              :            alignment, and stretching the last key would make it cover more
    1786              :            than the one interval it is supposed to cover. */
    1787           17 :         if (GNUNET_TIME_RI_NONE == denom->anchor_round)
    1788           16 :           anchor_end = end; /* extend period to align end periods */
    1789           17 :         finished = true;
    1790              :       }
    1791              :       /* adjust start time down to ensure overlap */
    1792           49 :       anchor_start = GNUNET_TIME_absolute_to_timestamp (
    1793              :         GNUNET_TIME_absolute_subtract (anchor_start.abs_time,
    1794              :                                        overlap_duration));
    1795           49 :       if (! *wake)
    1796              :       {
    1797            3 :         key_gen++;
    1798            3 :         *wake = true;
    1799              :       }
    1800           49 :       if (GNUNET_OK !=
    1801           49 :           create_key (denom,
    1802              :                       anchor_start,
    1803              :                       anchor_end))
    1804              :       {
    1805            0 :         GNUNET_break (0);
    1806            0 :         GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
    1807            0 :         globals->global_ret = EXIT_FAILURE;
    1808            0 :         GNUNET_SCHEDULER_shutdown ();
    1809            0 :         return;
    1810              :       }
    1811           49 :       anchor_start = anchor_end;
    1812              :     }
    1813          117 :     remove_expired_denomination_keys (denom);
    1814              :   }
    1815           37 :   GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
    1816           37 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1817              :               "Updating denominations finished ...\n");
    1818              : }
    1819              : 
    1820              : 
    1821              : /**
    1822              :  * Task run periodically to expire keys and/or generate fresh ones.
    1823              :  *
    1824              :  * @param cls the `struct TALER_SECMOD_Options *`
    1825              :  */
    1826              : static void
    1827           15 : update_denominations (void *cls)
    1828              : {
    1829           15 :   struct TALER_SECMOD_Options *opt = cls;
    1830              :   struct GNUNET_TIME_Absolute at;
    1831           15 :   bool wake = false;
    1832              : 
    1833              :   (void) cls;
    1834           15 :   keygen_task = NULL;
    1835           15 :   opt->global_now = GNUNET_TIME_timestamp_get ();
    1836           15 :   create_missing_keys (opt,
    1837              :                        &wake);
    1838           15 :   if (wake)
    1839            3 :     TES_wake_clients ();
    1840           15 :   at = action_time ();
    1841           15 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1842              :               "Next key generation due at %s\n",
    1843              :               GNUNET_TIME_absolute2s (at));
    1844           15 :   keygen_task = GNUNET_SCHEDULER_add_at (at,
    1845              :                                          &update_denominations,
    1846              :                                          opt);
    1847           15 : }
    1848              : 
    1849              : 
    1850              : /**
    1851              :  * Parse private key of denomination @a denom in @a buf.
    1852              :  *
    1853              :  * @param[out] denom denomination of the key
    1854              :  * @param filename name of the file we are parsing, for logging
    1855              :  * @param priv key material
    1856              :  */
    1857              : static void
    1858          134 : parse_key (struct Denomination *denom,
    1859              :            const char *filename,
    1860              :            const struct GNUNET_CRYPTO_CsPrivateKey *priv)
    1861              : {
    1862              :   const char *anchor_s;
    1863              :   char dummy;
    1864              :   unsigned long long anchor_start_ll;
    1865              :   unsigned long long anchor_end_ll;
    1866              :   struct GNUNET_TIME_Timestamp anchor_start;
    1867              :   struct GNUNET_TIME_Timestamp anchor_end;
    1868          134 :   char *nf = NULL;
    1869              : 
    1870          134 :   anchor_s = strrchr (filename,
    1871              :                       '/');
    1872          134 :   if (NULL == anchor_s)
    1873              :   {
    1874              :     /* File in a directory without '/' in the name, this makes no sense. */
    1875            0 :     GNUNET_break (0);
    1876            0 :     return;
    1877              :   }
    1878          134 :   anchor_s++;
    1879          134 :   if (2 != sscanf (anchor_s,
    1880              :                    "%llu-%llu%c",
    1881              :                    &anchor_start_ll,
    1882              :                    &anchor_end_ll,
    1883              :                    &dummy))
    1884              :   {
    1885              :     /* try legacy mode */
    1886            3 :     if (1 != sscanf (anchor_s,
    1887              :                      "%llu%c",
    1888              :                      &anchor_start_ll,
    1889              :                      &dummy))
    1890              :     {
    1891              :       /* Filenames in KEYDIR must ONLY be the anchor time in seconds! */
    1892            0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1893              :                   "Filename `%s' invalid for key file, skipping\n",
    1894              :                   anchor_s);
    1895            0 :       return;
    1896              :     }
    1897              :     anchor_start.abs_time.abs_value_us
    1898            3 :       = anchor_start_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us;
    1899            6 :     if (anchor_start_ll != anchor_start.abs_time.abs_value_us
    1900            3 :         / GNUNET_TIME_UNIT_SECONDS.rel_value_us)
    1901              :     {
    1902              :       /* Integer overflow. Bad, invalid filename. */
    1903            0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1904              :                   "Integer overflow. Filename `%s' invalid for key file, skipping\n",
    1905              :                   anchor_s);
    1906            0 :       return;
    1907              :     }
    1908              :     anchor_end
    1909            3 :       = GNUNET_TIME_absolute_to_timestamp (
    1910              :           GNUNET_TIME_absolute_add (anchor_start.abs_time,
    1911              :                                     denom->duration_withdraw));
    1912            3 :     GNUNET_asprintf (
    1913              :       &nf,
    1914              :       "%s/%s/%llu-%llu",
    1915              :       keydir,
    1916              :       denom->section,
    1917              :       anchor_start_ll,
    1918            3 :       (unsigned long long) (anchor_end.abs_time.abs_value_us
    1919            3 :                             / GNUNET_TIME_UNIT_SECONDS.rel_value_us));
    1920              :     /* Try to fix the legacy filename */
    1921            3 :     if (0 !=
    1922            3 :         rename (filename,
    1923              :                 nf))
    1924              :     {
    1925            0 :       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
    1926              :                                 "rename",
    1927              :                                 filename);
    1928            0 :       GNUNET_free (nf);
    1929              :     }
    1930              :   }
    1931              :   else
    1932              :   {
    1933              :     anchor_start.abs_time.abs_value_us
    1934          131 :       = anchor_start_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us;
    1935              :     anchor_end.abs_time.abs_value_us
    1936          131 :       = anchor_end_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us;
    1937          262 :     if ( (anchor_start_ll != anchor_start.abs_time.abs_value_us
    1938          131 :           / GNUNET_TIME_UNIT_SECONDS.rel_value_us) ||
    1939          262 :          (anchor_end_ll != anchor_end.abs_time.abs_value_us
    1940          131 :           / GNUNET_TIME_UNIT_SECONDS.rel_value_us) )
    1941              :     {
    1942              :       /* Integer overflow. Bad, invalid filename. */
    1943            0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1944              :                   "Integer overflow. Filename `%s' invalid for key file, skipping\n",
    1945              :                   anchor_s);
    1946            0 :       return;
    1947              :     }
    1948              :   }
    1949              : 
    1950              :   {
    1951              :     struct DenominationKey *dk;
    1952              :     struct DenominationKey *before;
    1953              : 
    1954          134 :     dk = GNUNET_new (struct DenominationKey);
    1955          134 :     dk->denom_priv = *priv;
    1956          134 :     dk->denom = denom;
    1957          134 :     dk->anchor_start = anchor_start;
    1958          134 :     dk->anchor_end = anchor_end;
    1959          134 :     dk->filename = (NULL == nf) ? GNUNET_strdup (filename) : nf;
    1960          134 :     GNUNET_CRYPTO_cs_private_key_get_public (priv,
    1961              :                                              &dk->denom_pub);
    1962          134 :     GNUNET_CRYPTO_hash (&dk->denom_pub,
    1963              :                         sizeof (dk->denom_pub),
    1964              :                         &dk->h_cs.hash);
    1965          134 :     generate_response (dk);
    1966          134 :     if (GNUNET_OK !=
    1967          134 :         GNUNET_CONTAINER_multihashmap_put (
    1968              :           keys,
    1969          134 :           &dk->h_cs.hash,
    1970              :           dk,
    1971              :           GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
    1972              :     {
    1973            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1974              :                   "Duplicate private key %s detected in file `%s'. Skipping.\n",
    1975              :                   GNUNET_h2s (&dk->h_cs.hash),
    1976              :                   filename);
    1977            0 :       GNUNET_free (dk->an);
    1978            0 :       GNUNET_free (dk);
    1979            0 :       return;
    1980              :     }
    1981          134 :     before = NULL;
    1982          134 :     for (struct DenominationKey *pos = denom->keys_head;
    1983          135 :          NULL != pos;
    1984            1 :          pos = pos->next)
    1985              :     {
    1986           90 :       if (GNUNET_TIME_timestamp_cmp (pos->anchor_start,
    1987              :                                      >,
    1988              :                                      anchor_start))
    1989           89 :         break;
    1990            1 :       before = pos;
    1991              :     }
    1992          134 :     GNUNET_CONTAINER_DLL_insert_after (denom->keys_head,
    1993              :                                        denom->keys_tail,
    1994              :                                        before,
    1995              :                                        dk);
    1996          134 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1997              :                 "Imported key %s from `%s'\n",
    1998              :                 GNUNET_h2s (&dk->h_cs.hash),
    1999              :                 filename);
    2000              :   }
    2001              : }
    2002              : 
    2003              : 
    2004              : /**
    2005              :  * Import a private key from @a filename for the denomination
    2006              :  * given in @a cls.
    2007              :  *
    2008              :  * @param[in,out] cls a `struct Denomiantion`
    2009              :  * @param filename name of a file in the directory
    2010              :  * @return #GNUNET_OK (always, continue to iterate)
    2011              :  */
    2012              : static enum GNUNET_GenericReturnValue
    2013          134 : import_key (void *cls,
    2014              :             const char *filename)
    2015              : {
    2016          134 :   struct Denomination *denom = cls;
    2017              :   struct GNUNET_DISK_FileHandle *fh;
    2018              :   struct GNUNET_DISK_MapHandle *map;
    2019              :   void *ptr;
    2020              :   int fd;
    2021              :   struct stat sbuf;
    2022              : 
    2023              :   {
    2024              :     struct stat lsbuf;
    2025              : 
    2026          134 :     if (0 != lstat (filename,
    2027              :                     &lsbuf))
    2028              :     {
    2029            0 :       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
    2030              :                                 "lstat",
    2031              :                                 filename);
    2032            0 :       return GNUNET_OK;
    2033              :     }
    2034          134 :     if (! S_ISREG (lsbuf.st_mode))
    2035              :     {
    2036            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2037              :                   "File `%s' is not a regular file, which is not allowed for private keys!\n",
    2038              :                   filename);
    2039            0 :       return GNUNET_OK;
    2040              :     }
    2041              :   }
    2042              : 
    2043          134 :   fd = open (filename,
    2044              :              O_RDONLY | O_CLOEXEC);
    2045          134 :   if (-1 == fd)
    2046              :   {
    2047            0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
    2048              :                               "open",
    2049              :                               filename);
    2050            0 :     return GNUNET_OK;
    2051              :   }
    2052          134 :   if (0 != fstat (fd,
    2053              :                   &sbuf))
    2054              :   {
    2055            0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
    2056              :                               "stat",
    2057              :                               filename);
    2058            0 :     GNUNET_break (0 == close (fd));
    2059            0 :     return GNUNET_OK;
    2060              :   }
    2061          134 :   if (! S_ISREG (sbuf.st_mode))
    2062              :   {
    2063            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2064              :                 "File `%s' is not a regular file, which is not allowed for private keys!\n",
    2065              :                 filename);
    2066            0 :     GNUNET_break (0 == close (fd));
    2067            0 :     return GNUNET_OK;
    2068              :   }
    2069          134 :   if (0 != (sbuf.st_mode & (S_IWUSR | S_IRWXG | S_IRWXO)))
    2070              :   {
    2071              :     /* permission are NOT tight, try to patch them up! */
    2072            0 :     if (0 !=
    2073            0 :         fchmod (fd,
    2074              :                 S_IRUSR))
    2075              :     {
    2076            0 :       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
    2077              :                                 "fchmod",
    2078              :                                 filename);
    2079              :       /* refuse to use key if file has wrong permissions */
    2080            0 :       GNUNET_break (0 == close (fd));
    2081            0 :       return GNUNET_OK;
    2082              :     }
    2083              :   }
    2084          134 :   fh = GNUNET_DISK_get_handle_from_int_fd (fd);
    2085          134 :   if (NULL == fh)
    2086              :   {
    2087            0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
    2088              :                               "open",
    2089              :                               filename);
    2090            0 :     GNUNET_break (0 == close (fd));
    2091            0 :     return GNUNET_OK;
    2092              :   }
    2093          134 :   if (sbuf.st_size != sizeof(struct GNUNET_CRYPTO_CsPrivateKey))
    2094              :   {
    2095            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    2096              :                 "File `%s' too big to be a private key\n",
    2097              :                 filename);
    2098            0 :     GNUNET_DISK_file_close (fh);
    2099            0 :     return GNUNET_OK;
    2100              :   }
    2101          134 :   ptr = GNUNET_DISK_file_map (fh,
    2102              :                               &map,
    2103              :                               GNUNET_DISK_MAP_TYPE_READ,
    2104          134 :                               (size_t) sbuf.st_size);
    2105          134 :   if (NULL == ptr)
    2106              :   {
    2107            0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
    2108              :                               "mmap",
    2109              :                               filename);
    2110            0 :     GNUNET_DISK_file_close (fh);
    2111            0 :     return GNUNET_OK;
    2112              :   }
    2113          134 :   parse_key (denom,
    2114              :              filename,
    2115              :              (const struct GNUNET_CRYPTO_CsPrivateKey *) ptr);
    2116          134 :   GNUNET_DISK_file_unmap (map);
    2117          134 :   GNUNET_DISK_file_close (fh);
    2118          134 :   return GNUNET_OK;
    2119              : }
    2120              : 
    2121              : 
    2122              : /**
    2123              :  * Parse configuration for denomination type parameters.  Also determines
    2124              :  * our anchor by looking at the existing denominations of the same type.
    2125              :  *
    2126              :  * @param cfg configuration to use
    2127              :  * @param ct section in the configuration file giving the denomination type parameters
    2128              :  * @param[out] denom set to the denomination parameters from the configuration
    2129              :  * @return #GNUNET_OK on success, #GNUNET_SYSERR if the configuration is invalid
    2130              :  */
    2131              : static enum GNUNET_GenericReturnValue
    2132           57 : parse_denomination_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg,
    2133              :                         const char *ct,
    2134              :                         struct Denomination *denom)
    2135              : {
    2136              :   char *secname;
    2137              : 
    2138           57 :   GNUNET_asprintf (&secname,
    2139              :                    "%s-secmod-cs",
    2140           57 :                    globals->section);
    2141           57 :   if (GNUNET_OK !=
    2142           57 :       GNUNET_CONFIGURATION_get_value_time (cfg,
    2143              :                                            ct,
    2144              :                                            "DURATION_WITHDRAW",
    2145              :                                            &denom->duration_withdraw))
    2146              :   {
    2147            0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    2148              :                                ct,
    2149              :                                "DURATION_WITHDRAW");
    2150            0 :     GNUNET_free (secname);
    2151            0 :     return GNUNET_SYSERR;
    2152              :   }
    2153           57 :   if (GNUNET_TIME_relative_cmp (denom->duration_withdraw,
    2154              :                                 <,
    2155              :                                 GNUNET_TIME_UNIT_SECONDS))
    2156              :   {
    2157            0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    2158              :                                ct,
    2159              :                                "DURATION_WITHDRAW",
    2160              :                                "less than one second is not supported");
    2161            0 :     GNUNET_free (secname);
    2162            0 :     return GNUNET_SYSERR;
    2163              :   }
    2164           57 :   if (GNUNET_TIME_relative_cmp (overlap_duration,
    2165              :                                 >=,
    2166              :                                 denom->duration_withdraw))
    2167              :   {
    2168            0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    2169              :                                secname,
    2170              :                                "OVERLAP_DURATION",
    2171              :                                "Value given must be smaller than value for DURATION_WITHDRAW!");
    2172            0 :     GNUNET_free (secname);
    2173            0 :     return GNUNET_SYSERR;
    2174              :   }
    2175              :   {
    2176              :     struct GNUNET_TIME_Relative ar;
    2177              : 
    2178              :     /* The denomination section takes precedence, the secmod section
    2179              :        provides the default for all denominations. */
    2180           57 :     if ( (GNUNET_OK !=
    2181           57 :           GNUNET_CONFIGURATION_get_value_time (cfg,
    2182              :                                                ct,
    2183              :                                                "ANCHOR_ROUND",
    2184           53 :                                                &ar)) &&
    2185              :          (GNUNET_OK !=
    2186           53 :           GNUNET_CONFIGURATION_get_value_time (cfg,
    2187              :                                                secname,
    2188              :                                                "ANCHOR_ROUND",
    2189              :                                                &ar)) )
    2190            0 :       ar = GNUNET_TIME_UNIT_ZERO; /* not configured: do not round */
    2191              :     denom->anchor_round
    2192           57 :       = GNUNET_TIME_relative_to_round_interval (ar);
    2193           57 :     if ( (GNUNET_TIME_RI_NONE == denom->anchor_round) &&
    2194           53 :          (! GNUNET_TIME_relative_is_zero (ar)) )
    2195              :     {
    2196            0 :       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    2197              :                                  ct,
    2198              :                                  "ANCHOR_ROUND",
    2199              :                                  "Value given must be zero or exactly one second, minute, hour, day, week, month, quarter or year");
    2200            0 :       GNUNET_free (secname);
    2201            0 :       return GNUNET_SYSERR;
    2202              :     }
    2203              :   }
    2204           57 :   GNUNET_free (secname);
    2205           57 :   denom->section = TES_normalize_section (ct);
    2206           57 :   return GNUNET_OK;
    2207              : }
    2208              : 
    2209              : 
    2210              : /**
    2211              :  * Closure for #load_denominations.
    2212              :  */
    2213              : struct LoadContext
    2214              : {
    2215              : 
    2216              :   /**
    2217              :    * Configuration to use.
    2218              :    */
    2219              :   const struct GNUNET_CONFIGURATION_Handle *cfg;
    2220              : 
    2221              :   /**
    2222              :    * Current time to use.
    2223              :    */
    2224              :   struct GNUNET_TIME_Timestamp t;
    2225              : 
    2226              :   /**
    2227              :    * Configuration section prefix to use for denomination settings.
    2228              :    * "coin_" for the exchange, "doco_" for Donau.
    2229              :    */
    2230              :   const char *cprefix;
    2231              : 
    2232              :   /**
    2233              :    * Status, to be set to #GNUNET_SYSERR on failure
    2234              :    */
    2235              :   enum GNUNET_GenericReturnValue ret;
    2236              : };
    2237              : 
    2238              : 
    2239              : /**
    2240              :  * Generate new denomination signing keys for the denomination type of the given @a
    2241              :  * denomination_alias.
    2242              :  *
    2243              :  * @param cls a `struct LoadContext`, with 'ret' to be set to #GNUNET_SYSERR on failure
    2244              :  * @param denomination_alias name of the denomination's section in the configuration
    2245              :  */
    2246              : static void
    2247          903 : load_denominations (void *cls,
    2248              :                     const char *denomination_alias)
    2249              : {
    2250          903 :   struct LoadContext *ctx = cls;
    2251              :   struct Denomination *denom;
    2252              :   char *cipher;
    2253              : 
    2254          903 :   if (0 != strncasecmp (denomination_alias,
    2255              :                         ctx->cprefix,
    2256              :                         strlen (ctx->cprefix)))
    2257          846 :     return; /* not a denomination type definition */
    2258          121 :   if (GNUNET_OK !=
    2259          121 :       GNUNET_CONFIGURATION_get_value_string (ctx->cfg,
    2260              :                                              denomination_alias,
    2261              :                                              "CIPHER",
    2262              :                                              &cipher))
    2263              :   {
    2264            0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    2265              :                                denomination_alias,
    2266              :                                "CIPHER");
    2267            0 :     return;
    2268              :   }
    2269          121 :   if (0 != strcmp (cipher, "CS"))
    2270              :   {
    2271           64 :     GNUNET_free (cipher);
    2272           64 :     return; /* Ignore denominations of other types than CS*/
    2273              :   }
    2274           57 :   GNUNET_free (cipher);
    2275              : 
    2276           57 :   denom = GNUNET_new (struct Denomination);
    2277           57 :   if (GNUNET_OK !=
    2278           57 :       parse_denomination_cfg (ctx->cfg,
    2279              :                               denomination_alias,
    2280              :                               denom))
    2281              :   {
    2282            0 :     ctx->ret = GNUNET_SYSERR;
    2283            0 :     GNUNET_free (denom);
    2284            0 :     return;
    2285              :   }
    2286           57 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2287              :               "Loading keys for denomination %s\n",
    2288              :               denom->section);
    2289              :   {
    2290              :     char *dname;
    2291              : 
    2292           57 :     GNUNET_asprintf (&dname,
    2293              :                      "%s/%s",
    2294              :                      keydir,
    2295              :                      denom->section);
    2296           57 :     GNUNET_break (GNUNET_OK ==
    2297              :                   GNUNET_DISK_directory_create (dname));
    2298           57 :     GNUNET_DISK_directory_scan (dname,
    2299              :                                 &import_key,
    2300              :                                 denom);
    2301           57 :     GNUNET_free (dname);
    2302              :   }
    2303           57 :   GNUNET_CONTAINER_DLL_insert (denom_head,
    2304              :                                denom_tail,
    2305              :                                denom);
    2306              : }
    2307              : 
    2308              : 
    2309              : /**
    2310              :  * Load the various duration values from @a cfg
    2311              :  *
    2312              :  * @param cfg configuration to use
    2313              :  * @return #GNUNET_OK on success
    2314              :  */
    2315              : static enum GNUNET_GenericReturnValue
    2316           35 : load_durations (const struct GNUNET_CONFIGURATION_Handle *cfg)
    2317              : {
    2318              :   char *secname;
    2319              : 
    2320           35 :   GNUNET_asprintf (&secname,
    2321              :                    "%s-secmod-cs",
    2322           35 :                    globals->section);
    2323           35 :   if (GNUNET_OK !=
    2324           35 :       GNUNET_CONFIGURATION_get_value_time (cfg,
    2325              :                                            secname,
    2326              :                                            "OVERLAP_DURATION",
    2327              :                                            &overlap_duration))
    2328              :   {
    2329            0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    2330              :                                secname,
    2331              :                                "OVERLAP_DURATION");
    2332            0 :     GNUNET_free (secname);
    2333            0 :     return GNUNET_SYSERR;
    2334              :   }
    2335           35 :   if (GNUNET_OK !=
    2336           35 :       GNUNET_CONFIGURATION_get_value_time (cfg,
    2337              :                                            secname,
    2338              :                                            "LOOKAHEAD_SIGN",
    2339              :                                            &lookahead_sign))
    2340              :   {
    2341            0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    2342              :                                secname,
    2343              :                                "LOOKAHEAD_SIGN");
    2344            0 :     GNUNET_free (secname);
    2345            0 :     return GNUNET_SYSERR;
    2346              :   }
    2347           35 :   GNUNET_free (secname);
    2348           35 :   return GNUNET_OK;
    2349              : }
    2350              : 
    2351              : 
    2352              : /**
    2353              :  * Function run on shutdown. Stops the various jobs (nicely).
    2354              :  *
    2355              :  * @param cls a `struct TALER_SECMOD_Options`
    2356              :  */
    2357              : static void
    2358           22 : do_shutdown (void *cls)
    2359              : {
    2360              :   (void) cls;
    2361           22 :   TES_listen_stop ();
    2362           22 :   if (NULL != keygen_task)
    2363              :   {
    2364           12 :     GNUNET_SCHEDULER_cancel (keygen_task);
    2365           12 :     keygen_task = NULL;
    2366              :   }
    2367           22 :   stop_workers ();
    2368           22 :   sem_done (&worker_sem);
    2369           22 : }
    2370              : 
    2371              : 
    2372              : void
    2373           35 : TALER_SECMOD_cs_run (void *cls,
    2374              :                      char *const *args,
    2375              :                      const char *cfgfile,
    2376              :                      const struct GNUNET_CONFIGURATION_Handle *cfg)
    2377              : {
    2378              :   static struct TES_Callbacks cb = {
    2379              :     .dispatch = &cs_work_dispatch,
    2380              :     .updater = &cs_update_client_keys,
    2381              :     .init = &cs_client_init
    2382              :   };
    2383           35 :   struct TALER_SECMOD_Options *opt = cls;
    2384              :   char *secname;
    2385              : 
    2386              :   (void) args;
    2387              :   (void) cfgfile;
    2388           35 :   globals = opt;
    2389           35 :   if (GNUNET_TIME_timestamp_cmp (opt->global_now,
    2390              :                                  !=,
    2391              :                                  opt->global_now_tmp))
    2392              :   {
    2393              :     /* The user gave "--now", use it! */
    2394            0 :     opt->global_now = opt->global_now_tmp;
    2395              :   }
    2396              :   else
    2397              :   {
    2398              :     /* get current time again, we may be timetraveling! */
    2399           35 :     opt->global_now = GNUNET_TIME_timestamp_get ();
    2400              :   }
    2401           35 :   GNUNET_asprintf (&secname,
    2402              :                    "%s-secmod-cs",
    2403              :                    opt->section);
    2404           35 :   if (GNUNET_OK !=
    2405           35 :       GNUNET_CONFIGURATION_get_value_filename (cfg,
    2406              :                                                secname,
    2407              :                                                "KEY_DIR",
    2408              :                                                &keydir))
    2409              :   {
    2410            0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    2411              :                                secname,
    2412              :                                "KEY_DIR");
    2413            0 :     GNUNET_free (secname);
    2414            0 :     opt->global_ret = EXIT_NOTCONFIGURED;
    2415           23 :     return;
    2416              :   }
    2417           35 :   if (GNUNET_OK !=
    2418           35 :       load_durations (cfg))
    2419              :   {
    2420            0 :     opt->global_ret = EXIT_NOTCONFIGURED;
    2421            0 :     GNUNET_free (secname);
    2422            0 :     return;
    2423              :   }
    2424           35 :   if (GNUNET_OK !=
    2425           35 :       TES_normalize_key_directory (cfg,
    2426              :                                    keydir,
    2427              :                                    opt->cprefix))
    2428              :   {
    2429           13 :     opt->global_ret = EXIT_FAILURE;
    2430           13 :     GNUNET_free (secname);
    2431           13 :     return;
    2432              :   }
    2433           22 :   opt->global_ret = TES_listen_start (cfg,
    2434              :                                       secname,
    2435              :                                       &cb);
    2436           22 :   GNUNET_free (secname);
    2437           22 :   if (0 != opt->global_ret)
    2438            0 :     return;
    2439           22 :   sem_init (&worker_sem,
    2440              :             0);
    2441           22 :   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
    2442              :                                  opt);
    2443           22 :   if (0 == opt->max_workers)
    2444              :   {
    2445              :     long lret;
    2446              : 
    2447            0 :     lret = sysconf (_SC_NPROCESSORS_CONF);
    2448            0 :     if (lret <= 0)
    2449            0 :       lret = 1;
    2450            0 :     opt->max_workers = (unsigned int) lret;
    2451              :   }
    2452          314 :   for (unsigned int i = 0; i<opt->max_workers; i++)
    2453          292 :     if (GNUNET_OK !=
    2454          292 :         start_worker ())
    2455              :     {
    2456            0 :       GNUNET_SCHEDULER_shutdown ();
    2457            0 :       return;
    2458              :     }
    2459              :   /* Load denominations */
    2460           22 :   keys = GNUNET_CONTAINER_multihashmap_create (65536,
    2461              :                                                true);
    2462              :   {
    2463           22 :     struct LoadContext lc = {
    2464              :       .cfg = cfg,
    2465              :       .ret = GNUNET_OK,
    2466              :       .t = opt->global_now,
    2467           22 :       .cprefix = opt->cprefix
    2468              :     };
    2469           22 :     bool wake = true;
    2470              : 
    2471           22 :     GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
    2472           22 :     GNUNET_CONFIGURATION_iterate_sections (cfg,
    2473              :                                            &load_denominations,
    2474              :                                            &lc);
    2475           22 :     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
    2476           22 :     if (GNUNET_OK != lc.ret)
    2477              :     {
    2478            0 :       opt->global_ret = EXIT_FAILURE;
    2479            0 :       GNUNET_SCHEDULER_shutdown ();
    2480            0 :       return;
    2481              :     }
    2482           22 :     create_missing_keys (opt,
    2483              :                          &wake);
    2484              :   }
    2485           22 :   if (NULL == denom_head)
    2486              :   {
    2487           10 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2488              :                 "No CS denominations configured. Make sure section names start with `%s' if you are using CS!\n",
    2489              :                 opt->cprefix);
    2490           10 :     TES_wake_clients ();
    2491           10 :     return;
    2492              :   }
    2493              :   /* start job to keep keys up-to-date; MUST be run before the #listen_task,
    2494              :      hence with priority. */
    2495           12 :   keygen_task = GNUNET_SCHEDULER_add_with_priority (
    2496              :     GNUNET_SCHEDULER_PRIORITY_URGENT,
    2497              :     &update_denominations,
    2498              :     opt);
    2499              : }
        

Generated by: LCOV version 2.0-1