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


      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   struct BatchJob jobs[GNUNET_NZL (bs)];
    923   bool failure = false;
    924 
    925   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    926               "Handling batch sign request of size %u\n",
    927               (unsigned int) bs);
    928   if (bs > TALER_MAX_COINS)
    929   {
    930     GNUNET_break_op (0);
    931     return GNUNET_SYSERR;
    932   }
    933   while ( (bs > 0) &&
    934           (size >= sizeof (struct TALER_CRYPTO_CsSignRequestMessage)) )
    935   {
    936     const struct TALER_CRYPTO_CsSignRequestMessage *sr = off;
    937     uint16_t s = ntohs (sr->header.size);
    938 
    939     if (s > size)
    940     {
    941       failure = true;
    942       bs = idx;
    943       break;
    944     }
    945     start_sign_job (sr,
    946                     &jobs[idx++]);
    947     off += s;
    948     size -= s;
    949   }
    950   GNUNET_break_op (0 == size);
    951   bs = GNUNET_MIN (bs,
    952                    idx);
    953   for (unsigned int i = 0; i<bs; i++)
    954     finish_job (client,
    955                 &jobs[i]);
    956   if (failure)
    957   {
    958     struct TALER_CRYPTO_SignFailure sf = {
    959       .header.size = htons (sizeof (sf)),
    960       .header.type = htons (TALER_HELPER_CS_MT_RES_BATCH_SIGN_FAILURE),
    961       .ec = htonl (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE)
    962     };
    963 
    964     GNUNET_break (0);
    965     return TES_transmit (client->csock,
    966                          &sf.header);
    967   }
    968   return GNUNET_OK;
    969 }
    970 
    971 
    972 /**
    973  * Handle @a client request @a sr to create a batch of derivations. Creates the
    974  * derivations using the respective key and return the results to the client.
    975  *
    976  * @param client the client making the request
    977  * @param bdr the request details
    978  * @return #GNUNET_OK on success
    979  */
    980 static enum GNUNET_GenericReturnValue
    981 handle_batch_derive_request (struct TES_Client *client,
    982                              const struct TALER_CRYPTO_BatchDeriveRequest *bdr)
    983 {
    984   uint32_t bs = ntohl (bdr->batch_size);
    985   uint16_t size = ntohs (bdr->header.size) - sizeof (*bdr);
    986   const void *off = (const void *) &bdr[1];
    987   unsigned int idx = 0;
    988   struct BatchJob jobs[bs];
    989   bool failure = false;
    990 
    991   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    992               "Handling batch derivation request of size %u\n",
    993               (unsigned int) bs);
    994   if (bs > TALER_MAX_COINS)
    995   {
    996     GNUNET_break_op (0);
    997     return GNUNET_SYSERR;
    998   }
    999   while ( (bs > 0) &&
   1000           (size >= sizeof (struct TALER_CRYPTO_CsRDeriveRequest)) )
   1001   {
   1002     const struct TALER_CRYPTO_CsRDeriveRequest *rdr = off;
   1003     uint16_t s = ntohs (rdr->header.size);
   1004 
   1005     if ( (s > size) ||
   1006          (s != sizeof (*rdr)) )
   1007     {
   1008       failure = true;
   1009       bs = idx;
   1010       break;
   1011     }
   1012     start_derive_job (rdr,
   1013                       &jobs[idx++]);
   1014     off += s;
   1015     size -= s;
   1016   }
   1017   GNUNET_break_op (0 == size);
   1018   bs = GNUNET_MIN (bs,
   1019                    idx);
   1020   for (unsigned int i = 0; i<bs; i++)
   1021     finish_job (client,
   1022                 &jobs[i]);
   1023   if (failure)
   1024   {
   1025     GNUNET_break (0);
   1026     return fail_derive (client,
   1027                         TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE);
   1028   }
   1029   return GNUNET_OK;
   1030 }
   1031 
   1032 
   1033 /**
   1034  * Start worker thread for batch processing.
   1035  *
   1036  * @return #GNUNET_OK on success
   1037  */
   1038 static enum GNUNET_GenericReturnValue
   1039 start_worker (void)
   1040 {
   1041   struct Worker *w;
   1042 
   1043   w = GNUNET_new (struct Worker);
   1044   sem_init (&w->sem,
   1045             0);
   1046   if (0 != pthread_create (&w->pt,
   1047                            NULL,
   1048                            &worker,
   1049                            w))
   1050   {
   1051     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
   1052                          "pthread_create");
   1053     GNUNET_free (w);
   1054     return GNUNET_SYSERR;
   1055   }
   1056   workers++;
   1057   return GNUNET_OK;
   1058 }
   1059 
   1060 
   1061 /**
   1062  * Stop all worker threads.
   1063  */
   1064 static void
   1065 stop_workers (void)
   1066 {
   1067   while (workers > 0)
   1068   {
   1069     struct Worker *w;
   1070     void *result;
   1071 
   1072     sem_down (&worker_sem);
   1073     GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
   1074     w = worker_head;
   1075     GNUNET_CONTAINER_DLL_remove (worker_head,
   1076                                  worker_tail,
   1077                                  w);
   1078     GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
   1079     w->do_shutdown = true;
   1080     sem_up (&w->sem);
   1081     pthread_join (w->pt,
   1082                   &result);
   1083     GNUNET_assert (result == w);
   1084     sem_done (&w->sem);
   1085     GNUNET_free (w);
   1086     workers--;
   1087   }
   1088 }
   1089 
   1090 
   1091 /**
   1092  * Initialize key material for denomination key @a dk (also on disk).
   1093  *
   1094  * @param[in,out] dk denomination key to compute key material for
   1095  * @param position where in the DLL will the @a dk go
   1096  * @return #GNUNET_OK on success
   1097  */
   1098 static enum GNUNET_GenericReturnValue
   1099 setup_key (struct DenominationKey *dk,
   1100            struct DenominationKey *position)
   1101 {
   1102   struct Denomination *denom = dk->denom;
   1103   struct GNUNET_CRYPTO_CsPrivateKey priv;
   1104   struct GNUNET_CRYPTO_CsPublicKey pub;
   1105 
   1106   GNUNET_CRYPTO_cs_private_key_generate (&priv);
   1107   GNUNET_CRYPTO_cs_private_key_get_public (&priv,
   1108                                            &pub);
   1109   GNUNET_CRYPTO_hash (&pub,
   1110                       sizeof (pub),
   1111                       &dk->h_cs.hash);
   1112   GNUNET_asprintf (
   1113     &dk->filename,
   1114     "%s/%s/%llu-%llu",
   1115     keydir,
   1116     denom->section,
   1117     (unsigned long long) (dk->anchor_start.abs_time.abs_value_us
   1118                           / GNUNET_TIME_UNIT_SECONDS.rel_value_us
   1119                           ),
   1120     (unsigned long long) (dk->anchor_end.abs_time.abs_value_us
   1121                           / GNUNET_TIME_UNIT_SECONDS.rel_value_us
   1122                           ));
   1123   if (GNUNET_OK !=
   1124       GNUNET_DISK_fn_write (dk->filename,
   1125                             &priv,
   1126                             sizeof(priv),
   1127                             GNUNET_DISK_PERM_USER_READ))
   1128   {
   1129     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
   1130                               "write",
   1131                               dk->filename);
   1132     return GNUNET_SYSERR;
   1133   }
   1134   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1135               "Setup fresh private key %s at %s in `%s' (generation #%llu)\n",
   1136               GNUNET_h2s (&dk->h_cs.hash),
   1137               GNUNET_TIME_timestamp2s (dk->anchor_start),
   1138               dk->filename,
   1139               (unsigned long long) key_gen);
   1140   dk->denom_priv = priv;
   1141   dk->denom_pub = pub;
   1142   dk->key_gen = key_gen;
   1143   generate_response (dk);
   1144   if (GNUNET_OK !=
   1145       GNUNET_CONTAINER_multihashmap_put (
   1146         keys,
   1147         &dk->h_cs.hash,
   1148         dk,
   1149         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
   1150   {
   1151     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1152                 "Duplicate private key created! Terminating.\n");
   1153     GNUNET_free (dk->filename);
   1154     GNUNET_free (dk->an);
   1155     GNUNET_free (dk);
   1156     return GNUNET_SYSERR;
   1157   }
   1158   GNUNET_CONTAINER_DLL_insert_after (denom->keys_head,
   1159                                      denom->keys_tail,
   1160                                      position,
   1161                                      dk);
   1162   return GNUNET_OK;
   1163 }
   1164 
   1165 
   1166 /**
   1167  * The withdraw period of a key @a dk has expired. Purge it.
   1168  *
   1169  * @param[in] dk expired denomination key to purge
   1170  */
   1171 static void
   1172 purge_key (struct DenominationKey *dk)
   1173 {
   1174   if (dk->purge)
   1175     return;
   1176   if (0 != unlink (dk->filename))
   1177     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
   1178                               "unlink",
   1179                               dk->filename);
   1180   GNUNET_free (dk->filename);
   1181   dk->purge = true;
   1182   dk->key_gen = key_gen;
   1183 }
   1184 
   1185 
   1186 /**
   1187  * A @a client informs us that a key has been revoked.
   1188  * Check if the key is still in use, and if so replace (!)
   1189  * it with a fresh key.
   1190  *
   1191  * @param client the client making the request
   1192  * @param rr the revocation request
   1193  */
   1194 static enum GNUNET_GenericReturnValue
   1195 handle_revoke_request (struct TES_Client *client,
   1196                        const struct TALER_CRYPTO_CsRevokeRequest *rr)
   1197 {
   1198   struct DenominationKey *dk;
   1199   struct DenominationKey *ndk;
   1200   struct Denomination *denom;
   1201 
   1202   (void) client;
   1203   GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
   1204   dk = GNUNET_CONTAINER_multihashmap_get (keys,
   1205                                           &rr->h_cs.hash);
   1206   if (NULL == dk)
   1207   {
   1208     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
   1209     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1210                 "Revocation request ignored, denomination key %s unknown\n",
   1211                 GNUNET_h2s (&rr->h_cs.hash));
   1212     return GNUNET_OK;
   1213   }
   1214   if (dk->purge)
   1215   {
   1216     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
   1217     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1218                 "Revocation request ignored, denomination key %s already revoked\n",
   1219                 GNUNET_h2s (&rr->h_cs.hash));
   1220     return GNUNET_OK;
   1221   }
   1222 
   1223   key_gen++;
   1224   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1225               "Revoking key %s, bumping generation to %llu\n",
   1226               GNUNET_h2s (&rr->h_cs.hash),
   1227               (unsigned long long) key_gen);
   1228   purge_key (dk);
   1229 
   1230   /* Setup replacement key */
   1231   denom = dk->denom;
   1232   ndk = GNUNET_new (struct DenominationKey);
   1233   ndk->denom = denom;
   1234   ndk->anchor_start = dk->anchor_start;
   1235   ndk->anchor_end = dk->anchor_end;
   1236   if (GNUNET_OK !=
   1237       setup_key (ndk,
   1238                  dk))
   1239   {
   1240     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
   1241     GNUNET_break (0);
   1242     GNUNET_SCHEDULER_shutdown ();
   1243     globals->global_ret = EXIT_FAILURE;
   1244     return GNUNET_SYSERR;
   1245   }
   1246   GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
   1247   TES_wake_clients ();
   1248   return GNUNET_OK;
   1249 }
   1250 
   1251 
   1252 /**
   1253  * Handle @a client request @a rdr to create signature. Create the
   1254  * signature using the respective key and return the result to
   1255  * the client.
   1256  *
   1257  * @param client the client making the request
   1258  * @param rdr the request details
   1259  * @return #GNUNET_OK on success
   1260  */
   1261 static enum GNUNET_GenericReturnValue
   1262 handle_r_derive_request (struct TES_Client *client,
   1263                          const struct TALER_CRYPTO_CsRDeriveRequest *rdr)
   1264 {
   1265   struct GNUNET_CRYPTO_CSPublicRPairP r_pub;
   1266   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
   1267   enum TALER_ErrorCode ec;
   1268   enum GNUNET_GenericReturnValue ret;
   1269 
   1270   ec = do_derive (&rdr->h_cs,
   1271                   &rdr->nonce,
   1272                   (0 != ntohl (rdr->for_melt)),
   1273                   &r_pub);
   1274   if (TALER_EC_NONE != ec)
   1275   {
   1276     return fail_derive (client,
   1277                         ec);
   1278   }
   1279 
   1280   ret = send_derivation (client,
   1281                          &r_pub);
   1282   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1283               "Sent CS Derived R after %s\n",
   1284               GNUNET_TIME_relative2s (
   1285                 GNUNET_TIME_absolute_get_duration (now),
   1286                 GNUNET_YES));
   1287   return ret;
   1288 }
   1289 
   1290 
   1291 /**
   1292  * Handle @a hdr message received from @a client.
   1293  *
   1294  * @param client the client that received the message
   1295  * @param hdr message that was received
   1296  * @return #GNUNET_OK on success
   1297  */
   1298 static enum GNUNET_GenericReturnValue
   1299 cs_work_dispatch (struct TES_Client *client,
   1300                   const struct GNUNET_MessageHeader *hdr)
   1301 {
   1302   uint16_t msize = ntohs (hdr->size);
   1303 
   1304   switch (ntohs (hdr->type))
   1305   {
   1306   case TALER_HELPER_CS_MT_REQ_SIGN:
   1307     if (msize < sizeof (struct TALER_CRYPTO_CsSignRequestMessage))
   1308     {
   1309       GNUNET_break_op (0);
   1310       return GNUNET_SYSERR;
   1311     }
   1312     return handle_sign_request (
   1313       client,
   1314       (const struct TALER_CRYPTO_CsSignRequestMessage *) hdr);
   1315   case TALER_HELPER_CS_MT_REQ_REVOKE:
   1316     if (msize != sizeof (struct TALER_CRYPTO_CsRevokeRequest))
   1317     {
   1318       GNUNET_break_op (0);
   1319       return GNUNET_SYSERR;
   1320     }
   1321     return handle_revoke_request (
   1322       client,
   1323       (const struct TALER_CRYPTO_CsRevokeRequest *) hdr);
   1324   case TALER_HELPER_CS_MT_REQ_BATCH_SIGN:
   1325     if (msize <= sizeof (struct TALER_CRYPTO_BatchSignRequest))
   1326     {
   1327       GNUNET_break_op (0);
   1328       return GNUNET_SYSERR;
   1329     }
   1330     return handle_batch_sign_request (
   1331       client,
   1332       (const struct TALER_CRYPTO_BatchSignRequest *) hdr);
   1333   case TALER_HELPER_CS_MT_REQ_BATCH_RDERIVE:
   1334     if (msize <= sizeof (struct TALER_CRYPTO_BatchDeriveRequest))
   1335     {
   1336       GNUNET_break_op (0);
   1337       return GNUNET_SYSERR;
   1338     }
   1339     return handle_batch_derive_request (
   1340       client,
   1341       (const struct TALER_CRYPTO_BatchDeriveRequest *) hdr);
   1342   case TALER_HELPER_CS_MT_REQ_RDERIVE:
   1343     if (msize != sizeof (struct TALER_CRYPTO_CsRDeriveRequest))
   1344     {
   1345       GNUNET_break_op (0);
   1346       return GNUNET_SYSERR;
   1347     }
   1348     return handle_r_derive_request (client,
   1349                                     (const struct
   1350                                      TALER_CRYPTO_CsRDeriveRequest *) hdr);
   1351   default:
   1352     GNUNET_break_op (0);
   1353     return GNUNET_SYSERR;
   1354   }
   1355 }
   1356 
   1357 
   1358 /**
   1359  * Send our initial key set to @a client together with the
   1360  * "sync" terminator.
   1361  *
   1362  * @param client the client to inform
   1363  * @return #GNUNET_OK on success
   1364  */
   1365 static enum GNUNET_GenericReturnValue
   1366 cs_client_init (struct TES_Client *client)
   1367 {
   1368   size_t obs = 0;
   1369   char *buf;
   1370 
   1371   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1372               "Initializing new client %p\n",
   1373               client);
   1374   GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
   1375   for (struct Denomination *denom = denom_head;
   1376        NULL != denom;
   1377        denom = denom->next)
   1378   {
   1379     for (struct DenominationKey *dk = denom->keys_head;
   1380          NULL != dk;
   1381          dk = dk->next)
   1382     {
   1383       obs += ntohs (dk->an->header.size);
   1384     }
   1385   }
   1386   buf = GNUNET_malloc (obs);
   1387   obs = 0;
   1388   for (struct Denomination *denom = denom_head;
   1389        NULL != denom;
   1390        denom = denom->next)
   1391   {
   1392     for (struct DenominationKey *dk = denom->keys_head;
   1393          NULL != dk;
   1394          dk = dk->next)
   1395     {
   1396       GNUNET_memcpy (&buf[obs],
   1397                      dk->an,
   1398                      ntohs (dk->an->header.size));
   1399       obs += ntohs (dk->an->header.size);
   1400     }
   1401   }
   1402   client->key_gen = key_gen;
   1403   GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
   1404   if (GNUNET_OK !=
   1405       TES_transmit_raw (client->csock,
   1406                         obs,
   1407                         buf))
   1408   {
   1409     GNUNET_free (buf);
   1410     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1411                 "Client %p must have disconnected\n",
   1412                 client);
   1413     return GNUNET_SYSERR;
   1414   }
   1415   GNUNET_free (buf);
   1416   {
   1417     struct GNUNET_MessageHeader synced = {
   1418       .type = htons (TALER_HELPER_CS_SYNCED),
   1419       .size = htons (sizeof (synced))
   1420     };
   1421 
   1422     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1423                 "Sending CS SYNCED message to %p\n",
   1424                 client);
   1425     if (GNUNET_OK !=
   1426         TES_transmit (client->csock,
   1427                       &synced))
   1428     {
   1429       GNUNET_break (0);
   1430       return GNUNET_SYSERR;
   1431     }
   1432   }
   1433   return GNUNET_OK;
   1434 }
   1435 
   1436 
   1437 /**
   1438  * Notify @a client about all changes to the keys since
   1439  * the last generation known to the @a client.
   1440  *
   1441  * @param client the client to notify
   1442  * @return #GNUNET_OK on success
   1443  */
   1444 static enum GNUNET_GenericReturnValue
   1445 cs_update_client_keys (struct TES_Client *client)
   1446 {
   1447   size_t obs = 0;
   1448   char *buf;
   1449   enum GNUNET_GenericReturnValue ret;
   1450 
   1451   GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
   1452   for (struct Denomination *denom = denom_head;
   1453        NULL != denom;
   1454        denom = denom->next)
   1455   {
   1456     for (struct DenominationKey *key = denom->keys_head;
   1457          NULL != key;
   1458          key = key->next)
   1459     {
   1460       if (key->key_gen <= client->key_gen)
   1461         continue;
   1462       if (key->purge)
   1463         obs += sizeof (struct TALER_CRYPTO_CsKeyPurgeNotification);
   1464       else
   1465         obs += ntohs (key->an->header.size);
   1466     }
   1467   }
   1468   if (0 == obs)
   1469   {
   1470     /* nothing to do */
   1471     client->key_gen = key_gen;
   1472     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
   1473     return GNUNET_OK;
   1474   }
   1475   buf = GNUNET_malloc (obs);
   1476   obs = 0;
   1477   for (struct Denomination *denom = denom_head;
   1478        NULL != denom;
   1479        denom = denom->next)
   1480   {
   1481     for (struct DenominationKey *key = denom->keys_head;
   1482          NULL != key;
   1483          key = key->next)
   1484     {
   1485       if (key->key_gen <= client->key_gen)
   1486         continue;
   1487       if (key->purge)
   1488       {
   1489         struct TALER_CRYPTO_CsKeyPurgeNotification pn = {
   1490           .header.type = htons (TALER_HELPER_CS_MT_PURGE),
   1491           .header.size = htons (sizeof (pn)),
   1492           .h_cs = key->h_cs
   1493         };
   1494 
   1495         GNUNET_memcpy (&buf[obs],
   1496                        &pn,
   1497                        sizeof (pn));
   1498         GNUNET_assert (obs + sizeof (pn)
   1499                        > obs);
   1500         obs += sizeof (pn);
   1501       }
   1502       else
   1503       {
   1504         GNUNET_memcpy (&buf[obs],
   1505                        key->an,
   1506                        ntohs (key->an->header.size));
   1507         GNUNET_assert (obs + ntohs (key->an->header.size)
   1508                        > obs);
   1509         obs += ntohs (key->an->header.size);
   1510       }
   1511     }
   1512   }
   1513   client->key_gen = key_gen;
   1514   GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
   1515   ret = TES_transmit_raw (client->csock,
   1516                           obs,
   1517                           buf);
   1518   GNUNET_free (buf);
   1519   return ret;
   1520 }
   1521 
   1522 
   1523 /**
   1524  * Create a new denomination key (we do not have enough).
   1525  *
   1526  * @param[in,out] denom denomination key to create
   1527  * @param anchor_start when to start key signing validity
   1528  * @param anchor_end when to end key signing validity
   1529  * @return #GNUNET_OK on success
   1530  */
   1531 static enum GNUNET_GenericReturnValue
   1532 create_key (struct Denomination *denom,
   1533             struct GNUNET_TIME_Timestamp anchor_start,
   1534             struct GNUNET_TIME_Timestamp anchor_end)
   1535 {
   1536   struct DenominationKey *dk;
   1537 
   1538   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1539               "Creating new key for `%s' with start date %s\n",
   1540               denom->section,
   1541               GNUNET_TIME_timestamp2s (anchor_start));
   1542   dk = GNUNET_new (struct DenominationKey);
   1543   dk->denom = denom;
   1544   dk->anchor_start = anchor_start;
   1545   dk->anchor_end = anchor_end;
   1546   if (GNUNET_OK !=
   1547       setup_key (dk,
   1548                  denom->keys_tail))
   1549   {
   1550     GNUNET_break (0);
   1551     GNUNET_free (dk);
   1552     GNUNET_SCHEDULER_shutdown ();
   1553     globals->global_ret = EXIT_FAILURE;
   1554     return GNUNET_SYSERR;
   1555   }
   1556   return GNUNET_OK;
   1557 }
   1558 
   1559 
   1560 /**
   1561  * Obtain the maximum withdraw duration of all denominations.
   1562  *
   1563  * Must only be called while the #keys_lock is held.
   1564  *
   1565  * @return maximum withdraw duration, zero if there are no denominations
   1566  */
   1567 static struct GNUNET_TIME_Relative
   1568 get_maximum_duration (void)
   1569 {
   1570   struct GNUNET_TIME_Relative ret
   1571     = GNUNET_TIME_UNIT_ZERO;
   1572 
   1573   for (struct Denomination *denom = denom_head;
   1574        NULL != denom;
   1575        denom = denom->next)
   1576   {
   1577     ret = GNUNET_TIME_relative_max (ret,
   1578                                     denom->duration_withdraw);
   1579   }
   1580   return ret;
   1581 }
   1582 
   1583 
   1584 /**
   1585  * At what time do we need to next create keys if we just did?
   1586  *
   1587  * @return time when to next create keys if we just finished key generation
   1588  */
   1589 static struct GNUNET_TIME_Absolute
   1590 action_time (void)
   1591 {
   1592   struct GNUNET_TIME_Relative md = get_maximum_duration ();
   1593   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
   1594   uint64_t mod;
   1595 
   1596   if (GNUNET_TIME_relative_is_zero (md))
   1597     return GNUNET_TIME_UNIT_FOREVER_ABS;
   1598   mod = now.abs_value_us % md.rel_value_us;
   1599   now.abs_value_us -= mod;
   1600   return GNUNET_TIME_absolute_add (now,
   1601                                    md);
   1602 }
   1603 
   1604 
   1605 /**
   1606  * Remove all denomination keys of @a denom that have expired.
   1607  *
   1608  * @param[in,out] denom denomination family to remove keys for
   1609  */
   1610 static void
   1611 remove_expired_denomination_keys (struct Denomination *denom)
   1612 {
   1613   while ( (NULL != denom->keys_head) &&
   1614           GNUNET_TIME_absolute_is_past (
   1615             denom->keys_head->anchor_end.abs_time) )
   1616   {
   1617     struct DenominationKey *key = denom->keys_head;
   1618     struct DenominationKey *nxt = key->next;
   1619 
   1620     if (0 != key->rc)
   1621       break; /* later */
   1622     GNUNET_CONTAINER_DLL_remove (denom->keys_head,
   1623                                  denom->keys_tail,
   1624                                  key);
   1625     GNUNET_assert (GNUNET_OK ==
   1626                    GNUNET_CONTAINER_multihashmap_remove (
   1627                      keys,
   1628                      &key->h_cs.hash,
   1629                      key));
   1630     if ( (! key->purge) &&
   1631          (0 != unlink (key->filename)) )
   1632       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
   1633                                 "unlink",
   1634                                 key->filename);
   1635     GNUNET_free (key->filename);
   1636     GNUNET_free (key->an);
   1637     GNUNET_free (key);
   1638     key = nxt;
   1639   }
   1640 }
   1641 
   1642 
   1643 /**
   1644  * Obtain the end anchor to use at this point. Uses the
   1645  * #lookahead_sign and then rounds it up by the maximum
   1646  * duration of any denomination to arrive at a globally
   1647  * valid end-date.
   1648  *
   1649  * Must only be called while the #keys_lock is held.
   1650  *
   1651  * @return end anchor
   1652  */
   1653 static struct GNUNET_TIME_Timestamp
   1654 get_anchor_end (void)
   1655 {
   1656   struct GNUNET_TIME_Relative md = get_maximum_duration ();
   1657   struct GNUNET_TIME_Absolute end
   1658     = GNUNET_TIME_relative_to_absolute (lookahead_sign);
   1659   uint64_t mod;
   1660 
   1661   if (GNUNET_TIME_relative_is_zero (md))
   1662     return GNUNET_TIME_UNIT_ZERO_TS;
   1663   /* Round up 'end' to a multiple of 'md' */
   1664   mod = end.abs_value_us % md.rel_value_us;
   1665   end.abs_value_us -= mod;
   1666   return GNUNET_TIME_absolute_to_timestamp (
   1667     GNUNET_TIME_absolute_add (end,
   1668                               md));
   1669 }
   1670 
   1671 
   1672 /**
   1673  * Create all denomination keys that are required for our
   1674  * desired lookahead and that we do not yet have.
   1675  *
   1676  * @param[in,out] opt our options
   1677  * @param[in,out] wake set to true if we should wake the clients
   1678  */
   1679 static void
   1680 create_missing_keys (struct TALER_SECMOD_Options *opt,
   1681                      bool *wake)
   1682 {
   1683   struct GNUNET_TIME_Timestamp start;
   1684   struct GNUNET_TIME_Timestamp end;
   1685 
   1686   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1687               "Updating denominations ...\n");
   1688   start = opt->global_now;
   1689   GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
   1690   end = get_anchor_end ();
   1691   for (struct Denomination *denom = denom_head;
   1692        NULL != denom;
   1693        denom = denom->next)
   1694   {
   1695     struct GNUNET_TIME_Timestamp anchor_start;
   1696     struct GNUNET_TIME_Timestamp anchor_end;
   1697     struct GNUNET_TIME_Timestamp next_end;
   1698     bool finished = false;
   1699 
   1700     remove_expired_denomination_keys (denom);
   1701     if (NULL != denom->keys_tail)
   1702     {
   1703       anchor_start = denom->keys_tail->anchor_end;
   1704       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1705                   "Expanding keys of denomination `%s', last key %s valid for another %s\n",
   1706                   denom->section,
   1707                   GNUNET_h2s (&denom->keys_tail->h_cs.hash),
   1708                   GNUNET_TIME_relative2s (
   1709                     GNUNET_TIME_absolute_get_remaining (
   1710                       anchor_start.abs_time),
   1711                     true));
   1712     }
   1713     else
   1714     {
   1715       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1716                   "Starting keys of denomination `%s'\n",
   1717                   denom->section);
   1718       anchor_start = start;
   1719     }
   1720     finished = GNUNET_TIME_timestamp_cmp (anchor_start,
   1721                                           >=,
   1722                                           end);
   1723     while (! finished)
   1724     {
   1725       anchor_end = GNUNET_TIME_absolute_to_timestamp (
   1726         GNUNET_TIME_absolute_add (anchor_start.abs_time,
   1727                                   denom->duration_withdraw));
   1728       next_end = GNUNET_TIME_absolute_to_timestamp (
   1729         GNUNET_TIME_absolute_add (anchor_end.abs_time,
   1730                                   denom->duration_withdraw));
   1731       if (GNUNET_TIME_timestamp_cmp (next_end,
   1732                                      >,
   1733                                      end))
   1734       {
   1735         anchor_end = end; /* extend period to align end periods */
   1736         finished = true;
   1737       }
   1738       /* adjust start time down to ensure overlap */
   1739       anchor_start = GNUNET_TIME_absolute_to_timestamp (
   1740         GNUNET_TIME_absolute_subtract (anchor_start.abs_time,
   1741                                        overlap_duration));
   1742       if (! *wake)
   1743       {
   1744         key_gen++;
   1745         *wake = true;
   1746       }
   1747       if (GNUNET_OK !=
   1748           create_key (denom,
   1749                       anchor_start,
   1750                       anchor_end))
   1751       {
   1752         GNUNET_break (0);
   1753         GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
   1754         globals->global_ret = EXIT_FAILURE;
   1755         GNUNET_SCHEDULER_shutdown ();
   1756         return;
   1757       }
   1758       anchor_start = anchor_end;
   1759     }
   1760     remove_expired_denomination_keys (denom);
   1761   }
   1762   GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
   1763   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1764               "Updating denominations finished ...\n");
   1765 }
   1766 
   1767 
   1768 /**
   1769  * Task run periodically to expire keys and/or generate fresh ones.
   1770  *
   1771  * @param cls the `struct TALER_SECMOD_Options *`
   1772  */
   1773 static void
   1774 update_denominations (void *cls)
   1775 {
   1776   struct TALER_SECMOD_Options *opt = cls;
   1777   struct GNUNET_TIME_Absolute at;
   1778   bool wake = false;
   1779 
   1780   (void) cls;
   1781   keygen_task = NULL;
   1782   opt->global_now = GNUNET_TIME_timestamp_get ();
   1783   create_missing_keys (opt,
   1784                        &wake);
   1785   if (wake)
   1786     TES_wake_clients ();
   1787   at = action_time ();
   1788   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1789               "Next key generation due at %s\n",
   1790               GNUNET_TIME_absolute2s (at));
   1791   keygen_task = GNUNET_SCHEDULER_add_at (at,
   1792                                          &update_denominations,
   1793                                          opt);
   1794 }
   1795 
   1796 
   1797 /**
   1798  * Parse private key of denomination @a denom in @a buf.
   1799  *
   1800  * @param[out] denom denomination of the key
   1801  * @param filename name of the file we are parsing, for logging
   1802  * @param priv key material
   1803  */
   1804 static void
   1805 parse_key (struct Denomination *denom,
   1806            const char *filename,
   1807            const struct GNUNET_CRYPTO_CsPrivateKey *priv)
   1808 {
   1809   char *anchor_s;
   1810   char dummy;
   1811   unsigned long long anchor_start_ll;
   1812   unsigned long long anchor_end_ll;
   1813   struct GNUNET_TIME_Timestamp anchor_start;
   1814   struct GNUNET_TIME_Timestamp anchor_end;
   1815   char *nf = NULL;
   1816 
   1817   anchor_s = strrchr (filename,
   1818                       '/');
   1819   if (NULL == anchor_s)
   1820   {
   1821     /* File in a directory without '/' in the name, this makes no sense. */
   1822     GNUNET_break (0);
   1823     return;
   1824   }
   1825   anchor_s++;
   1826   if (2 != sscanf (anchor_s,
   1827                    "%llu-%llu%c",
   1828                    &anchor_start_ll,
   1829                    &anchor_end_ll,
   1830                    &dummy))
   1831   {
   1832     /* try legacy mode */
   1833     if (1 != sscanf (anchor_s,
   1834                      "%llu%c",
   1835                      &anchor_start_ll,
   1836                      &dummy))
   1837     {
   1838       /* Filenames in KEYDIR must ONLY be the anchor time in seconds! */
   1839       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1840                   "Filename `%s' invalid for key file, skipping\n",
   1841                   anchor_s);
   1842       return;
   1843     }
   1844     anchor_start.abs_time.abs_value_us
   1845       = anchor_start_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us;
   1846     if (anchor_start_ll != anchor_start.abs_time.abs_value_us
   1847         / GNUNET_TIME_UNIT_SECONDS.rel_value_us)
   1848     {
   1849       /* Integer overflow. Bad, invalid filename. */
   1850       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1851                   "Integer overflow. Filename `%s' invalid for key file, skipping\n",
   1852                   anchor_s);
   1853       return;
   1854     }
   1855     anchor_end
   1856       = GNUNET_TIME_absolute_to_timestamp (
   1857           GNUNET_TIME_absolute_add (anchor_start.abs_time,
   1858                                     denom->duration_withdraw));
   1859     GNUNET_asprintf (
   1860       &nf,
   1861       "%s/%s/%llu-%llu",
   1862       keydir,
   1863       denom->section,
   1864       anchor_start_ll,
   1865       (unsigned long long) (anchor_end.abs_time.abs_value_us
   1866                             / GNUNET_TIME_UNIT_SECONDS.rel_value_us));
   1867     /* Try to fix the legacy filename */
   1868     if (0 !=
   1869         rename (filename,
   1870                 nf))
   1871     {
   1872       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
   1873                                 "rename",
   1874                                 filename);
   1875       GNUNET_free (nf);
   1876     }
   1877   }
   1878   else
   1879   {
   1880     anchor_start.abs_time.abs_value_us
   1881       = anchor_start_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us;
   1882     anchor_end.abs_time.abs_value_us
   1883       = anchor_end_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us;
   1884     if ( (anchor_start_ll != anchor_start.abs_time.abs_value_us
   1885           / GNUNET_TIME_UNIT_SECONDS.rel_value_us) ||
   1886          (anchor_end_ll != anchor_end.abs_time.abs_value_us
   1887           / GNUNET_TIME_UNIT_SECONDS.rel_value_us) )
   1888     {
   1889       /* Integer overflow. Bad, invalid filename. */
   1890       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1891                   "Integer overflow. Filename `%s' invalid for key file, skipping\n",
   1892                   anchor_s);
   1893       return;
   1894     }
   1895   }
   1896 
   1897   {
   1898     struct DenominationKey *dk;
   1899     struct DenominationKey *before;
   1900 
   1901     dk = GNUNET_new (struct DenominationKey);
   1902     dk->denom_priv = *priv;
   1903     dk->denom = denom;
   1904     dk->anchor_start = anchor_start;
   1905     dk->anchor_end = anchor_end;
   1906     dk->filename = (NULL == nf) ? GNUNET_strdup (filename) : nf;
   1907     GNUNET_CRYPTO_cs_private_key_get_public (priv,
   1908                                              &dk->denom_pub);
   1909     GNUNET_CRYPTO_hash (&dk->denom_pub,
   1910                         sizeof (dk->denom_pub),
   1911                         &dk->h_cs.hash);
   1912     generate_response (dk);
   1913     if (GNUNET_OK !=
   1914         GNUNET_CONTAINER_multihashmap_put (
   1915           keys,
   1916           &dk->h_cs.hash,
   1917           dk,
   1918           GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
   1919     {
   1920       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1921                   "Duplicate private key %s detected in file `%s'. Skipping.\n",
   1922                   GNUNET_h2s (&dk->h_cs.hash),
   1923                   filename);
   1924       GNUNET_free (dk->an);
   1925       GNUNET_free (dk);
   1926       return;
   1927     }
   1928     before = NULL;
   1929     for (struct DenominationKey *pos = denom->keys_head;
   1930          NULL != pos;
   1931          pos = pos->next)
   1932     {
   1933       if (GNUNET_TIME_timestamp_cmp (pos->anchor_start,
   1934                                      >,
   1935                                      anchor_start))
   1936         break;
   1937       before = pos;
   1938     }
   1939     GNUNET_CONTAINER_DLL_insert_after (denom->keys_head,
   1940                                        denom->keys_tail,
   1941                                        before,
   1942                                        dk);
   1943     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1944                 "Imported key %s from `%s'\n",
   1945                 GNUNET_h2s (&dk->h_cs.hash),
   1946                 filename);
   1947   }
   1948 }
   1949 
   1950 
   1951 /**
   1952  * Import a private key from @a filename for the denomination
   1953  * given in @a cls.
   1954  *
   1955  * @param[in,out] cls a `struct Denomiantion`
   1956  * @param filename name of a file in the directory
   1957  * @return #GNUNET_OK (always, continue to iterate)
   1958  */
   1959 static enum GNUNET_GenericReturnValue
   1960 import_key (void *cls,
   1961             const char *filename)
   1962 {
   1963   struct Denomination *denom = cls;
   1964   struct GNUNET_DISK_FileHandle *fh;
   1965   struct GNUNET_DISK_MapHandle *map;
   1966   void *ptr;
   1967   int fd;
   1968   struct stat sbuf;
   1969 
   1970   {
   1971     struct stat lsbuf;
   1972 
   1973     if (0 != lstat (filename,
   1974                     &lsbuf))
   1975     {
   1976       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
   1977                                 "lstat",
   1978                                 filename);
   1979       return GNUNET_OK;
   1980     }
   1981     if (! S_ISREG (lsbuf.st_mode))
   1982     {
   1983       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1984                   "File `%s' is not a regular file, which is not allowed for private keys!\n",
   1985                   filename);
   1986       return GNUNET_OK;
   1987     }
   1988   }
   1989 
   1990   fd = open (filename,
   1991              O_RDONLY | O_CLOEXEC);
   1992   if (-1 == fd)
   1993   {
   1994     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
   1995                               "open",
   1996                               filename);
   1997     return GNUNET_OK;
   1998   }
   1999   if (0 != fstat (fd,
   2000                   &sbuf))
   2001   {
   2002     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
   2003                               "stat",
   2004                               filename);
   2005     GNUNET_break (0 == close (fd));
   2006     return GNUNET_OK;
   2007   }
   2008   if (! S_ISREG (sbuf.st_mode))
   2009   {
   2010     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2011                 "File `%s' is not a regular file, which is not allowed for private keys!\n",
   2012                 filename);
   2013     GNUNET_break (0 == close (fd));
   2014     return GNUNET_OK;
   2015   }
   2016   if (0 != (sbuf.st_mode & (S_IWUSR | S_IRWXG | S_IRWXO)))
   2017   {
   2018     /* permission are NOT tight, try to patch them up! */
   2019     if (0 !=
   2020         fchmod (fd,
   2021                 S_IRUSR))
   2022     {
   2023       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
   2024                                 "fchmod",
   2025                                 filename);
   2026       /* refuse to use key if file has wrong permissions */
   2027       GNUNET_break (0 == close (fd));
   2028       return GNUNET_OK;
   2029     }
   2030   }
   2031   fh = GNUNET_DISK_get_handle_from_int_fd (fd);
   2032   if (NULL == fh)
   2033   {
   2034     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
   2035                               "open",
   2036                               filename);
   2037     GNUNET_break (0 == close (fd));
   2038     return GNUNET_OK;
   2039   }
   2040   if (sbuf.st_size != sizeof(struct GNUNET_CRYPTO_CsPrivateKey))
   2041   {
   2042     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2043                 "File `%s' too big to be a private key\n",
   2044                 filename);
   2045     GNUNET_DISK_file_close (fh);
   2046     return GNUNET_OK;
   2047   }
   2048   ptr = GNUNET_DISK_file_map (fh,
   2049                               &map,
   2050                               GNUNET_DISK_MAP_TYPE_READ,
   2051                               (size_t) sbuf.st_size);
   2052   if (NULL == ptr)
   2053   {
   2054     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
   2055                               "mmap",
   2056                               filename);
   2057     GNUNET_DISK_file_close (fh);
   2058     return GNUNET_OK;
   2059   }
   2060   parse_key (denom,
   2061              filename,
   2062              (const struct GNUNET_CRYPTO_CsPrivateKey *) ptr);
   2063   GNUNET_DISK_file_unmap (map);
   2064   GNUNET_DISK_file_close (fh);
   2065   return GNUNET_OK;
   2066 }
   2067 
   2068 
   2069 /**
   2070  * Parse configuration for denomination type parameters.  Also determines
   2071  * our anchor by looking at the existing denominations of the same type.
   2072  *
   2073  * @param cfg configuration to use
   2074  * @param ct section in the configuration file giving the denomination type parameters
   2075  * @param[out] denom set to the denomination parameters from the configuration
   2076  * @return #GNUNET_OK on success, #GNUNET_SYSERR if the configuration is invalid
   2077  */
   2078 static enum GNUNET_GenericReturnValue
   2079 parse_denomination_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg,
   2080                         const char *ct,
   2081                         struct Denomination *denom)
   2082 {
   2083   char *secname;
   2084 
   2085   GNUNET_asprintf (&secname,
   2086                    "%s-secmod-cs",
   2087                    globals->section);
   2088   if (GNUNET_OK !=
   2089       GNUNET_CONFIGURATION_get_value_time (cfg,
   2090                                            ct,
   2091                                            "DURATION_WITHDRAW",
   2092                                            &denom->duration_withdraw))
   2093   {
   2094     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2095                                ct,
   2096                                "DURATION_WITHDRAW");
   2097     GNUNET_free (secname);
   2098     return GNUNET_SYSERR;
   2099   }
   2100   if (GNUNET_TIME_relative_cmp (denom->duration_withdraw,
   2101                                 <,
   2102                                 GNUNET_TIME_UNIT_SECONDS))
   2103   {
   2104     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2105                                ct,
   2106                                "DURATION_WITHDRAW",
   2107                                "less than one second is not supported");
   2108     GNUNET_free (secname);
   2109     return GNUNET_SYSERR;
   2110   }
   2111   if (GNUNET_TIME_relative_cmp (overlap_duration,
   2112                                 >=,
   2113                                 denom->duration_withdraw))
   2114   {
   2115     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2116                                secname,
   2117                                "OVERLAP_DURATION",
   2118                                "Value given must be smaller than value for DURATION_WITHDRAW!");
   2119     GNUNET_free (secname);
   2120     return GNUNET_SYSERR;
   2121   }
   2122   GNUNET_free (secname);
   2123   denom->section = GNUNET_strdup (ct);
   2124   return GNUNET_OK;
   2125 }
   2126 
   2127 
   2128 /**
   2129  * Closure for #load_denominations.
   2130  */
   2131 struct LoadContext
   2132 {
   2133 
   2134   /**
   2135    * Configuration to use.
   2136    */
   2137   const struct GNUNET_CONFIGURATION_Handle *cfg;
   2138 
   2139   /**
   2140    * Current time to use.
   2141    */
   2142   struct GNUNET_TIME_Timestamp t;
   2143 
   2144   /**
   2145    * Status, to be set to #GNUNET_SYSERR on failure
   2146    */
   2147   enum GNUNET_GenericReturnValue ret;
   2148 };
   2149 
   2150 
   2151 /**
   2152  * Generate new denomination signing keys for the denomination type of the given @a
   2153  * denomination_alias.
   2154  *
   2155  * @param cls a `struct LoadContext`, with 'ret' to be set to #GNUNET_SYSERR on failure
   2156  * @param denomination_alias name of the denomination's section in the configuration
   2157  */
   2158 static void
   2159 load_denominations (void *cls,
   2160                     const char *denomination_alias)
   2161 {
   2162   struct LoadContext *ctx = cls;
   2163   struct Denomination *denom;
   2164   char *cipher;
   2165 
   2166   if ( (0 != strncasecmp (denomination_alias,
   2167                           "coin_",
   2168                           strlen ("coin_"))) &&
   2169        (0 != strncasecmp (denomination_alias,
   2170                           "coin-",
   2171                           strlen ("coin-"))) )
   2172     return; /* not a denomination type definition */
   2173   if (GNUNET_OK !=
   2174       GNUNET_CONFIGURATION_get_value_string (ctx->cfg,
   2175                                              denomination_alias,
   2176                                              "CIPHER",
   2177                                              &cipher))
   2178   {
   2179     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2180                                denomination_alias,
   2181                                "CIPHER");
   2182     return;
   2183   }
   2184   if (0 != strcmp (cipher, "CS"))
   2185   {
   2186     GNUNET_free (cipher);
   2187     return; /* Ignore denominations of other types than CS*/
   2188   }
   2189   GNUNET_free (cipher);
   2190 
   2191   denom = GNUNET_new (struct Denomination);
   2192   if (GNUNET_OK !=
   2193       parse_denomination_cfg (ctx->cfg,
   2194                               denomination_alias,
   2195                               denom))
   2196   {
   2197     ctx->ret = GNUNET_SYSERR;
   2198     GNUNET_free (denom);
   2199     return;
   2200   }
   2201   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2202               "Loading keys for denomination %s\n",
   2203               denom->section);
   2204   {
   2205     char *dname;
   2206 
   2207     GNUNET_asprintf (&dname,
   2208                      "%s/%s",
   2209                      keydir,
   2210                      denom->section);
   2211     GNUNET_break (GNUNET_OK ==
   2212                   GNUNET_DISK_directory_create (dname));
   2213     GNUNET_DISK_directory_scan (dname,
   2214                                 &import_key,
   2215                                 denom);
   2216     GNUNET_free (dname);
   2217   }
   2218   GNUNET_CONTAINER_DLL_insert (denom_head,
   2219                                denom_tail,
   2220                                denom);
   2221 }
   2222 
   2223 
   2224 /**
   2225  * Load the various duration values from @a cfg
   2226  *
   2227  * @param cfg configuration to use
   2228  * @return #GNUNET_OK on success
   2229  */
   2230 static enum GNUNET_GenericReturnValue
   2231 load_durations (const struct GNUNET_CONFIGURATION_Handle *cfg)
   2232 {
   2233   char *secname;
   2234 
   2235   GNUNET_asprintf (&secname,
   2236                    "%s-secmod-cs",
   2237                    globals->section);
   2238   if (GNUNET_OK !=
   2239       GNUNET_CONFIGURATION_get_value_time (cfg,
   2240                                            secname,
   2241                                            "OVERLAP_DURATION",
   2242                                            &overlap_duration))
   2243   {
   2244     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2245                                secname,
   2246                                "OVERLAP_DURATION");
   2247     GNUNET_free (secname);
   2248     return GNUNET_SYSERR;
   2249   }
   2250   if (GNUNET_OK !=
   2251       GNUNET_CONFIGURATION_get_value_time (cfg,
   2252                                            secname,
   2253                                            "LOOKAHEAD_SIGN",
   2254                                            &lookahead_sign))
   2255   {
   2256     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2257                                secname,
   2258                                "LOOKAHEAD_SIGN");
   2259     GNUNET_free (secname);
   2260     return GNUNET_SYSERR;
   2261   }
   2262   GNUNET_free (secname);
   2263   return GNUNET_OK;
   2264 }
   2265 
   2266 
   2267 /**
   2268  * Function run on shutdown. Stops the various jobs (nicely).
   2269  *
   2270  * @param cls a `struct TALER_SECMOD_Options`
   2271  */
   2272 static void
   2273 do_shutdown (void *cls)
   2274 {
   2275   (void) cls;
   2276   TES_listen_stop ();
   2277   if (NULL != keygen_task)
   2278   {
   2279     GNUNET_SCHEDULER_cancel (keygen_task);
   2280     keygen_task = NULL;
   2281   }
   2282   stop_workers ();
   2283   sem_done (&worker_sem);
   2284 }
   2285 
   2286 
   2287 void
   2288 TALER_SECMOD_cs_run (void *cls,
   2289                      char *const *args,
   2290                      const char *cfgfile,
   2291                      const struct GNUNET_CONFIGURATION_Handle *cfg)
   2292 {
   2293   static struct TES_Callbacks cb = {
   2294     .dispatch = &cs_work_dispatch,
   2295     .updater = &cs_update_client_keys,
   2296     .init = &cs_client_init
   2297   };
   2298   struct TALER_SECMOD_Options *opt = cls;
   2299   char *secname;
   2300 
   2301   (void) args;
   2302   (void) cfgfile;
   2303   globals = opt;
   2304   if (GNUNET_TIME_timestamp_cmp (opt->global_now,
   2305                                  !=,
   2306                                  opt->global_now_tmp))
   2307   {
   2308     /* The user gave "--now", use it! */
   2309     opt->global_now = opt->global_now_tmp;
   2310   }
   2311   else
   2312   {
   2313     /* get current time again, we may be timetraveling! */
   2314     opt->global_now = GNUNET_TIME_timestamp_get ();
   2315   }
   2316   GNUNET_asprintf (&secname,
   2317                    "%s-secmod-cs",
   2318                    opt->section);
   2319   if (GNUNET_OK !=
   2320       GNUNET_CONFIGURATION_get_value_filename (cfg,
   2321                                                secname,
   2322                                                "KEY_DIR",
   2323                                                &keydir))
   2324   {
   2325     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2326                                secname,
   2327                                "KEY_DIR");
   2328     GNUNET_free (secname);
   2329     opt->global_ret = EXIT_NOTCONFIGURED;
   2330     return;
   2331   }
   2332   if (GNUNET_OK !=
   2333       load_durations (cfg))
   2334   {
   2335     opt->global_ret = EXIT_NOTCONFIGURED;
   2336     GNUNET_free (secname);
   2337     return;
   2338   }
   2339   opt->global_ret = TES_listen_start (cfg,
   2340                                       secname,
   2341                                       &cb);
   2342   GNUNET_free (secname);
   2343   if (0 != opt->global_ret)
   2344     return;
   2345   sem_init (&worker_sem,
   2346             0);
   2347   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
   2348                                  opt);
   2349   if (0 == opt->max_workers)
   2350   {
   2351     long lret;
   2352 
   2353     lret = sysconf (_SC_NPROCESSORS_CONF);
   2354     if (lret <= 0)
   2355       lret = 1;
   2356     opt->max_workers = (unsigned int) lret;
   2357   }
   2358   for (unsigned int i = 0; i<opt->max_workers; i++)
   2359     if (GNUNET_OK !=
   2360         start_worker ())
   2361     {
   2362       GNUNET_SCHEDULER_shutdown ();
   2363       return;
   2364     }
   2365   /* Load denominations */
   2366   keys = GNUNET_CONTAINER_multihashmap_create (65536,
   2367                                                true);
   2368   {
   2369     struct LoadContext lc = {
   2370       .cfg = cfg,
   2371       .ret = GNUNET_OK,
   2372       .t = opt->global_now
   2373     };
   2374     bool wake = true;
   2375 
   2376     GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
   2377     GNUNET_CONFIGURATION_iterate_sections (cfg,
   2378                                            &load_denominations,
   2379                                            &lc);
   2380     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
   2381     if (GNUNET_OK != lc.ret)
   2382     {
   2383       opt->global_ret = EXIT_FAILURE;
   2384       GNUNET_SCHEDULER_shutdown ();
   2385       return;
   2386     }
   2387     create_missing_keys (opt,
   2388                          &wake);
   2389   }
   2390   if (NULL == denom_head)
   2391   {
   2392     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   2393                 "No CS denominations configured. Make sure section names start with `%s' if you are using CS!\n",
   2394                 opt->section);
   2395     TES_wake_clients ();
   2396     return;
   2397   }
   2398   /* start job to keep keys up-to-date; MUST be run before the #listen_task,
   2399      hence with priority. */
   2400   keygen_task = GNUNET_SCHEDULER_add_with_priority (
   2401     GNUNET_SCHEDULER_PRIORITY_URGENT,
   2402     &update_denominations,
   2403     opt);
   2404 }