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


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