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


      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 "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_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         return;
   1754       }
   1755       anchor_start = anchor_end;
   1756     }
   1757     remove_expired_denomination_keys (denom);
   1758   }
   1759   GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
   1760   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1761               "Updating denominations finished ...\n");
   1762 }
   1763 
   1764 
   1765 /**
   1766  * Task run periodically to expire keys and/or generate fresh ones.
   1767  *
   1768  * @param cls the `struct TALER_SECMOD_Options *`
   1769  */
   1770 static void
   1771 update_denominations (void *cls)
   1772 {
   1773   struct TALER_SECMOD_Options *opt = cls;
   1774   struct GNUNET_TIME_Absolute at;
   1775   bool wake = false;
   1776 
   1777   (void) cls;
   1778   keygen_task = NULL;
   1779   opt->global_now = GNUNET_TIME_timestamp_get ();
   1780   create_missing_keys (opt,
   1781                        &wake);
   1782   if (wake)
   1783     TES_wake_clients ();
   1784   at = action_time ();
   1785   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1786               "Next key generation due at %s\n",
   1787               GNUNET_TIME_absolute2s (at));
   1788   keygen_task = GNUNET_SCHEDULER_add_at (at,
   1789                                          &update_denominations,
   1790                                          opt);
   1791 }
   1792 
   1793 
   1794 /**
   1795  * Parse private key of denomination @a denom in @a buf.
   1796  *
   1797  * @param[out] denom denomination of the key
   1798  * @param filename name of the file we are parsing, for logging
   1799  * @param priv key material
   1800  */
   1801 static void
   1802 parse_key (struct Denomination *denom,
   1803            const char *filename,
   1804            const struct GNUNET_CRYPTO_CsPrivateKey *priv)
   1805 {
   1806   char *anchor_s;
   1807   char dummy;
   1808   unsigned long long anchor_start_ll;
   1809   unsigned long long anchor_end_ll;
   1810   struct GNUNET_TIME_Timestamp anchor_start;
   1811   struct GNUNET_TIME_Timestamp anchor_end;
   1812   char *nf = NULL;
   1813 
   1814   anchor_s = strrchr (filename,
   1815                       '/');
   1816   if (NULL == anchor_s)
   1817   {
   1818     /* File in a directory without '/' in the name, this makes no sense. */
   1819     GNUNET_break (0);
   1820     return;
   1821   }
   1822   anchor_s++;
   1823   if (2 != sscanf (anchor_s,
   1824                    "%llu-%llu%c",
   1825                    &anchor_start_ll,
   1826                    &anchor_end_ll,
   1827                    &dummy))
   1828   {
   1829     /* try legacy mode */
   1830     if (1 != sscanf (anchor_s,
   1831                      "%llu%c",
   1832                      &anchor_start_ll,
   1833                      &dummy))
   1834     {
   1835       /* Filenames in KEYDIR must ONLY be the anchor time in seconds! */
   1836       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1837                   "Filename `%s' invalid for key file, skipping\n",
   1838                   anchor_s);
   1839       return;
   1840     }
   1841     anchor_start.abs_time.abs_value_us
   1842       = anchor_start_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us;
   1843     if (anchor_start_ll != anchor_start.abs_time.abs_value_us
   1844         / GNUNET_TIME_UNIT_SECONDS.rel_value_us)
   1845     {
   1846       /* Integer overflow. Bad, invalid filename. */
   1847       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1848                   "Integer overflow. Filename `%s' invalid for key file, skipping\n",
   1849                   anchor_s);
   1850       return;
   1851     }
   1852     anchor_end
   1853       = GNUNET_TIME_absolute_to_timestamp (
   1854           GNUNET_TIME_absolute_add (anchor_start.abs_time,
   1855                                     denom->duration_withdraw));
   1856     GNUNET_asprintf (
   1857       &nf,
   1858       "%s/%s/%llu-%llu",
   1859       keydir,
   1860       denom->section,
   1861       anchor_start_ll,
   1862       (unsigned long long) (anchor_end.abs_time.abs_value_us
   1863                             / GNUNET_TIME_UNIT_SECONDS.rel_value_us));
   1864     /* Try to fix the legacy filename */
   1865     if (0 !=
   1866         rename (filename,
   1867                 nf))
   1868     {
   1869       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
   1870                                 "rename",
   1871                                 filename);
   1872       GNUNET_free (nf);
   1873     }
   1874   }
   1875   else
   1876   {
   1877     anchor_start.abs_time.abs_value_us
   1878       = anchor_start_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us;
   1879     anchor_end.abs_time.abs_value_us
   1880       = anchor_end_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us;
   1881     if ( (anchor_start_ll != anchor_start.abs_time.abs_value_us
   1882           / GNUNET_TIME_UNIT_SECONDS.rel_value_us) ||
   1883          (anchor_end_ll != anchor_end.abs_time.abs_value_us
   1884           / GNUNET_TIME_UNIT_SECONDS.rel_value_us) )
   1885     {
   1886       /* Integer overflow. Bad, invalid filename. */
   1887       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1888                   "Integer overflow. Filename `%s' invalid for key file, skipping\n",
   1889                   anchor_s);
   1890       return;
   1891     }
   1892   }
   1893 
   1894   {
   1895     struct DenominationKey *dk;
   1896     struct DenominationKey *before;
   1897 
   1898     dk = GNUNET_new (struct DenominationKey);
   1899     dk->denom_priv = *priv;
   1900     dk->denom = denom;
   1901     dk->anchor_start = anchor_start;
   1902     dk->anchor_end = anchor_end;
   1903     dk->filename = (NULL == nf) ? GNUNET_strdup (filename) : nf;
   1904     GNUNET_CRYPTO_cs_private_key_get_public (priv,
   1905                                              &dk->denom_pub);
   1906     GNUNET_CRYPTO_hash (&dk->denom_pub,
   1907                         sizeof (dk->denom_pub),
   1908                         &dk->h_cs.hash);
   1909     generate_response (dk);
   1910     if (GNUNET_OK !=
   1911         GNUNET_CONTAINER_multihashmap_put (
   1912           keys,
   1913           &dk->h_cs.hash,
   1914           dk,
   1915           GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
   1916     {
   1917       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1918                   "Duplicate private key %s detected in file `%s'. Skipping.\n",
   1919                   GNUNET_h2s (&dk->h_cs.hash),
   1920                   filename);
   1921       GNUNET_free (dk->an);
   1922       GNUNET_free (dk);
   1923       return;
   1924     }
   1925     before = NULL;
   1926     for (struct DenominationKey *pos = denom->keys_head;
   1927          NULL != pos;
   1928          pos = pos->next)
   1929     {
   1930       if (GNUNET_TIME_timestamp_cmp (pos->anchor_start,
   1931                                      >,
   1932                                      anchor_start))
   1933         break;
   1934       before = pos;
   1935     }
   1936     GNUNET_CONTAINER_DLL_insert_after (denom->keys_head,
   1937                                        denom->keys_tail,
   1938                                        before,
   1939                                        dk);
   1940     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1941                 "Imported key %s from `%s'\n",
   1942                 GNUNET_h2s (&dk->h_cs.hash),
   1943                 filename);
   1944   }
   1945 }
   1946 
   1947 
   1948 /**
   1949  * Import a private key from @a filename for the denomination
   1950  * given in @a cls.
   1951  *
   1952  * @param[in,out] cls a `struct Denomiantion`
   1953  * @param filename name of a file in the directory
   1954  * @return #GNUNET_OK (always, continue to iterate)
   1955  */
   1956 static enum GNUNET_GenericReturnValue
   1957 import_key (void *cls,
   1958             const char *filename)
   1959 {
   1960   struct Denomination *denom = cls;
   1961   struct GNUNET_DISK_FileHandle *fh;
   1962   struct GNUNET_DISK_MapHandle *map;
   1963   void *ptr;
   1964   int fd;
   1965   struct stat sbuf;
   1966 
   1967   {
   1968     struct stat lsbuf;
   1969 
   1970     if (0 != lstat (filename,
   1971                     &lsbuf))
   1972     {
   1973       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
   1974                                 "lstat",
   1975                                 filename);
   1976       return GNUNET_OK;
   1977     }
   1978     if (! S_ISREG (lsbuf.st_mode))
   1979     {
   1980       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1981                   "File `%s' is not a regular file, which is not allowed for private keys!\n",
   1982                   filename);
   1983       return GNUNET_OK;
   1984     }
   1985   }
   1986 
   1987   fd = open (filename,
   1988              O_RDONLY | O_CLOEXEC);
   1989   if (-1 == fd)
   1990   {
   1991     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
   1992                               "open",
   1993                               filename);
   1994     return GNUNET_OK;
   1995   }
   1996   if (0 != fstat (fd,
   1997                   &sbuf))
   1998   {
   1999     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
   2000                               "stat",
   2001                               filename);
   2002     GNUNET_break (0 == close (fd));
   2003     return GNUNET_OK;
   2004   }
   2005   if (! S_ISREG (sbuf.st_mode))
   2006   {
   2007     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2008                 "File `%s' is not a regular file, which is not allowed for private keys!\n",
   2009                 filename);
   2010     GNUNET_break (0 == close (fd));
   2011     return GNUNET_OK;
   2012   }
   2013   if (0 != (sbuf.st_mode & (S_IWUSR | S_IRWXG | S_IRWXO)))
   2014   {
   2015     /* permission are NOT tight, try to patch them up! */
   2016     if (0 !=
   2017         fchmod (fd,
   2018                 S_IRUSR))
   2019     {
   2020       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
   2021                                 "fchmod",
   2022                                 filename);
   2023       /* refuse to use key if file has wrong permissions */
   2024       GNUNET_break (0 == close (fd));
   2025       return GNUNET_OK;
   2026     }
   2027   }
   2028   fh = GNUNET_DISK_get_handle_from_int_fd (fd);
   2029   if (NULL == fh)
   2030   {
   2031     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
   2032                               "open",
   2033                               filename);
   2034     GNUNET_break (0 == close (fd));
   2035     return GNUNET_OK;
   2036   }
   2037   if (sbuf.st_size != sizeof(struct GNUNET_CRYPTO_CsPrivateKey))
   2038   {
   2039     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2040                 "File `%s' too big to be a private key\n",
   2041                 filename);
   2042     GNUNET_DISK_file_close (fh);
   2043     return GNUNET_OK;
   2044   }
   2045   ptr = GNUNET_DISK_file_map (fh,
   2046                               &map,
   2047                               GNUNET_DISK_MAP_TYPE_READ,
   2048                               (size_t) sbuf.st_size);
   2049   if (NULL == ptr)
   2050   {
   2051     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
   2052                               "mmap",
   2053                               filename);
   2054     GNUNET_DISK_file_close (fh);
   2055     return GNUNET_OK;
   2056   }
   2057   parse_key (denom,
   2058              filename,
   2059              (const struct GNUNET_CRYPTO_CsPrivateKey *) ptr);
   2060   GNUNET_DISK_file_unmap (map);
   2061   GNUNET_DISK_file_close (fh);
   2062   return GNUNET_OK;
   2063 }
   2064 
   2065 
   2066 /**
   2067  * Parse configuration for denomination type parameters.  Also determines
   2068  * our anchor by looking at the existing denominations of the same type.
   2069  *
   2070  * @param cfg configuration to use
   2071  * @param ct section in the configuration file giving the denomination type parameters
   2072  * @param[out] denom set to the denomination parameters from the configuration
   2073  * @return #GNUNET_OK on success, #GNUNET_SYSERR if the configuration is invalid
   2074  */
   2075 static enum GNUNET_GenericReturnValue
   2076 parse_denomination_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg,
   2077                         const char *ct,
   2078                         struct Denomination *denom)
   2079 {
   2080   char *secname;
   2081 
   2082   GNUNET_asprintf (&secname,
   2083                    "%s-secmod-cs",
   2084                    globals->section);
   2085   if (GNUNET_OK !=
   2086       GNUNET_CONFIGURATION_get_value_time (cfg,
   2087                                            ct,
   2088                                            "DURATION_WITHDRAW",
   2089                                            &denom->duration_withdraw))
   2090   {
   2091     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2092                                ct,
   2093                                "DURATION_WITHDRAW");
   2094     GNUNET_free (secname);
   2095     return GNUNET_SYSERR;
   2096   }
   2097   if (GNUNET_TIME_relative_cmp (denom->duration_withdraw,
   2098                                 <,
   2099                                 GNUNET_TIME_UNIT_SECONDS))
   2100   {
   2101     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2102                                ct,
   2103                                "DURATION_WITHDRAW",
   2104                                "less than one second is not supported");
   2105     GNUNET_free (secname);
   2106     return GNUNET_SYSERR;
   2107   }
   2108   if (GNUNET_TIME_relative_cmp (overlap_duration,
   2109                                 >=,
   2110                                 denom->duration_withdraw))
   2111   {
   2112     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   2113                                secname,
   2114                                "OVERLAP_DURATION",
   2115                                "Value given must be smaller than value for DURATION_WITHDRAW!");
   2116     GNUNET_free (secname);
   2117     return GNUNET_SYSERR;
   2118   }
   2119   GNUNET_free (secname);
   2120   denom->section = GNUNET_strdup (ct);
   2121   return GNUNET_OK;
   2122 }
   2123 
   2124 
   2125 /**
   2126  * Closure for #load_denominations.
   2127  */
   2128 struct LoadContext
   2129 {
   2130 
   2131   /**
   2132    * Configuration to use.
   2133    */
   2134   const struct GNUNET_CONFIGURATION_Handle *cfg;
   2135 
   2136   /**
   2137    * Current time to use.
   2138    */
   2139   struct GNUNET_TIME_Timestamp t;
   2140 
   2141   /**
   2142    * Status, to be set to #GNUNET_SYSERR on failure
   2143    */
   2144   enum GNUNET_GenericReturnValue ret;
   2145 };
   2146 
   2147 
   2148 /**
   2149  * Generate new denomination signing keys for the denomination type of the given @a
   2150  * denomination_alias.
   2151  *
   2152  * @param cls a `struct LoadContext`, with 'ret' to be set to #GNUNET_SYSERR on failure
   2153  * @param denomination_alias name of the denomination's section in the configuration
   2154  */
   2155 static void
   2156 load_denominations (void *cls,
   2157                     const char *denomination_alias)
   2158 {
   2159   struct LoadContext *ctx = cls;
   2160   struct Denomination *denom;
   2161   char *cipher;
   2162 
   2163   if ( (0 != strncasecmp (denomination_alias,
   2164                           "coin_",
   2165                           strlen ("coin_"))) &&
   2166        (0 != strncasecmp (denomination_alias,
   2167                           "coin-",
   2168                           strlen ("coin-"))) )
   2169     return; /* not a denomination type definition */
   2170   if (GNUNET_OK !=
   2171       GNUNET_CONFIGURATION_get_value_string (ctx->cfg,
   2172                                              denomination_alias,
   2173                                              "CIPHER",
   2174                                              &cipher))
   2175   {
   2176     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2177                                denomination_alias,
   2178                                "CIPHER");
   2179     return;
   2180   }
   2181   if (0 != strcmp (cipher, "CS"))
   2182   {
   2183     GNUNET_free (cipher);
   2184     return; /* Ignore denominations of other types than CS*/
   2185   }
   2186   GNUNET_free (cipher);
   2187 
   2188   denom = GNUNET_new (struct Denomination);
   2189   if (GNUNET_OK !=
   2190       parse_denomination_cfg (ctx->cfg,
   2191                               denomination_alias,
   2192                               denom))
   2193   {
   2194     ctx->ret = GNUNET_SYSERR;
   2195     GNUNET_free (denom);
   2196     return;
   2197   }
   2198   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2199               "Loading keys for denomination %s\n",
   2200               denom->section);
   2201   {
   2202     char *dname;
   2203 
   2204     GNUNET_asprintf (&dname,
   2205                      "%s/%s",
   2206                      keydir,
   2207                      denom->section);
   2208     GNUNET_break (GNUNET_OK ==
   2209                   GNUNET_DISK_directory_create (dname));
   2210     GNUNET_DISK_directory_scan (dname,
   2211                                 &import_key,
   2212                                 denom);
   2213     GNUNET_free (dname);
   2214   }
   2215   GNUNET_CONTAINER_DLL_insert (denom_head,
   2216                                denom_tail,
   2217                                denom);
   2218 }
   2219 
   2220 
   2221 /**
   2222  * Load the various duration values from @a cfg
   2223  *
   2224  * @param cfg configuration to use
   2225  * @return #GNUNET_OK on success
   2226  */
   2227 static enum GNUNET_GenericReturnValue
   2228 load_durations (const struct GNUNET_CONFIGURATION_Handle *cfg)
   2229 {
   2230   char *secname;
   2231 
   2232   GNUNET_asprintf (&secname,
   2233                    "%s-secmod-cs",
   2234                    globals->section);
   2235   if (GNUNET_OK !=
   2236       GNUNET_CONFIGURATION_get_value_time (cfg,
   2237                                            secname,
   2238                                            "OVERLAP_DURATION",
   2239                                            &overlap_duration))
   2240   {
   2241     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2242                                secname,
   2243                                "OVERLAP_DURATION");
   2244     GNUNET_free (secname);
   2245     return GNUNET_SYSERR;
   2246   }
   2247   if (GNUNET_OK !=
   2248       GNUNET_CONFIGURATION_get_value_time (cfg,
   2249                                            secname,
   2250                                            "LOOKAHEAD_SIGN",
   2251                                            &lookahead_sign))
   2252   {
   2253     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2254                                secname,
   2255                                "LOOKAHEAD_SIGN");
   2256     GNUNET_free (secname);
   2257     return GNUNET_SYSERR;
   2258   }
   2259   GNUNET_free (secname);
   2260   return GNUNET_OK;
   2261 }
   2262 
   2263 
   2264 /**
   2265  * Function run on shutdown. Stops the various jobs (nicely).
   2266  *
   2267  * @param cls a `struct TALER_SECMOD_Options`
   2268  */
   2269 static void
   2270 do_shutdown (void *cls)
   2271 {
   2272   (void) cls;
   2273   TES_listen_stop ();
   2274   if (NULL != keygen_task)
   2275   {
   2276     GNUNET_SCHEDULER_cancel (keygen_task);
   2277     keygen_task = NULL;
   2278   }
   2279   stop_workers ();
   2280   sem_done (&worker_sem);
   2281 }
   2282 
   2283 
   2284 void
   2285 TALER_SECMOD_cs_run (void *cls,
   2286                      char *const *args,
   2287                      const char *cfgfile,
   2288                      const struct GNUNET_CONFIGURATION_Handle *cfg)
   2289 {
   2290   static struct TES_Callbacks cb = {
   2291     .dispatch = &cs_work_dispatch,
   2292     .updater = &cs_update_client_keys,
   2293     .init = &cs_client_init
   2294   };
   2295   struct TALER_SECMOD_Options *opt = cls;
   2296   char *secname;
   2297 
   2298   (void) args;
   2299   (void) cfgfile;
   2300   globals = opt;
   2301   if (GNUNET_TIME_timestamp_cmp (opt->global_now,
   2302                                  !=,
   2303                                  opt->global_now_tmp))
   2304   {
   2305     /* The user gave "--now", use it! */
   2306     opt->global_now = opt->global_now_tmp;
   2307   }
   2308   else
   2309   {
   2310     /* get current time again, we may be timetraveling! */
   2311     opt->global_now = GNUNET_TIME_timestamp_get ();
   2312   }
   2313   GNUNET_asprintf (&secname,
   2314                    "%s-secmod-cs",
   2315                    opt->section);
   2316   if (GNUNET_OK !=
   2317       GNUNET_CONFIGURATION_get_value_filename (cfg,
   2318                                                secname,
   2319                                                "KEY_DIR",
   2320                                                &keydir))
   2321   {
   2322     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   2323                                secname,
   2324                                "KEY_DIR");
   2325     GNUNET_free (secname);
   2326     opt->global_ret = EXIT_NOTCONFIGURED;
   2327     return;
   2328   }
   2329   if (GNUNET_OK !=
   2330       load_durations (cfg))
   2331   {
   2332     opt->global_ret = EXIT_NOTCONFIGURED;
   2333     GNUNET_free (secname);
   2334     return;
   2335   }
   2336   opt->global_ret = TES_listen_start (cfg,
   2337                                       secname,
   2338                                       &cb);
   2339   GNUNET_free (secname);
   2340   if (0 != opt->global_ret)
   2341     return;
   2342   sem_init (&worker_sem,
   2343             0);
   2344   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
   2345                                  opt);
   2346   if (0 == opt->max_workers)
   2347   {
   2348     long lret;
   2349 
   2350     lret = sysconf (_SC_NPROCESSORS_CONF);
   2351     if (lret <= 0)
   2352       lret = 1;
   2353     opt->max_workers = (unsigned int) lret;
   2354   }
   2355   for (unsigned int i = 0; i<opt->max_workers; i++)
   2356     if (GNUNET_OK !=
   2357         start_worker ())
   2358     {
   2359       GNUNET_SCHEDULER_shutdown ();
   2360       return;
   2361     }
   2362   /* Load denominations */
   2363   keys = GNUNET_CONTAINER_multihashmap_create (65536,
   2364                                                true);
   2365   {
   2366     struct LoadContext lc = {
   2367       .cfg = cfg,
   2368       .ret = GNUNET_OK,
   2369       .t = opt->global_now
   2370     };
   2371     bool wake = true;
   2372 
   2373     GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
   2374     GNUNET_CONFIGURATION_iterate_sections (cfg,
   2375                                            &load_denominations,
   2376                                            &lc);
   2377     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
   2378     if (GNUNET_OK != lc.ret)
   2379     {
   2380       opt->global_ret = EXIT_FAILURE;
   2381       GNUNET_SCHEDULER_shutdown ();
   2382       return;
   2383     }
   2384     create_missing_keys (opt,
   2385                          &wake);
   2386   }
   2387   if (NULL == denom_head)
   2388   {
   2389     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   2390                 "No CS denominations configured. Make sure section names start with `%s' if you are using CS!\n",
   2391                 opt->section);
   2392     TES_wake_clients ();
   2393     return;
   2394   }
   2395   /* start job to keep keys up-to-date; MUST be run before the #listen_task,
   2396      hence with priority. */
   2397   keygen_task = GNUNET_SCHEDULER_add_with_priority (
   2398     GNUNET_SCHEDULER_PRIORITY_URGENT,
   2399     &update_denominations,
   2400     opt);
   2401 }