LCOV - code coverage report
Current view: top level - util - taler-exchange-secmod-eddsa.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 294 502 58.6 %
Date: 2021-08-30 06:43:37 Functions: 17 21 81.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014-2020 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU General Public License as published by the Free Software
       7             :   Foundation; either version 3, or (at your option) any later version.
       8             : 
       9             :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10             :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11             :   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU General Public License along with
      14             :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : /**
      17             :  * @file util/taler-exchange-secmod-eddsa.c
      18             :  * @brief Standalone process to perform private key EDDSA 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 threat 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 (only) do the signing in parallel,
      29             :  *   working of a work-queue.
      30             :  * - thread-safety: signing happens in parallel, thus when REMOVING private keys,
      31             :  *   we must ensure that all signers are done before we fully free() the
      32             :  *   private key. This is done by reference counting (as work is always
      33             :  *   assigned and collected by the main thread).
      34             :  */
      35             : #include "platform.h"
      36             : #include "taler_util.h"
      37             : #include "taler-exchange-secmod-eddsa.h"
      38             : #include <gcrypt.h>
      39             : #include <pthread.h>
      40             : #include <sys/eventfd.h>
      41             : #include "taler_error_codes.h"
      42             : #include "taler_signatures.h"
      43             : #include "secmod_common.h"
      44             : 
      45             : 
      46             : /**
      47             :  * One particular key.
      48             :  */
      49             : struct Key
      50             : {
      51             : 
      52             :   /**
      53             :    * Kept in a DLL. Sorted by anchor time.
      54             :    */
      55             :   struct Key *next;
      56             : 
      57             :   /**
      58             :    * Kept in a DLL. Sorted by anchor time.
      59             :    */
      60             :   struct Key *prev;
      61             : 
      62             :   /**
      63             :    * Name of the file this key is stored under.
      64             :    */
      65             :   char *filename;
      66             : 
      67             :   /**
      68             :    * The private key.
      69             :    */
      70             :   struct TALER_ExchangePrivateKeyP exchange_priv;
      71             : 
      72             :   /**
      73             :    * The public key.
      74             :    */
      75             :   struct TALER_ExchangePublicKeyP exchange_pub;
      76             : 
      77             :   /**
      78             :    * Time at which this key is supposed to become valid.
      79             :    */
      80             :   struct GNUNET_TIME_Absolute anchor;
      81             : 
      82             :   /**
      83             :    * Reference counter. Counts the number of threads that are
      84             :    * using this key at this time.
      85             :    */
      86             :   unsigned int rc;
      87             : 
      88             :   /**
      89             :    * Flag set to true if this key has been purged and the memory
      90             :    * must be freed as soon as @e rc hits zero.
      91             :    */
      92             :   bool purge;
      93             : 
      94             : };
      95             : 
      96             : 
      97             : /**
      98             :  * Information we keep for a client connected to us.
      99             :  */
     100             : struct Client
     101             : {
     102             : 
     103             :   /**
     104             :    * Kept in a DLL.
     105             :    */
     106             :   struct Client *next;
     107             : 
     108             :   /**
     109             :    * Kept in a DLL.
     110             :    */
     111             :   struct Client *prev;
     112             : 
     113             :   /**
     114             :    * Client address.
     115             :    */
     116             :   struct sockaddr_un addr;
     117             : 
     118             :   /**
     119             :    * Number of bytes used in @e addr.
     120             :    */
     121             :   socklen_t addr_size;
     122             : 
     123             : };
     124             : 
     125             : 
     126             : struct WorkItem
     127             : {
     128             : 
     129             :   /**
     130             :    * Kept in a DLL.
     131             :    */
     132             :   struct WorkItem *next;
     133             : 
     134             :   /**
     135             :    * Kept in a DLL.
     136             :    */
     137             :   struct WorkItem *prev;
     138             : 
     139             :   /**
     140             :    * Key to be used for this operation.
     141             :    */
     142             :   struct Key *key;
     143             : 
     144             :   /**
     145             :    * EDDSA signature over @e msg using @e key. Result of doing the work.
     146             :    */
     147             :   struct TALER_ExchangeSignatureP signature;
     148             : 
     149             :   /**
     150             :    * Message to sign.
     151             :    */
     152             :   struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
     153             : 
     154             :   /**
     155             :    * Client address.
     156             :    */
     157             :   struct sockaddr_un addr;
     158             : 
     159             :   /**
     160             :    * Number of bytes used in @e addr.
     161             :    */
     162             :   socklen_t addr_size;
     163             : 
     164             :   /**
     165             :    * Operation status code.
     166             :    */
     167             :   enum TALER_ErrorCode ec;
     168             : 
     169             : };
     170             : 
     171             : 
     172             : /**
     173             :  * Private key of this security module. Used to sign denomination key
     174             :  * announcements.
     175             :  */
     176             : static struct TALER_SecurityModulePrivateKeyP smpriv;
     177             : 
     178             : /**
     179             :  * Public key of this security module.
     180             :  */
     181             : static struct TALER_SecurityModulePublicKeyP smpub;
     182             : 
     183             : /**
     184             :  * Head of DLL of actual keys, sorted by anchor.
     185             :  */
     186             : static struct Key *keys_head;
     187             : 
     188             : /**
     189             :  * Tail of DLL of actual keys.
     190             :  */
     191             : static struct Key *keys_tail;
     192             : 
     193             : /**
     194             :  * How long can a key be used?
     195             :  */
     196             : static struct GNUNET_TIME_Relative duration;
     197             : 
     198             : /**
     199             :  * Return value from main().
     200             :  */
     201             : static int global_ret;
     202             : 
     203             : /**
     204             :  * Number of worker threads to use. Default (0) is to use one per CPU core
     205             :  * available.
     206             :  * Length of the #workers array.
     207             :  */
     208             : static unsigned int num_workers;
     209             : 
     210             : /**
     211             :  * Time when the key update is executed.
     212             :  * Either the actual current time, or a pretended time.
     213             :  */
     214             : static struct GNUNET_TIME_Absolute now;
     215             : 
     216             : /**
     217             :  * The time for the key update, as passed by the user
     218             :  * on the command line.
     219             :  */
     220             : static struct GNUNET_TIME_Absolute now_tmp;
     221             : 
     222             : /**
     223             :  * Handle to the exchange's configuration
     224             :  */
     225             : static const struct GNUNET_CONFIGURATION_Handle *kcfg;
     226             : 
     227             : /**
     228             :  * Where do we store the keys?
     229             :  */
     230             : static char *keydir;
     231             : 
     232             : /**
     233             :  * How much should coin creation duration overlap
     234             :  * with the next key?  Basically, the starting time of two
     235             :  * keys is always #duration - #overlap_duration apart.
     236             :  */
     237             : static struct GNUNET_TIME_Relative overlap_duration;
     238             : 
     239             : /**
     240             :  * How long into the future do we pre-generate keys?
     241             :  */
     242             : static struct GNUNET_TIME_Relative lookahead_sign;
     243             : 
     244             : /**
     245             :  * Our listen socket.
     246             :  */
     247             : static struct GNUNET_NETWORK_Handle *unix_sock;
     248             : 
     249             : /**
     250             :  * Path where we are listening.
     251             :  */
     252             : static char *unixpath;
     253             : 
     254             : /**
     255             :  * Task run to accept new inbound connections.
     256             :  */
     257             : static struct GNUNET_SCHEDULER_Task *read_task;
     258             : 
     259             : /**
     260             :  * Task run to generate new keys.
     261             :  */
     262             : static struct GNUNET_SCHEDULER_Task *keygen_task;
     263             : 
     264             : /**
     265             :  * Head of DLL of clients connected to us.
     266             :  */
     267             : static struct Client *clients_head;
     268             : 
     269             : /**
     270             :  * Tail of DLL of clients connected to us.
     271             :  */
     272             : static struct Client *clients_tail;
     273             : 
     274             : /**
     275             :  * Head of DLL with pending signing operations.
     276             :  */
     277             : static struct WorkItem *work_head;
     278             : 
     279             : /**
     280             :  * Tail of DLL with pending signing operations.
     281             :  */
     282             : static struct WorkItem *work_tail;
     283             : 
     284             : /**
     285             :  * Lock for the work queue.
     286             :  */
     287             : static pthread_mutex_t work_lock;
     288             : 
     289             : /**
     290             :  * Condition variable for the semaphore of the work queue.
     291             :  */
     292             : static pthread_cond_t work_cond = PTHREAD_COND_INITIALIZER;
     293             : 
     294             : /**
     295             :  * Number of items in the work queue. Also used as the semaphore counter.
     296             :  */
     297             : static unsigned long long work_counter;
     298             : 
     299             : /**
     300             :  * Head of DLL with completed signing operations.
     301             :  */
     302             : static struct WorkItem *done_head;
     303             : 
     304             : /**
     305             :  * Tail of DLL with completed signing operations.
     306             :  */
     307             : static struct WorkItem *done_tail;
     308             : 
     309             : /**
     310             :  * Lock for the done queue.
     311             :  */
     312             : static pthread_mutex_t done_lock;
     313             : 
     314             : /**
     315             :  * Task waiting for work to be done.
     316             :  */
     317             : static struct GNUNET_SCHEDULER_Task *done_task;
     318             : 
     319             : /**
     320             :  * Signal used by threads to notify the #done_task that they
     321             :  * completed work that is now in the done queue.
     322             :  */
     323             : static struct GNUNET_NETWORK_Handle *done_signal;
     324             : 
     325             : /**
     326             :  * Set once we are in shutdown and workers should terminate.
     327             :  */
     328             : static volatile bool in_shutdown;
     329             : 
     330             : /**
     331             :  * Array of #num_workers sign_worker() threads.
     332             :  */
     333             : static pthread_t *workers;
     334             : 
     335             : 
     336             : /**
     337             :  * Main function of a worker thread that signs.
     338             :  *
     339             :  * @param cls NULL
     340             :  * @return NULL
     341             :  */
     342             : static void *
     343         159 : sign_worker (void *cls)
     344             : {
     345             :   (void) cls;
     346         159 :   GNUNET_assert (0 == pthread_mutex_lock (&work_lock));
     347         591 :   while (! in_shutdown)
     348             :   {
     349             :     struct WorkItem *wi;
     350             : 
     351         702 :     while (NULL != (wi = work_head))
     352             :     {
     353             :       /* take work from queue */
     354         271 :       GNUNET_CONTAINER_DLL_remove (work_head,
     355             :                                    work_tail,
     356             :                                    wi);
     357         271 :       work_counter--;
     358         271 :       GNUNET_assert (0 == pthread_mutex_unlock (&work_lock));
     359             :       {
     360         271 :         if (GNUNET_OK !=
     361         271 :             GNUNET_CRYPTO_eddsa_sign_ (&wi->key->exchange_priv.eddsa_priv,
     362         271 :                                        wi->purpose,
     363             :                                        &wi->signature.eddsa_signature))
     364           0 :           wi->ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     365             :         else
     366         271 :           wi->ec = TALER_EC_NONE;
     367             :       }
     368             :       /* put completed work into done queue */
     369         271 :       GNUNET_assert (0 == pthread_mutex_lock (&done_lock));
     370         271 :       GNUNET_CONTAINER_DLL_insert (done_head,
     371             :                                    done_tail,
     372             :                                    wi);
     373         271 :       GNUNET_assert (0 == pthread_mutex_unlock (&done_lock));
     374             :       {
     375         271 :         uint64_t val = GNUNET_htonll (1);
     376             : 
     377             :         /* raise #done_signal */
     378         271 :         if (sizeof(val) !=
     379         271 :             write (GNUNET_NETWORK_get_fd (done_signal),
     380             :                    &val,
     381             :                    sizeof (val)))
     382           0 :           GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
     383             :                                "write(eventfd)");
     384             :       }
     385         271 :       GNUNET_assert (0 == pthread_mutex_lock (&work_lock));
     386             :     }
     387         431 :     if (in_shutdown)
     388           0 :       break;
     389             :     /* queue is empty, wait for work */
     390         431 :     GNUNET_assert (0 ==
     391             :                    pthread_cond_wait (&work_cond,
     392             :                                       &work_lock));
     393             :   }
     394         160 :   GNUNET_assert (0 ==
     395             :                  pthread_mutex_unlock (&work_lock));
     396         155 :   return NULL;
     397             : }
     398             : 
     399             : 
     400             : /**
     401             :  * Free @a client, releasing all (remaining) state.
     402             :  *
     403             :  * @param[in] client data to free
     404             :  */
     405             : static void
     406           0 : free_client (struct Client *client)
     407             : {
     408           0 :   GNUNET_CONTAINER_DLL_remove (clients_head,
     409             :                                clients_tail,
     410             :                                client);
     411           0 :   GNUNET_free (client);
     412           0 : }
     413             : 
     414             : 
     415             : /**
     416             :  * Function run to read incoming requests from a client.
     417             :  *
     418             :  * @param cls the `struct Client`
     419             :  */
     420             : static void
     421             : read_job (void *cls);
     422             : 
     423             : 
     424             : /**
     425             :  * Free @a key. It must already have been removed from the DLL.
     426             :  *
     427             :  * @param[in] key the key to free
     428             :  */
     429             : static void
     430           3 : free_key (struct Key *key)
     431             : {
     432           3 :   GNUNET_free (key->filename);
     433           3 :   GNUNET_free (key);
     434           3 : }
     435             : 
     436             : 
     437             : /**
     438             :  * Send a message starting with @a hdr to @a client.  We expect that
     439             :  * the client is mostly able to handle everything at whatever speed
     440             :  * we have (after all, the crypto should be the slow part). However,
     441             :  * especially on startup when we send all of our keys, it is possible
     442             :  * that the client cannot keep up. In that case, we throttle when
     443             :  * sending fails. This does not work with poll() as we cannot specify
     444             :  * the sendto() target address with poll(). So we nanosleep() instead.
     445             :  *
     446             :  * @param addr address where to send the message
     447             :  * @param addr_size number of bytes in @a addr
     448             :  * @param hdr beginning of the message, length indicated in size field
     449             :  * @return #GNUNET_OK on success
     450             :  */
     451             : static int
     452         384 : transmit (const struct sockaddr_un *addr,
     453             :           socklen_t addr_size,
     454             :           const struct GNUNET_MessageHeader *hdr)
     455             : {
     456         384 :   for (unsigned int i = 0; i<100; i++)
     457             :   {
     458         384 :     ssize_t ret = sendto (GNUNET_NETWORK_get_fd (unix_sock),
     459             :                           hdr,
     460         384 :                           ntohs (hdr->size),
     461             :                           0 /* no flags => blocking! */,
     462             :                           (const struct sockaddr *) addr,
     463             :                           addr_size);
     464         384 :     if ( (-1 == ret) &&
     465           0 :          (EAGAIN == errno) )
     466             :     {
     467             :       /* _Maybe_ with blocking sendto(), this should no
     468             :          longer be needed; still keeping it just in case. */
     469             :       /* Wait a bit, in case client is just too slow */
     470           0 :       struct timespec req = {
     471             :         .tv_sec = 0,
     472             :         .tv_nsec = 1000
     473             :       };
     474           0 :       nanosleep (&req, NULL);
     475           0 :       continue;
     476             :     }
     477         384 :     if (ret == ntohs (hdr->size))
     478         384 :       return GNUNET_OK;
     479           0 :     if (ret != ntohs (hdr->size))
     480           0 :       break;
     481             :   }
     482           0 :   GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
     483             :                        "sendto");
     484           0 :   return GNUNET_SYSERR;
     485             : }
     486             : 
     487             : 
     488             : /**
     489             :  * Process completed tasks that are in the #done_head queue, sending
     490             :  * the result back to the client (and resuming the client).
     491             :  *
     492             :  * @param cls NULL
     493             :  */
     494             : static void
     495         271 : handle_done (void *cls)
     496             : {
     497             :   uint64_t data;
     498             :   (void) cls;
     499             : 
     500             :   /* consume #done_signal */
     501         271 :   if (sizeof (data) !=
     502         271 :       read (GNUNET_NETWORK_get_fd (done_signal),
     503             :             &data,
     504             :             sizeof (data)))
     505           0 :     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
     506             :                          "read(eventfd)");
     507         271 :   done_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
     508             :                                              done_signal,
     509             :                                              &handle_done,
     510             :                                              NULL);
     511         271 :   GNUNET_assert (0 == pthread_mutex_lock (&done_lock));
     512         542 :   while (NULL != done_head)
     513             :   {
     514         271 :     struct WorkItem *wi = done_head;
     515             : 
     516         271 :     GNUNET_CONTAINER_DLL_remove (done_head,
     517             :                                  done_tail,
     518             :                                  wi);
     519         271 :     GNUNET_assert (0 == pthread_mutex_unlock (&done_lock));
     520         271 :     if (TALER_EC_NONE != wi->ec)
     521             :     {
     522           0 :       struct TALER_CRYPTO_EddsaSignFailure sf = {
     523           0 :         .header.size = htons (sizeof (sf)),
     524           0 :         .header.type = htons (TALER_HELPER_EDDSA_MT_RES_SIGN_FAILURE),
     525           0 :         .ec = htonl (wi->ec)
     526             :       };
     527             : 
     528           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     529             :                   "Signing request %p failed, worker failed to produce signature\n",
     530             :                   wi);
     531           0 :       (void) transmit (&wi->addr,
     532             :                        wi->addr_size,
     533             :                        &sf.header);
     534             :     }
     535             :     else
     536             :     {
     537         271 :       struct TALER_CRYPTO_EddsaSignResponse sr = {
     538         271 :         .header.size = htons (sizeof (sr)),
     539         271 :         .header.type = htons (TALER_HELPER_EDDSA_MT_RES_SIGNATURE),
     540         271 :         .exchange_pub = wi->key->exchange_pub,
     541             :         .exchange_sig = wi->signature
     542             :       };
     543             : 
     544         271 :       (void) transmit (&wi->addr,
     545             :                        wi->addr_size,
     546             :                        &sr.header);
     547             :     }
     548             :     {
     549         271 :       struct Key *key = wi->key;
     550             : 
     551         271 :       key->rc--;
     552         271 :       if ( (0 == key->rc) &&
     553         271 :            (key->purge) )
     554           0 :         free_key (key);
     555             :     }
     556         271 :     GNUNET_free (wi->purpose);
     557         271 :     GNUNET_free (wi);
     558         271 :     GNUNET_assert (0 == pthread_mutex_lock (&done_lock));
     559             :   }
     560         271 :   GNUNET_assert (0 == pthread_mutex_unlock (&done_lock));
     561             : 
     562         271 : }
     563             : 
     564             : 
     565             : /**
     566             :  * Handle @a client request @a sr to create signature. Create the
     567             :  * signature using the respective key and return the result to
     568             :  * the client.
     569             :  *
     570             :  * @param addr address of the client making the request
     571             :  * @param addr_size number of bytes in @a addr
     572             :  * @param sr the request details
     573             :  */
     574             : static void
     575         271 : handle_sign_request (const struct sockaddr_un *addr,
     576             :                      socklen_t addr_size,
     577             :                      const struct TALER_CRYPTO_EddsaSignRequest *sr)
     578             : {
     579         271 :   const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose = &sr->purpose;
     580             :   struct WorkItem *wi;
     581         271 :   size_t purpose_size = ntohs (sr->header.size) - sizeof (*sr)
     582             :                         + sizeof (*purpose);
     583             : 
     584         271 :   if (purpose_size != htonl (purpose->size))
     585             :   {
     586           0 :     struct TALER_CRYPTO_EddsaSignFailure sf = {
     587           0 :       .header.size = htons (sizeof (sr)),
     588           0 :       .header.type = htons (TALER_HELPER_EDDSA_MT_RES_SIGN_FAILURE),
     589           0 :       .ec = htonl (TALER_EC_GENERIC_PARAMETER_MALFORMED)
     590             :     };
     591             : 
     592           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     593             :                 "Signing request failed, request malformed\n");
     594           0 :     (void) transmit (addr,
     595             :                      addr_size,
     596             :                      &sf.header);
     597           0 :     return;
     598             :   }
     599             :   {
     600             :     struct GNUNET_TIME_Absolute now;
     601             : 
     602         271 :     now = GNUNET_TIME_absolute_get ();
     603         271 :     if ( (now.abs_value_us >= keys_head->anchor.abs_value_us) &&
     604         271 :          (now.abs_value_us < keys_head->anchor.abs_value_us
     605         271 :           + duration.rel_value_us) )
     606         271 :       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     607             :                   "Signing at %llu with key valid from %llu to %llu\n",
     608             :                   (unsigned long long) now.abs_value_us,
     609             :                   (unsigned long long) keys_head->anchor.abs_value_us,
     610             :                   (unsigned long long) keys_head->anchor.abs_value_us
     611             :                   + duration.rel_value_us);
     612             :     else
     613           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     614             :                   "Signing at %llu with key valid from %llu to %llu\n",
     615             :                   (unsigned long long) now.abs_value_us,
     616             :                   (unsigned long long) keys_head->anchor.abs_value_us,
     617             :                   (unsigned long long) keys_head->anchor.abs_value_us
     618             :                   + duration.rel_value_us);
     619             :   }
     620         271 :   wi = GNUNET_new (struct WorkItem);
     621         271 :   wi->addr = *addr;
     622         271 :   wi->addr_size = addr_size;
     623         271 :   wi->key = keys_head;
     624         271 :   keys_head->rc++;
     625         271 :   wi->purpose = GNUNET_memdup (purpose,
     626             :                                purpose_size);
     627         271 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     628             :               "Received request to sign over %u bytes, queueing as %p\n",
     629             :               (unsigned int) purpose_size,
     630             :               wi);
     631         271 :   GNUNET_assert (0 == pthread_mutex_lock (&work_lock));
     632         271 :   work_counter++;
     633         271 :   GNUNET_CONTAINER_DLL_insert (work_head,
     634             :                                work_tail,
     635             :                                wi);
     636         271 :   GNUNET_assert (0 == pthread_cond_signal (&work_cond));
     637         271 :   GNUNET_assert (0 == pthread_mutex_unlock (&work_lock));
     638             : }
     639             : 
     640             : 
     641             : /**
     642             :  * Notify @a client about @a key becoming available.
     643             :  *
     644             :  * @param[in,out] client the client to notify; possible freed if transmission fails
     645             :  * @param key the key to notify @a client about
     646             :  * @return #GNUNET_OK on success
     647             :  */
     648             : static int
     649          73 : notify_client_key_add (struct Client *client,
     650             :                        const struct Key *key)
     651             : {
     652         146 :   struct TALER_CRYPTO_EddsaKeyAvailableNotification an = {
     653          73 :     .header.size = htons (sizeof (an)),
     654          73 :     .header.type = htons (TALER_HELPER_EDDSA_MT_AVAIL),
     655          73 :     .anchor_time = GNUNET_TIME_absolute_hton (key->anchor),
     656          73 :     .duration = GNUNET_TIME_relative_hton (duration),
     657             :     .exchange_pub = key->exchange_pub,
     658             :     .secm_pub = smpub
     659             :   };
     660             : 
     661          73 :   TALER_exchange_secmod_eddsa_sign (&key->exchange_pub,
     662             :                                     key->anchor,
     663             :                                     duration,
     664             :                                     &smpriv,
     665             :                                     &an.secm_sig);
     666          73 :   if (GNUNET_OK !=
     667          73 :       transmit (&client->addr,
     668             :                 client->addr_size,
     669             :                 &an.header))
     670             :   {
     671           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     672             :                 "Client %s must have disconnected\n",
     673             :                 client->addr.sun_path);
     674           0 :     free_client (client);
     675           0 :     return GNUNET_SYSERR;
     676             :   }
     677          73 :   return GNUNET_OK;
     678             : }
     679             : 
     680             : 
     681             : /**
     682             :  * Notify @a client about @a key being purged.
     683             :  *
     684             :  * @param[in,out] client the client to notify; possible freed if transmission fails
     685             :  * @param key the key to notify @a client about
     686             :  * @return #GNUNET_OK on success
     687             :  */
     688             : static int
     689           3 : notify_client_key_del (struct Client *client,
     690             :                        const struct Key *key)
     691             : {
     692           3 :   struct TALER_CRYPTO_EddsaKeyPurgeNotification pn = {
     693           3 :     .header.type = htons (TALER_HELPER_EDDSA_MT_PURGE),
     694           3 :     .header.size = htons (sizeof (pn)),
     695             :     .exchange_pub = key->exchange_pub
     696             :   };
     697             : 
     698           3 :   if (GNUNET_OK !=
     699           3 :       transmit (&client->addr,
     700             :                 client->addr_size,
     701             :                 &pn.header))
     702             :   {
     703           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     704             :                 "Client %s must have disconnected\n",
     705             :                 client->addr.sun_path);
     706           0 :     free_client (client);
     707           0 :     return GNUNET_SYSERR;
     708             :   }
     709           3 :   return GNUNET_OK;
     710             : }
     711             : 
     712             : 
     713             : /**
     714             :  * Initialize key material for key @a key (also on disk).
     715             :  *
     716             :  * @param[in,out] key to compute key material for
     717             :  * @param position where in the DLL will the @a key go
     718             :  * @return #GNUNET_OK on success
     719             :  */
     720             : static int
     721          25 : setup_key (struct Key *key,
     722             :            struct Key *position)
     723             : {
     724             :   struct GNUNET_CRYPTO_EddsaPrivateKey priv;
     725             :   struct GNUNET_CRYPTO_EddsaPublicKey pub;
     726             : 
     727          25 :   GNUNET_CRYPTO_eddsa_key_create (&priv);
     728          25 :   GNUNET_CRYPTO_eddsa_key_get_public (&priv,
     729             :                                       &pub);
     730          25 :   GNUNET_asprintf (&key->filename,
     731             :                    "%s/%llu",
     732             :                    keydir,
     733          25 :                    (unsigned long long) (key->anchor.abs_value_us
     734          25 :                                          / GNUNET_TIME_UNIT_SECONDS.rel_value_us));
     735          25 :   if (GNUNET_OK !=
     736          25 :       GNUNET_DISK_fn_write (key->filename,
     737             :                             &priv,
     738             :                             sizeof (priv),
     739             :                             GNUNET_DISK_PERM_USER_READ))
     740             :   {
     741           0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
     742             :                               "write",
     743             :                               key->filename);
     744           0 :     return GNUNET_SYSERR;
     745             :   }
     746          25 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     747             :               "Setup fresh private key in `%s'\n",
     748             :               key->filename);
     749          25 :   key->exchange_priv.eddsa_priv = priv;
     750          25 :   key->exchange_pub.eddsa_pub = pub;
     751          25 :   GNUNET_CONTAINER_DLL_insert_after (keys_head,
     752             :                                      keys_tail,
     753             :                                      position,
     754             :                                      key);
     755             : 
     756             :   /* tell clients about new key */
     757             :   {
     758             :     struct Client *nxt;
     759             : 
     760          28 :     for (struct Client *client = clients_head;
     761             :          NULL != client;
     762           3 :          client = nxt)
     763             :     {
     764           3 :       nxt = client->next;
     765           3 :       if (GNUNET_OK !=
     766           3 :           notify_client_key_add (client,
     767             :                                  key))
     768             :       {
     769           0 :         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     770             :                     "Failed to notify client about new key, client dropped\n");
     771             :       }
     772             :     }
     773             :   }
     774          25 :   return GNUNET_OK;
     775             : }
     776             : 
     777             : 
     778             : /**
     779             :  * A client informs us that a key has been revoked.
     780             :  * Check if the key is still in use, and if so replace (!)
     781             :  * it with a fresh key.
     782             :  *
     783             :  * @param addr address of the client making the request
     784             :  * @param addr_size number of bytes in @a addr
     785             :  * @param rr the revocation request
     786             :  */
     787             : static void
     788           3 : handle_revoke_request (const struct sockaddr_un *addr,
     789             :                        socklen_t addr_size,
     790             :                        const struct TALER_CRYPTO_EddsaRevokeRequest *rr)
     791             : {
     792             :   struct Key *key;
     793             :   struct Key *nkey;
     794             : 
     795           3 :   key = NULL;
     796           7 :   for (struct Key *pos = keys_head; NULL != pos; pos = pos->next)
     797           7 :     if (0 == GNUNET_memcmp (&pos->exchange_pub,
     798             :                             &rr->exchange_pub))
     799             :     {
     800           3 :       key = pos;
     801           3 :       break;
     802             :     }
     803           3 :   if (NULL == key)
     804             :   {
     805           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     806             :                 "Revocation request ignored, key unknown\n");
     807           0 :     return;
     808             :   }
     809             : 
     810             :   /* kill existing key, done first to ensure this always happens */
     811           3 :   if (0 != unlink (key->filename))
     812           0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
     813             :                               "unlink",
     814             :                               key->filename);
     815             : 
     816             :   /* Setup replacement key */
     817           3 :   nkey = GNUNET_new (struct Key);
     818           3 :   nkey->anchor = key->anchor;
     819           3 :   if (GNUNET_OK !=
     820           3 :       setup_key (nkey,
     821             :                  key))
     822             :   {
     823           0 :     GNUNET_break (0);
     824           0 :     GNUNET_SCHEDULER_shutdown ();
     825           0 :     global_ret = 44;
     826           0 :     return;
     827             :   }
     828             : 
     829             :   /* get rid of the old key */
     830           3 :   key->purge = true;
     831           3 :   GNUNET_CONTAINER_DLL_remove (keys_head,
     832             :                                keys_tail,
     833             :                                key);
     834           3 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     835             :               "Revocation complete\n");
     836             : 
     837             :   /* Tell clients this key is gone */
     838             :   {
     839             :     struct Client *nxt;
     840             : 
     841           6 :     for (struct Client *client = clients_head;
     842             :          NULL != client;
     843           3 :          client = nxt)
     844             :     {
     845           3 :       nxt = client->next;
     846           3 :       if (GNUNET_OK !=
     847           3 :           notify_client_key_del (client,
     848             :                                  key))
     849           0 :         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     850             :                     "Failed to notify client about revoked key, client dropped\n");
     851             :     }
     852             :   }
     853           3 :   if (0 == key->rc)
     854           3 :     free_key (key);
     855             : }
     856             : 
     857             : 
     858             : static void
     859         311 : read_job (void *cls)
     860             : {
     861         311 :   struct Client *client = cls;
     862             :   char buf[65536];
     863             :   ssize_t buf_size;
     864             :   const struct GNUNET_MessageHeader *hdr;
     865             :   struct sockaddr_un addr;
     866         311 :   socklen_t addr_size = sizeof (addr);
     867             : 
     868         311 :   read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
     869             :                                              unix_sock,
     870             :                                              &read_job,
     871             :                                              NULL);
     872         311 :   buf_size = GNUNET_NETWORK_socket_recvfrom (unix_sock,
     873             :                                              buf,
     874             :                                              sizeof (buf),
     875             :                                              (struct sockaddr *) &addr,
     876             :                                              &addr_size);
     877         311 :   if (-1 == buf_size)
     878             :   {
     879           0 :     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
     880             :                          "recv");
     881           0 :     return;
     882             :   }
     883         311 :   if (0 == buf_size)
     884             :   {
     885           0 :     return;
     886             :   }
     887         311 :   if (buf_size < sizeof (struct GNUNET_MessageHeader))
     888             :   {
     889           0 :     GNUNET_break_op (0);
     890           0 :     return;
     891             :   }
     892         311 :   hdr = (const struct GNUNET_MessageHeader *) buf;
     893         311 :   if (ntohs (hdr->size) != buf_size)
     894             :   {
     895           0 :     GNUNET_break_op (0);
     896           0 :     free_client (client);
     897           0 :     return;
     898             :   }
     899         311 :   switch (ntohs (hdr->type))
     900             :   {
     901          37 :   case TALER_HELPER_EDDSA_MT_REQ_INIT:
     902          37 :     if (ntohs (hdr->size) != sizeof (struct GNUNET_MessageHeader))
     903             :     {
     904           0 :       GNUNET_break_op (0);
     905           0 :       return;
     906             :     }
     907             :     {
     908             :       struct Client *client;
     909             : 
     910          37 :       client = GNUNET_new (struct Client);
     911          37 :       client->addr = addr;
     912          37 :       client->addr_size = addr_size;
     913          37 :       GNUNET_CONTAINER_DLL_insert (clients_head,
     914             :                                    clients_tail,
     915             :                                    client);
     916         107 :       for (struct Key *key = keys_head;
     917             :            NULL != key;
     918          70 :            key = key->next)
     919             :       {
     920          70 :         if (GNUNET_OK !=
     921          70 :             notify_client_key_add (client,
     922             :                                    key))
     923             :         {
     924             :           /* client died, skip the rest */
     925           0 :           client = NULL;
     926           0 :           break;
     927             :         }
     928             :       }
     929          37 :       if (NULL != client)
     930             :       {
     931          37 :         struct GNUNET_MessageHeader synced = {
     932          37 :           .type = htons (TALER_HELPER_EDDSA_SYNCED),
     933          37 :           .size = htons (sizeof (synced))
     934             :         };
     935             : 
     936          37 :         if (GNUNET_OK !=
     937          37 :             transmit (&client->addr,
     938             :                       client->addr_size,
     939             :                       &synced))
     940             :         {
     941           0 :           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     942             :                       "Client %s must have disconnected\n",
     943             :                       client->addr.sun_path);
     944           0 :           free_client (client);
     945             :         }
     946             :       }
     947             :     }
     948          37 :     break;
     949         271 :   case TALER_HELPER_EDDSA_MT_REQ_SIGN:
     950         271 :     if (ntohs (hdr->size) < sizeof (struct TALER_CRYPTO_EddsaSignRequest))
     951             :     {
     952           0 :       GNUNET_break_op (0);
     953           0 :       return;
     954             :     }
     955         271 :     handle_sign_request (&addr,
     956             :                          addr_size,
     957             :                          (const struct TALER_CRYPTO_EddsaSignRequest *) buf);
     958         271 :     break;
     959           3 :   case TALER_HELPER_EDDSA_MT_REQ_REVOKE:
     960           3 :     if (ntohs (hdr->size) != sizeof (struct TALER_CRYPTO_EddsaRevokeRequest))
     961             :     {
     962           0 :       GNUNET_break_op (0);
     963           0 :       return;
     964             :     }
     965           3 :     handle_revoke_request (&addr,
     966             :                            addr_size,
     967             :                            (const struct
     968             :                             TALER_CRYPTO_EddsaRevokeRequest *) buf);
     969           3 :     break;
     970           0 :   default:
     971           0 :     GNUNET_break_op (0);
     972           0 :     return;
     973             :   }
     974             : }
     975             : 
     976             : 
     977             : /**
     978             :  * Create a new key (we do not have enough).
     979             :  *
     980             :  * @return #GNUNET_OK on success
     981             :  */
     982             : static int
     983          22 : create_key (void)
     984             : {
     985             :   struct Key *key;
     986             :   struct GNUNET_TIME_Absolute anchor;
     987             :   struct GNUNET_TIME_Absolute now;
     988             : 
     989          22 :   now = GNUNET_TIME_absolute_get ();
     990          22 :   (void) GNUNET_TIME_round_abs (&now);
     991          22 :   if (NULL == keys_tail)
     992             :   {
     993          10 :     anchor = now;
     994             :   }
     995             :   else
     996             :   {
     997          12 :     anchor = GNUNET_TIME_absolute_add (keys_tail->anchor,
     998             :                                        GNUNET_TIME_relative_subtract (
     999             :                                          duration,
    1000             :                                          overlap_duration));
    1001          12 :     if (now.abs_value_us > anchor.abs_value_us)
    1002           0 :       anchor = now;
    1003             :   }
    1004          22 :   key = GNUNET_new (struct Key);
    1005          22 :   key->anchor = anchor;
    1006          22 :   if (GNUNET_OK !=
    1007          22 :       setup_key (key,
    1008             :                  keys_tail))
    1009             :   {
    1010           0 :     GNUNET_break (0);
    1011           0 :     GNUNET_free (key);
    1012           0 :     GNUNET_SCHEDULER_shutdown ();
    1013           0 :     global_ret = 42;
    1014           0 :     return GNUNET_SYSERR;
    1015             :   }
    1016          22 :   return GNUNET_OK;
    1017             : }
    1018             : 
    1019             : 
    1020             : /**
    1021             :  * At what time does the current key set require its next action?  Basically,
    1022             :  * the minimum of the expiration time of the oldest key, and the expiration
    1023             :  * time of the newest key minus the #lookahead_sign time.
    1024             :  */
    1025             : static struct GNUNET_TIME_Absolute
    1026          10 : key_action_time (void)
    1027             : {
    1028          10 :   if (NULL == keys_head)
    1029           0 :     return GNUNET_TIME_UNIT_ZERO_ABS;
    1030          20 :   return GNUNET_TIME_absolute_min (
    1031          10 :     GNUNET_TIME_absolute_add (keys_head->anchor,
    1032             :                               duration),
    1033             :     GNUNET_TIME_absolute_subtract (
    1034             :       GNUNET_TIME_absolute_subtract (
    1035          10 :         GNUNET_TIME_absolute_add (keys_tail->anchor,
    1036             :                                   duration),
    1037             :         lookahead_sign),
    1038             :       overlap_duration));
    1039             : }
    1040             : 
    1041             : 
    1042             : /**
    1043             :  * The validity period of a key @a key has expired. Purge it.
    1044             :  *
    1045             :  * @param[in] key expired key to purge and free
    1046             :  */
    1047             : static void
    1048           0 : purge_key (struct Key *key)
    1049             : {
    1050             :   struct Client *nxt;
    1051             : 
    1052           0 :   for (struct Client *client = clients_head;
    1053             :        NULL != client;
    1054           0 :        client = nxt)
    1055             :   {
    1056           0 :     nxt = client->next;
    1057           0 :     if (GNUNET_OK !=
    1058           0 :         notify_client_key_del (client,
    1059             :                                key))
    1060             :     {
    1061           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1062             :                   "Failed to notify client about purged key, client dropped\n");
    1063             :     }
    1064             :   }
    1065           0 :   GNUNET_CONTAINER_DLL_remove (keys_head,
    1066             :                                keys_tail,
    1067             :                                key);
    1068           0 :   if (0 != unlink (key->filename))
    1069             :   {
    1070           0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
    1071             :                               "unlink",
    1072             :                               key->filename);
    1073             :   }
    1074             :   else
    1075             :   {
    1076           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1077             :                 "Purged expired private key `%s'\n",
    1078             :                 key->filename);
    1079             :   }
    1080           0 :   GNUNET_free (key->filename);
    1081           0 :   if (0 != key->rc)
    1082             :   {
    1083             :     /* delay until all signing threads are done with this key */
    1084           0 :     key->purge = true;
    1085           0 :     return;
    1086             :   }
    1087           0 :   GNUNET_free (key);
    1088             : }
    1089             : 
    1090             : 
    1091             : /**
    1092             :  * Create new keys and expire ancient keys.
    1093             :  *
    1094             :  * @param cls NULL
    1095             :  */
    1096             : static void
    1097          10 : update_keys (void *cls)
    1098             : {
    1099             :   (void) cls;
    1100             : 
    1101          10 :   keygen_task = NULL;
    1102             :   /* create new keys */
    1103          32 :   while ( (NULL == keys_tail) ||
    1104             :           (0 ==
    1105          22 :            GNUNET_TIME_absolute_get_remaining (
    1106             :              GNUNET_TIME_absolute_subtract (
    1107             :                GNUNET_TIME_absolute_subtract (
    1108          22 :                  GNUNET_TIME_absolute_add (keys_tail->anchor,
    1109             :                                            duration),
    1110             :                  lookahead_sign),
    1111          22 :                overlap_duration)).rel_value_us) )
    1112             :   {
    1113          22 :     if (GNUNET_OK !=
    1114          22 :         create_key ())
    1115             :     {
    1116           0 :       GNUNET_break (0);
    1117           0 :       GNUNET_SCHEDULER_shutdown ();
    1118           0 :       return;
    1119             :     }
    1120             :   }
    1121             :   /* remove expired keys */
    1122          10 :   while ( (NULL != keys_head) &&
    1123             :           (0 ==
    1124          10 :            GNUNET_TIME_absolute_get_remaining
    1125          10 :              (GNUNET_TIME_absolute_add (keys_head->anchor,
    1126          10 :                                         duration)).rel_value_us) )
    1127           0 :     purge_key (keys_head);
    1128          10 :   keygen_task = GNUNET_SCHEDULER_add_at (key_action_time (),
    1129             :                                          &update_keys,
    1130             :                                          NULL);
    1131             : }
    1132             : 
    1133             : 
    1134             : /**
    1135             :  * Parse private key from @a filename in @a buf.
    1136             :  *
    1137             :  * @param filename name of the file we are parsing, for logging
    1138             :  * @param buf key material
    1139             :  * @param buf_size number of bytes in @a buf
    1140             :  */
    1141             : static void
    1142           0 : parse_key (const char *filename,
    1143             :            const void *buf,
    1144             :            size_t buf_size)
    1145             : {
    1146             :   struct GNUNET_CRYPTO_EddsaPrivateKey priv;
    1147             :   char *anchor_s;
    1148             :   char dummy;
    1149             :   unsigned long long anchor_ll;
    1150             :   struct GNUNET_TIME_Absolute anchor;
    1151             : 
    1152           0 :   anchor_s = strrchr (filename,
    1153             :                       '/');
    1154           0 :   if (NULL == anchor_s)
    1155             :   {
    1156             :     /* File in a directory without '/' in the name, this makes no sense. */
    1157           0 :     GNUNET_break (0);
    1158           0 :     return;
    1159             :   }
    1160           0 :   anchor_s++;
    1161           0 :   if (1 != sscanf (anchor_s,
    1162             :                    "%llu%c",
    1163             :                    &anchor_ll,
    1164             :                    &dummy))
    1165             :   {
    1166             :     /* Filenames in KEYDIR must ONLY be the anchor time in seconds! */
    1167           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1168             :                 "Filename `%s' invalid for key file, skipping\n",
    1169             :                 filename);
    1170           0 :     return;
    1171             :   }
    1172           0 :   anchor.abs_value_us = anchor_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us;
    1173           0 :   if (anchor_ll != anchor.abs_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us)
    1174             :   {
    1175             :     /* Integer overflow. Bad, invalid filename. */
    1176           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1177             :                 "Filename `%s' invalid for key file, skipping\n",
    1178             :                 filename);
    1179           0 :     return;
    1180             :   }
    1181           0 :   if (buf_size != sizeof (priv))
    1182             :   {
    1183             :     /* Parser failure. */
    1184           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1185             :                 "File `%s' is malformed, skipping\n",
    1186             :                 filename);
    1187           0 :     return;
    1188             :   }
    1189           0 :   memcpy (&priv,
    1190             :           buf,
    1191             :           buf_size);
    1192             : 
    1193             :   {
    1194             :     struct GNUNET_CRYPTO_EddsaPublicKey pub;
    1195             :     struct Key *key;
    1196             :     struct Key *before;
    1197             : 
    1198           0 :     GNUNET_CRYPTO_eddsa_key_get_public (&priv,
    1199             :                                         &pub);
    1200           0 :     key = GNUNET_new (struct Key);
    1201           0 :     key->exchange_priv.eddsa_priv = priv;
    1202           0 :     key->exchange_pub.eddsa_pub = pub;
    1203           0 :     key->anchor = anchor;
    1204           0 :     key->filename = GNUNET_strdup (filename);
    1205           0 :     before = NULL;
    1206           0 :     for (struct Key *pos = keys_head;
    1207             :          NULL != pos;
    1208           0 :          pos = pos->next)
    1209             :     {
    1210           0 :       if (pos->anchor.abs_value_us > anchor.abs_value_us)
    1211           0 :         break;
    1212           0 :       before = pos;
    1213             :     }
    1214           0 :     GNUNET_CONTAINER_DLL_insert_after (keys_head,
    1215             :                                        keys_tail,
    1216             :                                        before,
    1217             :                                        key);
    1218           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1219             :                 "Imported key from `%s'\n",
    1220             :                 filename);
    1221             :   }
    1222             : }
    1223             : 
    1224             : 
    1225             : /**
    1226             :  * Import a private key from @a filename.
    1227             :  *
    1228             :  * @param cls NULL
    1229             :  * @param filename name of a file in the directory
    1230             :  */
    1231             : static int
    1232           0 : import_key (void *cls,
    1233             :             const char *filename)
    1234             : {
    1235             :   struct GNUNET_DISK_FileHandle *fh;
    1236             :   struct GNUNET_DISK_MapHandle *map;
    1237             :   void *ptr;
    1238             :   int fd;
    1239             :   struct stat sbuf;
    1240             : 
    1241             :   {
    1242             :     struct stat lsbuf;
    1243             : 
    1244           0 :     if (0 != lstat (filename,
    1245             :                     &lsbuf))
    1246             :     {
    1247           0 :       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
    1248             :                                 "lstat",
    1249             :                                 filename);
    1250           0 :       return GNUNET_OK;
    1251             :     }
    1252           0 :     if (! S_ISREG (lsbuf.st_mode))
    1253             :     {
    1254           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1255             :                   "File `%s' is not a regular file, which is not allowed for private keys!\n",
    1256             :                   filename);
    1257           0 :       return GNUNET_OK;
    1258             :     }
    1259             :   }
    1260             : 
    1261           0 :   fd = open (filename,
    1262             :              O_CLOEXEC);
    1263           0 :   if (-1 == fd)
    1264             :   {
    1265           0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
    1266             :                               "open",
    1267             :                               filename);
    1268           0 :     return GNUNET_OK;
    1269             :   }
    1270           0 :   if (0 != fstat (fd,
    1271             :                   &sbuf))
    1272             :   {
    1273           0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
    1274             :                               "stat",
    1275             :                               filename);
    1276           0 :     return GNUNET_OK;
    1277             :   }
    1278           0 :   if (! S_ISREG (sbuf.st_mode))
    1279             :   {
    1280           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1281             :                 "File `%s' is not a regular file, which is not allowed for private keys!\n",
    1282             :                 filename);
    1283           0 :     return GNUNET_OK;
    1284             :   }
    1285           0 :   if (0 != (sbuf.st_mode & (S_IWUSR | S_IRWXG | S_IRWXO)))
    1286             :   {
    1287             :     /* permission are NOT tight, try to patch them up! */
    1288           0 :     if (0 !=
    1289           0 :         fchmod (fd,
    1290             :                 S_IRUSR))
    1291             :     {
    1292           0 :       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
    1293             :                                 "fchmod",
    1294             :                                 filename);
    1295             :       /* refuse to use key if file has wrong permissions */
    1296           0 :       GNUNET_break (0 == close (fd));
    1297           0 :       return GNUNET_OK;
    1298             :     }
    1299             :   }
    1300           0 :   fh = GNUNET_DISK_get_handle_from_int_fd (fd);
    1301           0 :   if (NULL == fh)
    1302             :   {
    1303           0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
    1304             :                               "open",
    1305             :                               filename);
    1306           0 :     GNUNET_break (0 == close (fd));
    1307           0 :     return GNUNET_OK;
    1308             :   }
    1309           0 :   if (sbuf.st_size > 2048)
    1310             :   {
    1311           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1312             :                 "File `%s' to big to be a private key\n",
    1313             :                 filename);
    1314           0 :     GNUNET_DISK_file_close (fh);
    1315           0 :     return GNUNET_OK;
    1316             :   }
    1317           0 :   ptr = GNUNET_DISK_file_map (fh,
    1318             :                               &map,
    1319             :                               GNUNET_DISK_MAP_TYPE_READ,
    1320           0 :                               (size_t) sbuf.st_size);
    1321           0 :   if (NULL == ptr)
    1322             :   {
    1323           0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
    1324             :                               "mmap",
    1325             :                               filename);
    1326           0 :     GNUNET_DISK_file_close (fh);
    1327           0 :     return GNUNET_OK;
    1328             :   }
    1329           0 :   parse_key (filename,
    1330             :              ptr,
    1331           0 :              (size_t) sbuf.st_size);
    1332           0 :   GNUNET_DISK_file_unmap (map);
    1333           0 :   GNUNET_DISK_file_close (fh);
    1334           0 :   return GNUNET_OK;
    1335             : }
    1336             : 
    1337             : 
    1338             : /**
    1339             :  * Load the various duration values from #kcfg.
    1340             :  *
    1341             :  * @return #GNUNET_OK on success
    1342             :  */
    1343             : static int
    1344          12 : load_durations (void)
    1345             : {
    1346          12 :   if (GNUNET_OK !=
    1347          12 :       GNUNET_CONFIGURATION_get_value_time (kcfg,
    1348             :                                            "taler-exchange-secmod-eddsa",
    1349             :                                            "OVERLAP_DURATION",
    1350             :                                            &overlap_duration))
    1351             :   {
    1352           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1353             :                                "taler-exchange-secmod-eddsa",
    1354             :                                "OVERLAP_DURATION");
    1355           0 :     return GNUNET_SYSERR;
    1356             :   }
    1357          12 :   if (GNUNET_OK !=
    1358          12 :       GNUNET_CONFIGURATION_get_value_time (kcfg,
    1359             :                                            "taler-exchange-secmod-eddsa",
    1360             :                                            "DURATION",
    1361             :                                            &duration))
    1362             :   {
    1363           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1364             :                                "taler-exchange-secmod-eddsa",
    1365             :                                "DURATION");
    1366           0 :     return GNUNET_SYSERR;
    1367             :   }
    1368          12 :   GNUNET_TIME_round_rel (&overlap_duration);
    1369             : 
    1370          12 :   if (GNUNET_OK !=
    1371          12 :       GNUNET_CONFIGURATION_get_value_time (kcfg,
    1372             :                                            "taler-exchange-secmod-eddsa",
    1373             :                                            "LOOKAHEAD_SIGN",
    1374             :                                            &lookahead_sign))
    1375             :   {
    1376           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1377             :                                "taler-exchange-secmod-eddsa",
    1378             :                                "LOOKAHEAD_SIGN");
    1379           0 :     return GNUNET_SYSERR;
    1380             :   }
    1381          12 :   GNUNET_TIME_round_rel (&lookahead_sign);
    1382          12 :   return GNUNET_OK;
    1383             : }
    1384             : 
    1385             : 
    1386             : /**
    1387             :  * Function run on shutdown. Stops the various jobs (nicely).
    1388             :  *
    1389             :  * @param cls NULL
    1390             :  */
    1391             : static void
    1392          10 : do_shutdown (void *cls)
    1393             : {
    1394             :   (void) cls;
    1395          10 :   if (NULL != read_task)
    1396             :   {
    1397          10 :     GNUNET_SCHEDULER_cancel (read_task);
    1398          10 :     read_task = NULL;
    1399             :   }
    1400          10 :   if (NULL != unix_sock)
    1401             :   {
    1402          10 :     GNUNET_break (GNUNET_OK ==
    1403             :                   GNUNET_NETWORK_socket_close (unix_sock));
    1404          10 :     unix_sock = NULL;
    1405             :   }
    1406          10 :   if (0 != unlink (unixpath))
    1407             :   {
    1408           0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
    1409             :                               "unlink",
    1410             :                               unixpath);
    1411             :   }
    1412          10 :   GNUNET_free (unixpath);
    1413          10 :   if (NULL != keygen_task)
    1414             :   {
    1415          10 :     GNUNET_SCHEDULER_cancel (keygen_task);
    1416          10 :     keygen_task = NULL;
    1417             :   }
    1418          10 :   if (NULL != done_task)
    1419             :   {
    1420          10 :     GNUNET_SCHEDULER_cancel (done_task);
    1421          10 :     done_task = NULL;
    1422             :   }
    1423             :   /* shut down worker threads */
    1424          10 :   if (NULL != workers)
    1425             :   {
    1426          10 :     GNUNET_assert (0 == pthread_mutex_lock (&work_lock));
    1427          10 :     in_shutdown = true;
    1428          10 :     GNUNET_assert (0 == pthread_cond_broadcast (&work_cond));
    1429          10 :     GNUNET_assert (0 == pthread_mutex_unlock (&work_lock));
    1430         170 :     for (unsigned int i = 0; i<num_workers; i++)
    1431         160 :       GNUNET_assert (0 == pthread_join (workers[i],
    1432             :                                         NULL));
    1433             :   }
    1434          10 :   if (NULL != done_signal)
    1435             :   {
    1436          10 :     GNUNET_break (GNUNET_OK ==
    1437             :                   GNUNET_NETWORK_socket_close (done_signal));
    1438          10 :     done_signal = NULL;
    1439             :   }
    1440          10 : }
    1441             : 
    1442             : 
    1443             : /**
    1444             :  * Main function that will be run under the GNUnet scheduler.
    1445             :  *
    1446             :  * @param cls closure
    1447             :  * @param args remaining command-line arguments
    1448             :  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
    1449             :  * @param cfg configuration
    1450             :  */
    1451             : static void
    1452          12 : run (void *cls,
    1453             :      char *const *args,
    1454             :      const char *cfgfile,
    1455             :      const struct GNUNET_CONFIGURATION_Handle *cfg)
    1456             : {
    1457             :   (void) cls;
    1458             :   (void) args;
    1459             :   (void) cfgfile;
    1460          12 :   kcfg = cfg;
    1461          12 :   if (now.abs_value_us != now_tmp.abs_value_us)
    1462             :   {
    1463             :     /* The user gave "--now", use it! */
    1464           0 :     now = now_tmp;
    1465             :   }
    1466             :   else
    1467             :   {
    1468             :     /* get current time again, we may be timetraveling! */
    1469          12 :     now = GNUNET_TIME_absolute_get ();
    1470             :   }
    1471          12 :   GNUNET_TIME_round_abs (&now);
    1472             : 
    1473             :   {
    1474             :     char *pfn;
    1475             : 
    1476          12 :     if (GNUNET_OK !=
    1477          12 :         GNUNET_CONFIGURATION_get_value_filename (kcfg,
    1478             :                                                  "taler-exchange-secmod-eddsa",
    1479             :                                                  "SM_PRIV_KEY",
    1480             :                                                  &pfn))
    1481             :     {
    1482           0 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1483             :                                  "taler-exchange-secmod-eddsa",
    1484             :                                  "SM_PRIV_KEY");
    1485           0 :       global_ret = 1;
    1486           0 :       return;
    1487             :     }
    1488          12 :     if (GNUNET_SYSERR ==
    1489          12 :         GNUNET_CRYPTO_eddsa_key_from_file (pfn,
    1490             :                                            GNUNET_YES,
    1491             :                                            &smpriv.eddsa_priv))
    1492             :     {
    1493           0 :       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    1494             :                                  "taler-exchange-secmod-rsa",
    1495             :                                  "SM_PRIV_KEY",
    1496             :                                  "Could not use file to persist private key");
    1497           0 :       GNUNET_free (pfn);
    1498           0 :       global_ret = 1;
    1499           0 :       return;
    1500             :     }
    1501          12 :     GNUNET_free (pfn);
    1502          12 :     GNUNET_CRYPTO_eddsa_key_get_public (&smpriv.eddsa_priv,
    1503             :                                         &smpub.eddsa_pub);
    1504             :   }
    1505             : 
    1506          12 :   if (GNUNET_OK !=
    1507          12 :       load_durations ())
    1508             :   {
    1509           0 :     global_ret = 1;
    1510           0 :     return;
    1511             :   }
    1512          12 :   if (GNUNET_OK !=
    1513          12 :       GNUNET_CONFIGURATION_get_value_filename (kcfg,
    1514             :                                                "taler-exchange-secmod-eddsa",
    1515             :                                                "KEY_DIR",
    1516             :                                                &keydir))
    1517             :   {
    1518           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1519             :                                "taler-exchange-secmod-eddsa",
    1520             :                                "KEY_DIR");
    1521           0 :     global_ret = 1;
    1522           0 :     return;
    1523             :   }
    1524             : 
    1525             :   /* Create client directory and set permissions. */
    1526             :   {
    1527             :     char *client_dir;
    1528             : 
    1529          12 :     if (GNUNET_OK !=
    1530          12 :         GNUNET_CONFIGURATION_get_value_filename (kcfg,
    1531             :                                                  "taler-exchange-secmod-eddsa",
    1532             :                                                  "CLIENT_DIR",
    1533             :                                                  &client_dir))
    1534             :     {
    1535           0 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1536             :                                  "taler-exchange-secmod-eddsa",
    1537             :                                  "CLIENT_DIR");
    1538           0 :       global_ret = 3;
    1539           2 :       return;
    1540             :     }
    1541             : 
    1542          12 :     if (GNUNET_OK != GNUNET_DISK_directory_create (client_dir))
    1543             :     {
    1544           2 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1545             :                   "Can't create client directory (%s)\n",
    1546             :                   client_dir);
    1547           2 :       global_ret = 3;
    1548           2 :       return;
    1549             :     }
    1550             :     /* Set sticky group bit, so that clients will be writeable by the current service. */
    1551          10 :     if (0 != chmod (client_dir,
    1552             :                     S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP
    1553             :                     | S_ISGID))
    1554             :     {
    1555           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1556             :                   "Can't set permissions for client directory (%s)\n",
    1557             :                   client_dir);
    1558           0 :       global_ret = 3;
    1559           0 :       return;
    1560             :     }
    1561             : 
    1562          10 :     GNUNET_free (client_dir);
    1563             :   }
    1564             : 
    1565          10 :   if (GNUNET_OK !=
    1566          10 :       GNUNET_CONFIGURATION_get_value_filename (kcfg,
    1567             :                                                "taler-exchange-secmod-eddsa",
    1568             :                                                "UNIXPATH",
    1569             :                                                &unixpath))
    1570             :   {
    1571           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    1572             :                                "taler-exchange-secmod-eddsa",
    1573             :                                "UNIXPATH");
    1574           0 :     global_ret = 3;
    1575           0 :     return;
    1576             :   }
    1577             : 
    1578          10 :   GNUNET_assert (NULL != unixpath);
    1579          10 :   unix_sock = TES_open_socket (unixpath);
    1580             : 
    1581          10 :   if (NULL == unix_sock)
    1582             :   {
    1583           0 :     GNUNET_free (unixpath);
    1584           0 :     global_ret = 2;
    1585           0 :     return;
    1586             :   }
    1587             : 
    1588          10 :   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
    1589             :                                  NULL);
    1590             : 
    1591             :   /* Load keys */
    1592          10 :   GNUNET_break (GNUNET_OK ==
    1593             :                 GNUNET_DISK_directory_create (keydir));
    1594          10 :   GNUNET_DISK_directory_scan (keydir,
    1595             :                               &import_key,
    1596             :                               NULL);
    1597             :   /* start job to accept incoming requests on 'sock' */
    1598          10 :   read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
    1599             :                                              unix_sock,
    1600             :                                              &read_job,
    1601             :                                              NULL);
    1602             :   /* start job to keep keys up-to-date; MUST be run before the #read_task,
    1603             :      hence with priority. */
    1604          10 :   keygen_task = GNUNET_SCHEDULER_add_with_priority (
    1605             :     GNUNET_SCHEDULER_PRIORITY_URGENT,
    1606             :     &update_keys,
    1607             :     NULL);
    1608             : 
    1609             :   /* start job to handle completed work */
    1610             :   {
    1611             :     int fd;
    1612             : 
    1613          10 :     fd = eventfd (0,
    1614             :                   EFD_NONBLOCK | EFD_CLOEXEC);
    1615          10 :     if (-1 == fd)
    1616             :     {
    1617           0 :       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
    1618             :                            "eventfd");
    1619           0 :       global_ret = 6;
    1620           0 :       GNUNET_SCHEDULER_shutdown ();
    1621           0 :       return;
    1622             :     }
    1623          10 :     done_signal = GNUNET_NETWORK_socket_box_native (fd);
    1624             :   }
    1625          10 :   done_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
    1626             :                                              done_signal,
    1627             :                                              &handle_done,
    1628             :                                              NULL);
    1629             : 
    1630             :   /* start crypto workers */
    1631          10 :   if (0 == num_workers)
    1632          10 :     num_workers = sysconf (_SC_NPROCESSORS_CONF);
    1633          10 :   if (0 == num_workers)
    1634           0 :     num_workers = 1;
    1635          10 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1636             :               "Starting %u crypto workers\n",
    1637             :               num_workers);
    1638          10 :   workers = GNUNET_new_array (num_workers,
    1639             :                               pthread_t);
    1640         170 :   for (unsigned int i = 0; i<num_workers; i++)
    1641         160 :     GNUNET_assert (0 ==
    1642             :                    pthread_create (&workers[i],
    1643             :                                    NULL,
    1644             :                                    &sign_worker,
    1645             :                                    NULL));
    1646             : }
    1647             : 
    1648             : 
    1649             : /**
    1650             :  * The entry point.
    1651             :  *
    1652             :  * @param argc number of arguments in @a argv
    1653             :  * @param argv command-line arguments
    1654             :  * @return 0 on normal termination
    1655             :  */
    1656             : int
    1657          12 : main (int argc,
    1658             :       char **argv)
    1659             : {
    1660          12 :   struct GNUNET_GETOPT_CommandLineOption options[] = {
    1661          12 :     GNUNET_GETOPT_option_timetravel ('T',
    1662             :                                      "timetravel"),
    1663          12 :     GNUNET_GETOPT_option_uint ('p',
    1664             :                                "parallelism",
    1665             :                                "NUM_WORKERS",
    1666             :                                "number of worker threads to use",
    1667             :                                &num_workers),
    1668          12 :     GNUNET_GETOPT_option_absolute_time ('t',
    1669             :                                         "time",
    1670             :                                         "TIMESTAMP",
    1671             :                                         "pretend it is a different time for the update",
    1672             :                                         &now_tmp),
    1673             :     GNUNET_GETOPT_OPTION_END
    1674             :   };
    1675             :   int ret;
    1676             : 
    1677             :   /* Restrict permissions for the key files that we create. */
    1678          12 :   (void) umask (S_IWGRP | S_IROTH | S_IWOTH | S_IXOTH);
    1679             : 
    1680             :   /* force linker to link against libtalerutil; if we do
    1681             :    not do this, the linker may "optimize" libtalerutil
    1682             :    away and skip #TALER_OS_init(), which we do need */
    1683          12 :   TALER_OS_init ();
    1684          12 :   now = now_tmp = GNUNET_TIME_absolute_get ();
    1685          12 :   ret = GNUNET_PROGRAM_run (argc, argv,
    1686             :                             "taler-exchange-secmod-eddsa",
    1687             :                             "Handle private EDDSA key operations for a Taler exchange",
    1688             :                             options,
    1689             :                             &run,
    1690             :                             NULL);
    1691          12 :   if (GNUNET_NO == ret)
    1692           0 :     return 0;
    1693          12 :   if (GNUNET_SYSERR == ret)
    1694           0 :     return 1;
    1695          12 :   return global_ret;
    1696             : }

Generated by: LCOV version 1.14