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 (61640B)


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