LCOV - code coverage report
Current view: top level - util - secmod_rsa.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 68.1 % 736 501
Test Date: 2026-02-16 10:50:18 Functions: 94.3 % 35 33

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

Generated by: LCOV version 2.0-1