exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

secmod_cs.c (66649B)


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