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


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