LCOV - code coverage report
Current view: top level - util - secmod_cs.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 79.8 % 743 593
Test Date: 2026-01-04 22:17:00 Functions: 100.0 % 38 38

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

Generated by: LCOV version 2.0-1