LCOV - code coverage report
Current view: top level - util - secmod_cs.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 593 743 79.8 %
Date: 2025-06-05 21:03:14 Functions: 38 38 100.0 %

          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 "platform.h"
      35             : #include "taler_util.h"
      36             : #include "secmod_cs.h"
      37             : #include <gcrypt.h>
      38             : #include <pthread.h>
      39             : #include <sys/eventfd.h>
      40             : #include "taler_error_codes.h"
      41             : #include "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        2675 : generate_response (struct DenominationKey *dk)
     381             : {
     382        2675 :   struct Denomination *denom = dk->denom;
     383        2675 :   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        2675 :   GNUNET_assert (nlen < UINT16_MAX);
     390        2675 :   tlen = nlen + sizeof (*an);
     391        2675 :   GNUNET_assert (tlen < UINT16_MAX);
     392        2675 :   an = GNUNET_malloc (tlen);
     393        2675 :   an->header.size = htons ((uint16_t) tlen);
     394        2675 :   an->header.type = htons (TALER_HELPER_CS_MT_AVAIL);
     395        2675 :   an->section_name_len = htons ((uint16_t) nlen);
     396        2675 :   an->anchor_time = GNUNET_TIME_timestamp_hton (dk->anchor);
     397        2675 :   an->duration_withdraw = GNUNET_TIME_relative_hton (denom->duration_withdraw);
     398        2675 :   an->denom_pub = dk->denom_pub;
     399        2675 :   TALER_exchange_secmod_cs_sign (&dk->h_cs,
     400        2675 :                                  denom->section,
     401             :                                  dk->anchor,
     402             :                                  denom->duration_withdraw,
     403             :                                  &TES_smpriv,
     404             :                                  &an->secm_sig);
     405        2675 :   an->secm_pub = TES_smpub;
     406        2675 :   p = (void *) &an[1];
     407        2675 :   GNUNET_memcpy (p,
     408             :                  denom->section,
     409             :                  nlen);
     410        2675 :   dk->an = an;
     411        2675 : }
     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        1135 : 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        1135 :   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        1148 :   GNUNET_CRYPTO_cs_sign_derive (&dk->denom_priv,
     462             :                                 r,
     463             :                                 planchet,
     464             :                                 cs_sigp);
     465        1143 :   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        1147 :   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        1148 : send_signature (struct TES_Client *client,
     526             :                 const struct GNUNET_CRYPTO_CsBlindSignature *cs_answer)
     527             : {
     528             :   struct TALER_CRYPTO_SignResponse sres;
     529             : 
     530        1148 :   sres.header.size = htons (sizeof (sres));
     531        1148 :   sres.header.type = htons (TALER_HELPER_CS_MT_RES_SIGNATURE);
     532        1148 :   sres.b = htonl (cs_answer->b);
     533        1148 :   sres.cs_answer = cs_answer->s_scalar;
     534        1148 :   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         888 : handle_sign_request (struct TES_Client *client,
     550             :                      const struct TALER_CRYPTO_CsSignRequestMessage *sr)
     551             : {
     552             :   struct GNUNET_CRYPTO_CsBlindSignature cs_answer;
     553         888 :   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
     554             :   enum TALER_ErrorCode ec;
     555             :   enum GNUNET_GenericReturnValue ret;
     556             : 
     557         890 :   ec = do_sign (&sr->h_cs,
     558             :                 &sr->message,
     559         890 :                 (0 != ntohl (sr->for_melt)),
     560             :                 &cs_answer);
     561         901 :   if (TALER_EC_NONE != ec)
     562             :   {
     563           1 :     return fail_sign (client,
     564             :                       ec);
     565             :   }
     566         900 :   ret = send_signature (client,
     567             :                         &cs_answer);
     568         897 :   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         887 :   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        1097 : 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        1097 :   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         355 :   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         352 :   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        1691 : sem_init (struct Semaphore *sem,
     666             :           unsigned int val)
     667             : {
     668        1691 :   GNUNET_assert (0 ==
     669             :                  pthread_mutex_init (&sem->mutex,
     670             :                                      NULL));
     671        1691 :   GNUNET_assert (0 ==
     672             :                  pthread_cond_init (&sem->cv,
     673             :                                     NULL));
     674        1691 :   sem->ctr = val;
     675        1691 : }
     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        4654 : sem_down (struct Semaphore *sem)
     685             : {
     686        4654 :   GNUNET_assert (0 == pthread_mutex_lock (&sem->mutex));
     687        6484 :   while (0 == sem->ctr)
     688             :   {
     689        1829 :     pthread_cond_wait (&sem->cv,
     690             :                        &sem->mutex);
     691             :   }
     692        4655 :   sem->ctr--;
     693        4655 :   GNUNET_assert (0 == pthread_mutex_unlock (&sem->mutex));
     694        4654 : }
     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        4630 : sem_up (struct Semaphore *sem)
     704             : {
     705        4630 :   GNUNET_assert (0 == pthread_mutex_lock (&sem->mutex));
     706        4669 :   sem->ctr++;
     707        4669 :   GNUNET_assert (0 == pthread_mutex_unlock (&sem->mutex));
     708        4640 :   pthread_cond_signal (&sem->cv);
     709        4640 : }
     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        1691 : sem_done (struct Semaphore *sem)
     719             : {
     720        1691 :   GNUNET_break (0 == pthread_cond_destroy (&sem->cv));
     721        1691 :   GNUNET_break (0 == pthread_mutex_destroy (&sem->mutex));
     722        1691 : }
     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         320 : worker (void *cls)
     734             : {
     735         320 :   struct Worker *w = cls;
     736             : 
     737             :   while (true)
     738             :   {
     739        1661 :     GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
     740        1671 :     GNUNET_CONTAINER_DLL_insert (worker_head,
     741             :                                  worker_tail,
     742             :                                  w);
     743        1671 :     GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
     744        1666 :     sem_up (&worker_sem);
     745        1668 :     sem_down (&w->sem);
     746        1647 :     if (w->do_shutdown)
     747         320 :       break;
     748             :     {
     749        1327 :       struct BatchJob *bj = w->job;
     750             : 
     751        1327 :       switch (bj->type)
     752             :       {
     753         236 :       case TYPE_SIGN:
     754             :         {
     755         236 :           const struct TALER_CRYPTO_CsSignRequestMessage *sr
     756             :             = bj->details.sign.sr;
     757             : 
     758         485 :           bj->ec = do_sign (&sr->h_cs,
     759             :                             &sr->message,
     760         236 :                             (0 != ntohl (sr->for_melt)),
     761             :                             &bj->details.sign.cs_answer);
     762         249 :           break;
     763             :         }
     764        1080 :       case TYPE_RDERIVE:
     765             :         {
     766        1080 :           const struct TALER_CRYPTO_CsRDeriveRequest *rdr
     767             :             = bj->details.rderive.rdr;
     768        2177 :           bj->ec = do_derive (&rdr->h_cs,
     769             :                               &rdr->nonce,
     770        1080 :                               (0 != ntohl (rdr->for_melt)),
     771             :                               &bj->details.rderive.rpairp);
     772        1097 :           break;
     773             :         }
     774             :       }
     775        1357 :       sem_up (&bj->sem);
     776        1341 :       w->job = NULL;
     777             :     }
     778             :   }
     779         320 :   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         320 : start_worker (void)
    1007             : {
    1008             :   struct Worker *w;
    1009             : 
    1010         320 :   w = GNUNET_new (struct Worker);
    1011         320 :   sem_init (&w->sem,
    1012             :             0);
    1013         320 :   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         320 :   workers++;
    1024         320 :   return GNUNET_OK;
    1025             : }
    1026             : 
    1027             : 
    1028             : /**
    1029             :  * Stop all worker threads.
    1030             :  */
    1031             : static void
    1032          20 : stop_workers (void)
    1033             : {
    1034         340 :   while (workers > 0)
    1035             :   {
    1036             :     struct Worker *w;
    1037             :     void *result;
    1038             : 
    1039         320 :     sem_down (&worker_sem);
    1040         320 :     GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
    1041         320 :     w = worker_head;
    1042         320 :     GNUNET_CONTAINER_DLL_remove (worker_head,
    1043             :                                  worker_tail,
    1044             :                                  w);
    1045         320 :     GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
    1046         320 :     w->do_shutdown = true;
    1047         320 :     sem_up (&w->sem);
    1048         320 :     pthread_join (w->pt,
    1049             :                   &result);
    1050         320 :     GNUNET_assert (result == w);
    1051         320 :     sem_done (&w->sem);
    1052         320 :     GNUNET_free (w);
    1053         320 :     workers--;
    1054             :   }
    1055          20 : }
    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         549 : setup_key (struct DenominationKey *dk,
    1067             :            struct DenominationKey *position)
    1068             : {
    1069         549 :   struct Denomination *denom = dk->denom;
    1070             :   struct GNUNET_CRYPTO_CsPrivateKey priv;
    1071             :   struct GNUNET_CRYPTO_CsPublicKey pub;
    1072             : 
    1073         549 :   GNUNET_CRYPTO_cs_private_key_generate (&priv);
    1074         549 :   GNUNET_CRYPTO_cs_private_key_get_public (&priv,
    1075             :                                            &pub);
    1076         549 :   GNUNET_CRYPTO_hash (&pub,
    1077             :                       sizeof (pub),
    1078             :                       &dk->h_cs.hash);
    1079         549 :   GNUNET_asprintf (&dk->filename,
    1080             :                    "%s/%s/%llu",
    1081             :                    keydir,
    1082             :                    denom->section,
    1083         549 :                    (unsigned long long) (dk->anchor.abs_time.abs_value_us
    1084         549 :                                          / GNUNET_TIME_UNIT_SECONDS.rel_value_us
    1085             :                                          ));
    1086         549 :   if (GNUNET_OK !=
    1087         549 :       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         549 :   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         549 :   dk->denom_priv = priv;
    1104         549 :   dk->denom_pub = pub;
    1105         549 :   dk->key_gen = key_gen;
    1106         549 :   generate_response (dk);
    1107         549 :   if (GNUNET_OK !=
    1108         549 :       GNUNET_CONTAINER_multihashmap_put (
    1109             :         keys,
    1110         549 :         &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         549 :   GNUNET_CONTAINER_DLL_insert_after (denom->keys_head,
    1122             :                                      denom->keys_tail,
    1123             :                                      position,
    1124             :                                      dk);
    1125         549 :   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        1103 : cs_work_dispatch (struct TES_Client *client,
    1262             :                   const struct GNUNET_MessageHeader *hdr)
    1263             : {
    1264        1103 :   uint16_t msize = ntohs (hdr->size);
    1265             : 
    1266        1103 :   switch (ntohs (hdr->type))
    1267             :   {
    1268         888 :   case TALER_HELPER_CS_MT_REQ_SIGN:
    1269         888 :     if (msize < sizeof (struct TALER_CRYPTO_CsSignRequestMessage))
    1270             :     {
    1271           0 :       GNUNET_break_op (0);
    1272           0 :       return GNUNET_SYSERR;
    1273             :     }
    1274         888 :     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          38 : cs_client_init (struct TES_Client *client)
    1329             : {
    1330          38 :   size_t obs = 0;
    1331             :   char *buf;
    1332             : 
    1333          38 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1334             :               "Initializing new client %p\n",
    1335             :               client);
    1336          38 :   GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
    1337          38 :   for (struct Denomination *denom = denom_head;
    1338          99 :        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          38 :   buf = GNUNET_malloc (obs);
    1349          38 :   obs = 0;
    1350          38 :   for (struct Denomination *denom = denom_head;
    1351          99 :        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          38 :   client->key_gen = key_gen;
    1365          38 :   GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
    1366          38 :   if (GNUNET_OK !=
    1367          38 :       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          38 :   GNUNET_free (buf);
    1378             :   {
    1379          38 :     struct GNUNET_MessageHeader synced = {
    1380          38 :       .type = htons (TALER_HELPER_CS_SYNCED),
    1381          38 :       .size = htons (sizeof (synced))
    1382             :     };
    1383             : 
    1384          38 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1385             :                 "Sending CS SYNCED message to %p\n",
    1386             :                 client);
    1387          38 :     if (GNUNET_OK !=
    1388          38 :         TES_transmit (client->csock,
    1389             :                       &synced))
    1390             :     {
    1391           0 :       GNUNET_break (0);
    1392           0 :       return GNUNET_SYSERR;
    1393             :     }
    1394             :   }
    1395          38 :   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          22 : cs_update_client_keys (struct TES_Client *client)
    1408             : {
    1409          22 :   size_t obs = 0;
    1410             :   char *buf;
    1411             :   enum GNUNET_GenericReturnValue ret;
    1412             : 
    1413          22 :   GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
    1414          22 :   for (struct Denomination *denom = denom_head;
    1415          68 :        NULL != denom;
    1416          46 :        denom = denom->next)
    1417             :   {
    1418          46 :     for (struct DenominationKey *key = denom->keys_head;
    1419        2209 :          NULL != key;
    1420        2163 :          key = key->next)
    1421             :     {
    1422        2163 :       if (key->key_gen <= client->key_gen)
    1423        2156 :         continue;
    1424           7 :       if (key->purge)
    1425           3 :         obs += sizeof (struct TALER_CRYPTO_CsKeyPurgeNotification);
    1426             :       else
    1427           4 :         obs += ntohs (key->an->header.size);
    1428             :     }
    1429             :   }
    1430          22 :   if (0 == obs)
    1431             :   {
    1432             :     /* nothing to do */
    1433          18 :     client->key_gen = key_gen;
    1434          18 :     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
    1435          18 :     return GNUNET_OK;
    1436             :   }
    1437           4 :   buf = GNUNET_malloc (obs);
    1438           4 :   obs = 0;
    1439           4 :   for (struct Denomination *denom = denom_head;
    1440           8 :        NULL != denom;
    1441           4 :        denom = denom->next)
    1442             :   {
    1443           4 :     for (struct DenominationKey *key = denom->keys_head;
    1444          35 :          NULL != key;
    1445          31 :          key = key->next)
    1446             :     {
    1447          31 :       if (key->key_gen <= client->key_gen)
    1448          24 :         continue;
    1449           7 :       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           4 :         GNUNET_memcpy (&buf[obs],
    1467             :                        key->an,
    1468             :                        ntohs (key->an->header.size));
    1469           4 :         GNUNET_assert (obs + ntohs (key->an->header.size)
    1470             :                        > obs);
    1471           4 :         obs += ntohs (key->an->header.size);
    1472             :       }
    1473             :     }
    1474             :   }
    1475           4 :   client->key_gen = key_gen;
    1476           4 :   GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
    1477           4 :   ret = TES_transmit_raw (client->csock,
    1478             :                           obs,
    1479             :                           buf);
    1480           4 :   GNUNET_free (buf);
    1481           4 :   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         546 : create_key (struct Denomination *denom,
    1494             :             struct GNUNET_TIME_Timestamp now)
    1495             : {
    1496             :   struct DenominationKey *dk;
    1497             :   struct GNUNET_TIME_Timestamp anchor;
    1498             : 
    1499         546 :   anchor = now;
    1500         546 :   if (NULL != denom->keys_tail)
    1501             :   {
    1502             :     struct GNUNET_TIME_Absolute abs;
    1503             : 
    1504         534 :     abs = GNUNET_TIME_absolute_add (denom->keys_tail->anchor.abs_time,
    1505             :                                     GNUNET_TIME_relative_subtract (
    1506             :                                       denom->duration_withdraw,
    1507             :                                       overlap_duration));
    1508         534 :     if (GNUNET_TIME_absolute_cmp (now.abs_time,
    1509             :                                   <,
    1510             :                                   abs))
    1511         534 :       anchor = GNUNET_TIME_absolute_to_timestamp (abs);
    1512             :   }
    1513         546 :   dk = GNUNET_new (struct DenominationKey);
    1514         546 :   dk->denom = denom;
    1515         546 :   dk->anchor = anchor;
    1516         546 :   if (GNUNET_OK !=
    1517         546 :       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         546 :   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         123 : denomination_action_time (const struct Denomination *denom)
    1540             : {
    1541         123 :   struct DenominationKey *head = denom->keys_head;
    1542         123 :   struct DenominationKey *tail = denom->keys_tail;
    1543             :   struct GNUNET_TIME_Absolute tt;
    1544             : 
    1545         123 :   if (NULL == head)
    1546           0 :     return GNUNET_TIME_UNIT_ZERO_ABS;
    1547         123 :   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         123 :   if (head->rc > 0)
    1554           0 :     return tt; /* head expiration does not count due to rc > 0 */
    1555         123 :   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          63 : update_keys (struct Denomination *denom,
    1574             :              struct GNUNET_TIME_Timestamp now,
    1575             :              bool *wake)
    1576             : {
    1577             :   /* create new denomination keys */
    1578          63 :   if (NULL != denom->keys_tail)
    1579          51 :     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        1206 :   while ( (NULL == denom->keys_tail) ||
    1592         597 :           GNUNET_TIME_absolute_is_past (
    1593             :             GNUNET_TIME_absolute_subtract (
    1594             :               GNUNET_TIME_absolute_subtract (
    1595         597 :                 GNUNET_TIME_absolute_add (denom->keys_tail->anchor.abs_time,
    1596             :                                           denom->duration_withdraw),
    1597             :                 lookahead_sign),
    1598             :               overlap_duration)) )
    1599             :   {
    1600         546 :     if (! *wake)
    1601             :     {
    1602           1 :       key_gen++;
    1603           1 :       *wake = true;
    1604             :     }
    1605         546 :     if (GNUNET_OK !=
    1606         546 :         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         134 :   while ( (NULL != denom->keys_head) &&
    1617          67 :           GNUNET_TIME_absolute_is_past
    1618          67 :             (GNUNET_TIME_absolute_add (denom->keys_head->anchor.abs_time,
    1619             :                                        denom->duration_withdraw)) )
    1620             :   {
    1621           4 :     struct DenominationKey *key = denom->keys_head;
    1622           4 :     struct DenominationKey *nxt = key->next;
    1623             : 
    1624           4 :     if (0 != key->rc)
    1625           0 :       break; /* later */
    1626           4 :     GNUNET_CONTAINER_DLL_remove (denom->keys_head,
    1627             :                                  denom->keys_tail,
    1628             :                                  key);
    1629           4 :     GNUNET_assert (GNUNET_OK ==
    1630             :                    GNUNET_CONTAINER_multihashmap_remove (
    1631             :                      keys,
    1632             :                      &key->h_cs.hash,
    1633             :                      key));
    1634           8 :     if ( (! key->purge) &&
    1635           4 :          (0 != unlink (key->filename)) )
    1636           0 :       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
    1637             :                                 "unlink",
    1638             :                                 key->filename);
    1639           4 :     GNUNET_free (key->filename);
    1640           4 :     GNUNET_free (key->an);
    1641           4 :     GNUNET_free (key);
    1642           4 :     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          63 :     at = denomination_action_time (denom);
    1651          63 :     GNUNET_CONTAINER_DLL_remove (denom_head,
    1652             :                                  denom_tail,
    1653             :                                  denom);
    1654          63 :     before = NULL;
    1655          63 :     for (struct Denomination *pos = denom_head;
    1656          63 :          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          63 :     GNUNET_CONTAINER_DLL_insert_after (denom_head,
    1664             :                                        denom_tail,
    1665             :                                        before,
    1666             :                                        denom);
    1667             :   }
    1668          63 :   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          10 : update_denominations (void *cls)
    1679             : {
    1680             :   struct Denomination *denom;
    1681             :   struct GNUNET_TIME_Absolute now;
    1682             :   struct GNUNET_TIME_Timestamp t;
    1683          10 :   bool wake = false;
    1684             : 
    1685             :   (void) cls;
    1686          10 :   keygen_task = NULL;
    1687          10 :   now = GNUNET_TIME_absolute_get ();
    1688          10 :   t = GNUNET_TIME_absolute_to_timestamp (now);
    1689          10 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1690             :               "Updating denominations ...\n");
    1691          10 :   GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
    1692             :   do {
    1693          10 :     denom = denom_head;
    1694          10 :     if (GNUNET_OK !=
    1695          10 :         update_keys (denom,
    1696             :                      t,
    1697             :                      &wake))
    1698           0 :       return;
    1699          10 :   } while (denom != denom_head);
    1700          10 :   GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
    1701          10 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1702             :               "Updating denominations finished ...\n");
    1703          10 :   if (wake)
    1704           1 :     TES_wake_clients ();
    1705          10 :   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        2126 : 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        2126 :   anchor_s = strrchr (filename,
    1729             :                       '/');
    1730        2126 :   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        2126 :   anchor_s++;
    1737        2126 :   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        2126 :     = anchor_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us;
    1750        4252 :   if (anchor_ll != anchor.abs_time.abs_value_us
    1751        2126 :       / 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        2126 :     dk = GNUNET_new (struct DenominationKey);
    1764        2126 :     dk->denom_priv = *priv;
    1765        2126 :     dk->denom = denom;
    1766        2126 :     dk->anchor = anchor;
    1767        2126 :     dk->filename = GNUNET_strdup (filename);
    1768        2126 :     GNUNET_CRYPTO_cs_private_key_get_public (priv,
    1769             :                                              &dk->denom_pub);
    1770        2126 :     GNUNET_CRYPTO_hash (&dk->denom_pub,
    1771             :                         sizeof (dk->denom_pub),
    1772             :                         &dk->h_cs.hash);
    1773        2126 :     generate_response (dk);
    1774        2126 :     if (GNUNET_OK !=
    1775        2126 :         GNUNET_CONTAINER_multihashmap_put (
    1776             :           keys,
    1777        2126 :           &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        2126 :     before = NULL;
    1790        2126 :     for (struct DenominationKey *pos = denom->keys_head;
    1791        2126 :          NULL != pos;
    1792           0 :          pos = pos->next)
    1793             :     {
    1794        2085 :       if (GNUNET_TIME_timestamp_cmp (pos->anchor,
    1795             :                                      >,
    1796             :                                      anchor))
    1797        2085 :         break;
    1798           0 :       before = pos;
    1799             :     }
    1800        2126 :     GNUNET_CONTAINER_DLL_insert_after (denom->keys_head,
    1801             :                                        denom->keys_tail,
    1802             :                                        before,
    1803             :                                        dk);
    1804        2126 :     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        2126 : import_key (void *cls,
    1822             :             const char *filename)
    1823             : {
    1824        2126 :   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        2126 :     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        2126 :     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        2126 :   fd = open (filename,
    1852             :              O_RDONLY | O_CLOEXEC);
    1853        2126 :   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        2126 :   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        2126 :   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        2126 :   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        2126 :   fh = GNUNET_DISK_get_handle_from_int_fd (fd);
    1893        2126 :   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        2126 :   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        2126 :   ptr = GNUNET_DISK_file_map (fh,
    1910             :                               &map,
    1911             :                               GNUNET_DISK_MAP_TYPE_READ,
    1912        2126 :                               (size_t) sbuf.st_size);
    1913        2126 :   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        2126 :   parse_key (denom,
    1922             :              filename,
    1923             :              (const struct GNUNET_CRYPTO_CsPrivateKey *) ptr);
    1924        2126 :   GNUNET_DISK_file_unmap (map);
    1925        2126 :   GNUNET_DISK_file_close (fh);
    1926        2126 :   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         953 : load_denominations (void *cls,
    2010             :                     const char *denomination_alias)
    2011             : {
    2012         953 :   struct LoadContext *ctx = cls;
    2013             :   struct Denomination *denom;
    2014         953 :   bool wake = true;
    2015             :   char *cipher;
    2016             : 
    2017         953 :   if ( (0 != strncasecmp (denomination_alias,
    2018             :                           "coin_",
    2019         820 :                           strlen ("coin_"))) &&
    2020         820 :        (0 != strncasecmp (denomination_alias,
    2021             :                           "coin-",
    2022             :                           strlen ("coin-"))) )
    2023         900 :     return; /* not a denomination type definition */
    2024         133 :   if (GNUNET_OK !=
    2025         133 :       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         133 :   if (0 != strcmp (cipher, "CS"))
    2036             :   {
    2037          80 :     GNUNET_free (cipher);
    2038          80 :     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          20 : load_durations (const struct GNUNET_CONFIGURATION_Handle *cfg)
    2086             : {
    2087             :   char *secname;
    2088             : 
    2089          20 :   GNUNET_asprintf (&secname,
    2090             :                    "%s-secmod-cs",
    2091          20 :                    globals->section);
    2092          20 :   if (GNUNET_OK !=
    2093          20 :       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          20 :   if (GNUNET_OK !=
    2105          20 :       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          20 :   GNUNET_free (secname);
    2117          20 :   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          20 : do_shutdown (void *cls)
    2128             : {
    2129             :   (void) cls;
    2130          20 :   TES_listen_stop ();
    2131          20 :   if (NULL != keygen_task)
    2132             :   {
    2133           8 :     GNUNET_SCHEDULER_cancel (keygen_task);
    2134           8 :     keygen_task = NULL;
    2135             :   }
    2136          20 :   stop_workers ();
    2137          20 :   sem_done (&worker_sem);
    2138          20 : }
    2139             : 
    2140             : 
    2141             : void
    2142          20 : 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          20 :   struct TALER_SECMOD_Options *opt = cls;
    2153             :   char *secname;
    2154             : 
    2155             :   (void) args;
    2156             :   (void) cfgfile;
    2157          20 :   globals = opt;
    2158          20 :   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          20 :     opt->global_now = GNUNET_TIME_timestamp_get ();
    2169             :   }
    2170          20 :   GNUNET_asprintf (&secname,
    2171             :                    "%s-secmod-cs",
    2172             :                    opt->section);
    2173          20 :   if (GNUNET_OK !=
    2174          20 :       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          12 :     return;
    2185             :   }
    2186          20 :   if (GNUNET_OK !=
    2187          20 :       load_durations (cfg))
    2188             :   {
    2189           0 :     opt->global_ret = EXIT_NOTCONFIGURED;
    2190           0 :     GNUNET_free (secname);
    2191           0 :     return;
    2192             :   }
    2193          20 :   opt->global_ret = TES_listen_start (cfg,
    2194             :                                       secname,
    2195             :                                       &cb);
    2196          20 :   GNUNET_free (secname);
    2197          20 :   if (0 != opt->global_ret)
    2198           0 :     return;
    2199          20 :   sem_init (&worker_sem,
    2200             :             0);
    2201          20 :   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
    2202             :                                  opt);
    2203          20 :   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         340 :   for (unsigned int i = 0; i<opt->max_workers; i++)
    2213         320 :     if (GNUNET_OK !=
    2214         320 :         start_worker ())
    2215             :     {
    2216           0 :       GNUNET_SCHEDULER_shutdown ();
    2217           0 :       return;
    2218             :     }
    2219             :   /* Load denominations */
    2220          20 :   keys = GNUNET_CONTAINER_multihashmap_create (65536,
    2221             :                                                true);
    2222             :   {
    2223          20 :     struct LoadContext lc = {
    2224             :       .cfg = cfg,
    2225             :       .ret = GNUNET_OK,
    2226             :       .t = opt->global_now
    2227             :     };
    2228             : 
    2229          20 :     GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
    2230          20 :     GNUNET_CONFIGURATION_iterate_sections (cfg,
    2231             :                                            &load_denominations,
    2232             :                                            &lc);
    2233          20 :     GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
    2234          20 :     if (GNUNET_OK != lc.ret)
    2235             :     {
    2236           0 :       opt->global_ret = EXIT_FAILURE;
    2237           0 :       GNUNET_SCHEDULER_shutdown ();
    2238           0 :       return;
    2239             :     }
    2240             :   }
    2241          20 :   if (NULL == denom_head)
    2242             :   {
    2243          12 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    2244             :                 "No CS denominations configured\n");
    2245          12 :     TES_wake_clients ();
    2246          12 :     return;
    2247             :   }
    2248             :   /* start job to keep keys up-to-date; MUST be run before the #listen_task,
    2249             :      hence with priority. */
    2250           8 :   keygen_task = GNUNET_SCHEDULER_add_with_priority (
    2251             :     GNUNET_SCHEDULER_PRIORITY_URGENT,
    2252             :     &update_denominations,
    2253             :     NULL);
    2254             : }

Generated by: LCOV version 1.16