LCOV - code coverage report
Current view: top level - util - taler-exchange-secmod-rsa.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 390 672 58.0 %
Date: 2022-08-25 06:15:09 Functions: 28 33 84.8 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14