LCOV - code coverage report
Current view: top level - util - secmod_cs.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 75.7 % 797 603
Test Date: 2026-05-12 15:34:29 Functions: 95.1 % 41 39

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

Generated by: LCOV version 2.0-1