diff options
Diffstat (limited to 'src/util/taler-exchange-secmod-eddsa.c')
-rw-r--r-- | src/util/taler-exchange-secmod-eddsa.c | 1493 |
1 files changed, 505 insertions, 988 deletions
diff --git a/src/util/taler-exchange-secmod-eddsa.c b/src/util/taler-exchange-secmod-eddsa.c index dc2d35d13..0b95447f7 100644 --- a/src/util/taler-exchange-secmod-eddsa.c +++ b/src/util/taler-exchange-secmod-eddsa.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2020 Taler Systems SA + Copyright (C) 2014-2021 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -26,7 +26,7 @@ * and merged with the public keys of the helper by the exchange HTTPD! * - the main loop of the helper is SINGLE-THREADED, but there are * threads for crypto-workers which (only) do the signing in parallel, - * working of a work-queue. + * one per client. * - thread-safety: signing happens in parallel, thus when REMOVING private keys, * we must ensure that all signers are done before we fully free() the * private key. This is done by reference counting (as work is always @@ -37,10 +37,10 @@ #include "taler-exchange-secmod-eddsa.h" #include <gcrypt.h> #include <pthread.h> -#include <sys/eventfd.h> #include "taler_error_codes.h" #include "taler_signatures.h" #include "secmod_common.h" +#include <poll.h> /** @@ -77,7 +77,12 @@ struct Key /** * Time at which this key is supposed to become valid. */ - struct GNUNET_TIME_Absolute anchor; + struct GNUNET_TIME_Timestamp anchor; + + /** + * Generation when this key was created or revoked. + */ + uint64_t key_gen; /** * Reference counter. Counts the number of threads that are @@ -95,92 +100,6 @@ struct Key /** - * Information we keep for a client connected to us. - */ -struct Client -{ - - /** - * Kept in a DLL. - */ - struct Client *next; - - /** - * Kept in a DLL. - */ - struct Client *prev; - - /** - * Client address. - */ - struct sockaddr_un addr; - - /** - * Number of bytes used in @e addr. - */ - socklen_t addr_size; - -}; - - -struct WorkItem -{ - - /** - * Kept in a DLL. - */ - struct WorkItem *next; - - /** - * Kept in a DLL. - */ - struct WorkItem *prev; - - /** - * Key to be used for this operation. - */ - struct Key *key; - - /** - * EDDSA signature over @e msg using @e key. Result of doing the work. - */ - struct TALER_ExchangeSignatureP signature; - - /** - * Message to sign. - */ - struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; - - /** - * Client address. - */ - struct sockaddr_un addr; - - /** - * Number of bytes used in @e addr. - */ - socklen_t addr_size; - - /** - * Operation status code. - */ - enum TALER_ErrorCode ec; - -}; - - -/** - * Private key of this security module. Used to sign denomination key - * announcements. - */ -static struct TALER_SecurityModulePrivateKeyP smpriv; - -/** - * Public key of this security module. - */ -static struct TALER_SecurityModulePublicKeyP smpub; - -/** * Head of DLL of actual keys, sorted by anchor. */ static struct Key *keys_head; @@ -201,33 +120,28 @@ static struct GNUNET_TIME_Relative duration; static int global_ret; /** - * Number of worker threads to use. Default (0) is to use one per CPU core - * available. - * Length of the #workers array. - */ -static unsigned int num_workers; - -/** * Time when the key update is executed. * Either the actual current time, or a pretended time. */ -static struct GNUNET_TIME_Absolute now; +static struct GNUNET_TIME_Timestamp now; /** * The time for the key update, as passed by the user * on the command line. */ -static struct GNUNET_TIME_Absolute now_tmp; +static struct GNUNET_TIME_Timestamp now_tmp; /** - * Handle to the exchange's configuration + * Where do we store the keys? */ -static const struct GNUNET_CONFIGURATION_Handle *kcfg; +static char *keydir; /** - * Where do we store the keys? + * Name of the configuration section prefix to use. Usually either "taler-exchange" or + * "donau". The actual configuration section will then be + * "$SECTION-secmod-eddsa". */ -static char *keydir; +static char *section; /** * How much should coin creation duration overlap @@ -242,323 +156,86 @@ static struct GNUNET_TIME_Relative overlap_duration; static struct GNUNET_TIME_Relative lookahead_sign; /** - * Our listen socket. - */ -static struct GNUNET_NETWORK_Handle *unix_sock; - -/** - * Path where we are listening. - */ -static char *unixpath; - -/** - * Task run to accept new inbound connections. - */ -static struct GNUNET_SCHEDULER_Task *read_task; - -/** * Task run to generate new keys. */ static struct GNUNET_SCHEDULER_Task *keygen_task; /** - * Head of DLL of clients connected to us. - */ -static struct Client *clients_head; - -/** - * Tail of DLL of clients connected to us. - */ -static struct Client *clients_tail; - -/** - * Head of DLL with pending signing operations. - */ -static struct WorkItem *work_head; - -/** - * Tail of DLL with pending signing operations. - */ -static struct WorkItem *work_tail; - -/** - * Lock for the work queue. - */ -static pthread_mutex_t work_lock; - -/** - * Condition variable for the semaphore of the work queue. - */ -static pthread_cond_t work_cond = PTHREAD_COND_INITIALIZER; - -/** - * Number of items in the work queue. Also used as the semaphore counter. - */ -static unsigned long long work_counter; - -/** - * Head of DLL with completed signing operations. - */ -static struct WorkItem *done_head; - -/** - * Tail of DLL with completed signing operations. - */ -static struct WorkItem *done_tail; - -/** - * Lock for the done queue. - */ -static pthread_mutex_t done_lock; - -/** - * Task waiting for work to be done. - */ -static struct GNUNET_SCHEDULER_Task *done_task; - -/** - * Signal used by threads to notify the #done_task that they - * completed work that is now in the done queue. - */ -static struct GNUNET_NETWORK_Handle *done_signal; - -/** - * Set once we are in shutdown and workers should terminate. - */ -static volatile bool in_shutdown; - -/** - * Array of #num_workers sign_worker() threads. - */ -static pthread_t *workers; - - -/** - * Main function of a worker thread that signs. - * - * @param cls NULL - * @return NULL - */ -static void * -sign_worker (void *cls) -{ - (void) cls; - GNUNET_assert (0 == pthread_mutex_lock (&work_lock)); - while (! in_shutdown) - { - struct WorkItem *wi; - - while (NULL != (wi = work_head)) - { - /* take work from queue */ - GNUNET_CONTAINER_DLL_remove (work_head, - work_tail, - wi); - work_counter--; - GNUNET_assert (0 == pthread_mutex_unlock (&work_lock)); - { - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_sign_ (&wi->key->exchange_priv.eddsa_priv, - wi->purpose, - &wi->signature.eddsa_signature)) - wi->ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; - else - wi->ec = TALER_EC_NONE; - } - /* put completed work into done queue */ - GNUNET_assert (0 == pthread_mutex_lock (&done_lock)); - GNUNET_CONTAINER_DLL_insert (done_head, - done_tail, - wi); - GNUNET_assert (0 == pthread_mutex_unlock (&done_lock)); - { - uint64_t val = GNUNET_htonll (1); - - /* raise #done_signal */ - if (sizeof(val) != - write (GNUNET_NETWORK_get_fd (done_signal), - &val, - sizeof (val))) - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, - "write(eventfd)"); - } - GNUNET_assert (0 == pthread_mutex_lock (&work_lock)); - } - if (in_shutdown) - break; - /* queue is empty, wait for work */ - GNUNET_assert (0 == - pthread_cond_wait (&work_cond, - &work_lock)); - } - GNUNET_assert (0 == - pthread_mutex_unlock (&work_lock)); - return NULL; -} - - -/** - * Free @a client, releasing all (remaining) state. - * - * @param[in] client data to free - */ -static void -free_client (struct Client *client) -{ - GNUNET_CONTAINER_DLL_remove (clients_head, - clients_tail, - client); - GNUNET_free (client); -} - - -/** - * Function run to read incoming requests from a client. - * - * @param cls the `struct Client` + * Lock for the keys queue. */ -static void -read_job (void *cls); - +static pthread_mutex_t keys_lock; /** - * Free @a key. It must already have been removed from the DLL. - * - * @param[in] key the key to free + * Current key generation. */ -static void -free_key (struct Key *key) -{ - GNUNET_free (key->filename); - GNUNET_free (key); -} +static uint64_t key_gen; /** - * Send a message starting with @a hdr to @a client. We expect that - * the client is mostly able to handle everything at whatever speed - * we have (after all, the crypto should be the slow part). However, - * especially on startup when we send all of our keys, it is possible - * that the client cannot keep up. In that case, we throttle when - * sending fails. This does not work with poll() as we cannot specify - * the sendto() target address with poll(). So we nanosleep() instead. + * Notify @a client about @a key becoming available. * - * @param addr address where to send the message - * @param addr_size number of bytes in @a addr - * @param hdr beginning of the message, length indicated in size field + * @param[in,out] client the client to notify; possible freed if transmission fails + * @param key the key to notify @a client about * @return #GNUNET_OK on success */ -static int -transmit (const struct sockaddr_un *addr, - socklen_t addr_size, - const struct GNUNET_MessageHeader *hdr) +static enum GNUNET_GenericReturnValue +notify_client_key_add (struct TES_Client *client, + const struct Key *key) { - for (unsigned int i = 0; i<100; i++) + struct TALER_CRYPTO_EddsaKeyAvailableNotification an = { + .header.size = htons (sizeof (an)), + .header.type = htons (TALER_HELPER_EDDSA_MT_AVAIL), + .anchor_time = GNUNET_TIME_timestamp_hton (key->anchor), + .duration = GNUNET_TIME_relative_hton (duration), + .exchange_pub = key->exchange_pub, + .secm_pub = TES_smpub + }; + + TALER_exchange_secmod_eddsa_sign (&key->exchange_pub, + key->anchor, + duration, + &TES_smpriv, + &an.secm_sig); + if (GNUNET_OK != + TES_transmit (client->csock, + &an.header)) { - ssize_t ret = sendto (GNUNET_NETWORK_get_fd (unix_sock), - hdr, - ntohs (hdr->size), - 0 /* no flags => blocking! */, - (const struct sockaddr *) addr, - addr_size); - if ( (-1 == ret) && - (EAGAIN == errno) ) - { - /* _Maybe_ with blocking sendto(), this should no - longer be needed; still keeping it just in case. */ - /* Wait a bit, in case client is just too slow */ - struct timespec req = { - .tv_sec = 0, - .tv_nsec = 1000 - }; - nanosleep (&req, NULL); - continue; - } - if (ret == ntohs (hdr->size)) - return GNUNET_OK; - if (ret != ntohs (hdr->size)) - break; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Client %p must have disconnected\n", + client); + return GNUNET_SYSERR; } - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, - "sendto"); - return GNUNET_SYSERR; + return GNUNET_OK; } /** - * Process completed tasks that are in the #done_head queue, sending - * the result back to the client (and resuming the client). + * Notify @a client about @a key being purged. * - * @param cls NULL + * @param[in,out] client the client to notify; possible freed if transmission fails + * @param key the key to notify @a client about + * @return #GNUNET_OK on success */ -static void -handle_done (void *cls) +static enum GNUNET_GenericReturnValue +notify_client_key_del (struct TES_Client *client, + const struct Key *key) { - uint64_t data; - (void) cls; + struct TALER_CRYPTO_EddsaKeyPurgeNotification pn = { + .header.type = htons (TALER_HELPER_EDDSA_MT_PURGE), + .header.size = htons (sizeof (pn)), + .exchange_pub = key->exchange_pub + }; - /* consume #done_signal */ - if (sizeof (data) != - read (GNUNET_NETWORK_get_fd (done_signal), - &data, - sizeof (data))) - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, - "read(eventfd)"); - done_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, - done_signal, - &handle_done, - NULL); - GNUNET_assert (0 == pthread_mutex_lock (&done_lock)); - while (NULL != done_head) + if (GNUNET_OK != + TES_transmit (client->csock, + &pn.header)) { - struct WorkItem *wi = done_head; - - GNUNET_CONTAINER_DLL_remove (done_head, - done_tail, - wi); - GNUNET_assert (0 == pthread_mutex_unlock (&done_lock)); - if (TALER_EC_NONE != wi->ec) - { - struct TALER_CRYPTO_EddsaSignFailure sf = { - .header.size = htons (sizeof (sf)), - .header.type = htons (TALER_HELPER_EDDSA_MT_RES_SIGN_FAILURE), - .ec = htonl (wi->ec) - }; - - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Signing request %p failed, worker failed to produce signature\n", - wi); - (void) transmit (&wi->addr, - wi->addr_size, - &sf.header); - } - else - { - struct TALER_CRYPTO_EddsaSignResponse sr = { - .header.size = htons (sizeof (sr)), - .header.type = htons (TALER_HELPER_EDDSA_MT_RES_SIGNATURE), - .exchange_pub = wi->key->exchange_pub, - .exchange_sig = wi->signature - }; - - (void) transmit (&wi->addr, - wi->addr_size, - &sr.header); - } - { - struct Key *key = wi->key; - - key->rc--; - if ( (0 == key->rc) && - (key->purge) ) - free_key (key); - } - GNUNET_free (wi->purpose); - GNUNET_free (wi); - GNUNET_assert (0 == pthread_mutex_lock (&done_lock)); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Client %p must have disconnected\n", + client); + return GNUNET_SYSERR; } - GNUNET_assert (0 == pthread_mutex_unlock (&done_lock)); - + return GNUNET_OK; } @@ -567,19 +244,23 @@ handle_done (void *cls) * signature using the respective key and return the result to * the client. * - * @param addr address of the client making the request - * @param addr_size number of bytes in @a addr + * @param client the client making the request * @param sr the request details + * @return #GNUNET_OK on success */ -static void -handle_sign_request (const struct sockaddr_un *addr, - socklen_t addr_size, +static enum GNUNET_GenericReturnValue +handle_sign_request (struct TES_Client *client, const struct TALER_CRYPTO_EddsaSignRequest *sr) { const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose = &sr->purpose; - struct WorkItem *wi; size_t purpose_size = ntohs (sr->header.size) - sizeof (*sr) + sizeof (*purpose); + struct Key *key; + struct TALER_CRYPTO_EddsaSignResponse sres = { + .header.size = htons (sizeof (sres)), + .header.type = htons (TALER_HELPER_EDDSA_MT_RES_SIGNATURE) + }; + enum TALER_ErrorCode ec; if (purpose_size != htonl (purpose->size)) { @@ -591,122 +272,81 @@ handle_sign_request (const struct sockaddr_un *addr, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Signing request failed, request malformed\n"); - (void) transmit (addr, - addr_size, - &sf.header); - return; + return TES_transmit (client->csock, + &sf.header); } - { - struct GNUNET_TIME_Absolute now; - - now = GNUNET_TIME_absolute_get (); - if ( (now.abs_value_us >= keys_head->anchor.abs_value_us) && - (now.abs_value_us < keys_head->anchor.abs_value_us - + duration.rel_value_us) ) - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Signing at %llu with key valid from %llu to %llu\n", - (unsigned long long) now.abs_value_us, - (unsigned long long) keys_head->anchor.abs_value_us, - (unsigned long long) keys_head->anchor.abs_value_us - + duration.rel_value_us); - else - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Signing at %llu with key valid from %llu to %llu\n", - (unsigned long long) now.abs_value_us, - (unsigned long long) keys_head->anchor.abs_value_us, - (unsigned long long) keys_head->anchor.abs_value_us - + duration.rel_value_us); - } - wi = GNUNET_new (struct WorkItem); - wi->addr = *addr; - wi->addr_size = addr_size; - wi->key = keys_head; - keys_head->rc++; - wi->purpose = GNUNET_memdup (purpose, - purpose_size); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Received request to sign over %u bytes, queueing as %p\n", - (unsigned int) purpose_size, - wi); - GNUNET_assert (0 == pthread_mutex_lock (&work_lock)); - work_counter++; - GNUNET_CONTAINER_DLL_insert (work_head, - work_tail, - wi); - GNUNET_assert (0 == pthread_cond_signal (&work_cond)); - GNUNET_assert (0 == pthread_mutex_unlock (&work_lock)); -} - - -/** - * Notify @a client about @a key becoming available. - * - * @param[in,out] client the client to notify; possible freed if transmission fails - * @param key the key to notify @a client about - * @return #GNUNET_OK on success - */ -static int -notify_client_key_add (struct Client *client, - const struct Key *key) -{ - struct TALER_CRYPTO_EddsaKeyAvailableNotification an = { - .header.size = htons (sizeof (an)), - .header.type = htons (TALER_HELPER_EDDSA_MT_AVAIL), - .anchor_time = GNUNET_TIME_absolute_hton (key->anchor), - .duration = GNUNET_TIME_relative_hton (duration), - .exchange_pub = key->exchange_pub, - .secm_pub = smpub - }; - TALER_exchange_secmod_eddsa_sign (&key->exchange_pub, - key->anchor, - duration, - &smpriv, - &an.secm_sig); - if (GNUNET_OK != - transmit (&client->addr, - client->addr_size, - &an.header)) + GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); + key = keys_head; + while ( (NULL != key) && + (GNUNET_TIME_absolute_is_past ( + GNUNET_TIME_absolute_add (key->anchor.abs_time, + duration))) ) { + struct Key *nxt = key->next; + + if (0 != key->rc) + break; /* do later */ GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Client %s must have disconnected\n", - client->addr.sun_path); - free_client (client); - return GNUNET_SYSERR; + "Deleting past key %s (expired %s ago)\n", + TALER_B2S (&nxt->exchange_pub), + GNUNET_TIME_relative2s ( + GNUNET_TIME_absolute_get_duration ( + GNUNET_TIME_absolute_add (key->anchor.abs_time, + duration)), + GNUNET_YES)); + GNUNET_CONTAINER_DLL_remove (keys_head, + keys_tail, + key); + if ( (! key->purge) && + (0 != unlink (key->filename)) ) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, + "unlink", + key->filename); + GNUNET_free (key->filename); + GNUNET_free (key); + key = nxt; } - return GNUNET_OK; -} - - -/** - * Notify @a client about @a key being purged. - * - * @param[in,out] client the client to notify; possible freed if transmission fails - * @param key the key to notify @a client about - * @return #GNUNET_OK on success - */ -static int -notify_client_key_del (struct Client *client, - const struct Key *key) -{ - struct TALER_CRYPTO_EddsaKeyPurgeNotification pn = { - .header.type = htons (TALER_HELPER_EDDSA_MT_PURGE), - .header.size = htons (sizeof (pn)), - .exchange_pub = key->exchange_pub - }; + if (NULL == key) + { + GNUNET_break (0); + ec = TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING; + } + else + { + GNUNET_assert (key->rc < UINT_MAX); + key->rc++; + GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); - if (GNUNET_OK != - transmit (&client->addr, - client->addr_size, - &pn.header)) + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_sign_ (&key->exchange_priv.eddsa_priv, + purpose, + &sres.exchange_sig.eddsa_signature)) + ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; + else + ec = TALER_EC_NONE; + sres.exchange_pub = key->exchange_pub; + GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); + GNUNET_assert (key->rc > 0); + key->rc--; + } + GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); + if (TALER_EC_NONE != ec) { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Client %s must have disconnected\n", - client->addr.sun_path); - free_client (client); - return GNUNET_SYSERR; + struct TALER_CRYPTO_EddsaSignFailure sf = { + .header.size = htons (sizeof (sf)), + .header.type = htons (TALER_HELPER_EDDSA_MT_RES_SIGN_FAILURE), + .ec = htonl ((uint32_t) ec) + }; + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Signing request %p failed, worker failed to produce signature\n", + client); + return TES_transmit (client->csock, + &sf.header); } - return GNUNET_OK; + return TES_transmit (client->csock, + &sres.header); } @@ -717,7 +357,7 @@ notify_client_key_del (struct Client *client, * @param position where in the DLL will the @a key go * @return #GNUNET_OK on success */ -static int +static enum GNUNET_GenericReturnValue setup_key (struct Key *key, struct Key *position) { @@ -730,7 +370,7 @@ setup_key (struct Key *key, GNUNET_asprintf (&key->filename, "%s/%llu", keydir, - (unsigned long long) (key->anchor.abs_value_us + (unsigned long long) (key->anchor.abs_time.abs_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us)); if (GNUNET_OK != GNUNET_DISK_fn_write (key->filename, @@ -746,54 +386,67 @@ setup_key (struct Key *key, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Setup fresh private key in `%s'\n", key->filename); + key->key_gen = key_gen; key->exchange_priv.eddsa_priv = priv; key->exchange_pub.eddsa_pub = pub; GNUNET_CONTAINER_DLL_insert_after (keys_head, keys_tail, position, key); + return GNUNET_OK; +} - /* tell clients about new key */ - { - struct Client *nxt; - for (struct Client *client = clients_head; - NULL != client; - client = nxt) - { - nxt = client->next; - if (GNUNET_OK != - notify_client_key_add (client, - key)) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Failed to notify client about new key, client dropped\n"); - } - } +/** + * The validity period of a key @a key has expired. Purge it. + * + * @param[in] key expired or revoked key to purge + */ +static void +purge_key (struct Key *key) +{ + if (key->purge) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Key %s already purged, skipping\n", + TALER_B2S (&key->exchange_pub)); + return; } - return GNUNET_OK; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Purging key %s\n", + TALER_B2S (&key->exchange_pub)); + if (0 != unlink (key->filename)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, + "unlink", + key->filename); + key->purge = true; + key->key_gen = key_gen; + GNUNET_free (key->filename); } /** - * A client informs us that a key has been revoked. + * A @a client informs us that a key has been revoked. * Check if the key is still in use, and if so replace (!) * it with a fresh key. * - * @param addr address of the client making the request - * @param addr_size number of bytes in @a addr + * @param client the client making the request * @param rr the revocation request + * @return #GNUNET_OK on success */ -static void -handle_revoke_request (const struct sockaddr_un *addr, - socklen_t addr_size, +static enum GNUNET_GenericReturnValue +handle_revoke_request (struct TES_Client *client, const struct TALER_CRYPTO_EddsaRevokeRequest *rr) { struct Key *key; struct Key *nkey; + (void) client; key = NULL; - for (struct Key *pos = keys_head; NULL != pos; pos = pos->next) + GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); + for (struct Key *pos = keys_head; + NULL != pos; + pos = pos->next) if (0 == GNUNET_memcmp (&pos->exchange_pub, &rr->exchange_pub)) { @@ -802,16 +455,25 @@ handle_revoke_request (const struct sockaddr_un *addr, } if (NULL == key) { + GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Revocation request ignored, key unknown\n"); - return; + return GNUNET_OK; } - - /* kill existing key, done first to ensure this always happens */ - if (0 != unlink (key->filename)) - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, - "unlink", - key->filename); + if (key->purge) + { + GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Revocation request ignored, key %s already revoked\n", + TALER_B2S (&key->exchange_pub)); + return GNUNET_OK; + } + key_gen++; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Revoking key %s, bumping generation to %llu\n", + TALER_B2S (&key->exchange_pub), + (unsigned long long) key_gen); + purge_key (key); /* Setup replacement key */ nkey = GNUNET_new (struct Key); @@ -820,157 +482,156 @@ handle_revoke_request (const struct sockaddr_un *addr, setup_key (nkey, key)) { + GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); GNUNET_break (0); GNUNET_SCHEDULER_shutdown (); - global_ret = 44; - return; + global_ret = EXIT_FAILURE; + return GNUNET_SYSERR; } + GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); + TES_wake_clients (); + return GNUNET_OK; +} - /* get rid of the old key */ - key->purge = true; - GNUNET_CONTAINER_DLL_remove (keys_head, - keys_tail, - key); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Revocation complete\n"); - /* Tell clients this key is gone */ - { - struct Client *nxt; +/** + * Handle @a hdr message received from @a client. + * + * @param client the client that received the message + * @param hdr message that was received + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +eddsa_work_dispatch (struct TES_Client *client, + const struct GNUNET_MessageHeader *hdr) +{ + uint16_t msize = ntohs (hdr->size); - for (struct Client *client = clients_head; - NULL != client; - client = nxt) + switch (ntohs (hdr->type)) + { + case TALER_HELPER_EDDSA_MT_REQ_SIGN: + if (msize < sizeof (struct TALER_CRYPTO_EddsaSignRequest)) { - nxt = client->next; - if (GNUNET_OK != - notify_client_key_del (client, - key)) - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Failed to notify client about revoked key, client dropped\n"); + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return handle_sign_request ( + client, + (const struct TALER_CRYPTO_EddsaSignRequest *) hdr); + case TALER_HELPER_EDDSA_MT_REQ_REVOKE: + if (msize != sizeof (struct TALER_CRYPTO_EddsaRevokeRequest)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; } + return handle_revoke_request ( + client, + (const struct TALER_CRYPTO_EddsaRevokeRequest *) hdr); + default: + GNUNET_break_op (0); + return GNUNET_SYSERR; } - if (0 == key->rc) - free_key (key); } -static void -read_job (void *cls) +/** + * Send our initial key set to @a client together with the + * "sync" terminator. + * + * @param client the client to inform + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +eddsa_client_init (struct TES_Client *client) { - struct Client *client = cls; - char buf[65536]; - ssize_t buf_size; - const struct GNUNET_MessageHeader *hdr; - struct sockaddr_un addr; - socklen_t addr_size = sizeof (addr); - - read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, - unix_sock, - &read_job, - NULL); - buf_size = GNUNET_NETWORK_socket_recvfrom (unix_sock, - buf, - sizeof (buf), - (struct sockaddr *) &addr, - &addr_size); - if (-1 == buf_size) + GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); + for (struct Key *key = keys_head; + NULL != key; + key = key->next) { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, - "recv"); - return; - } - if (0 == buf_size) - { - return; - } - if (buf_size < sizeof (struct GNUNET_MessageHeader)) - { - GNUNET_break_op (0); - return; + if (GNUNET_OK != + notify_client_key_add (client, + key)) + { + GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); + GNUNET_break (0); + return GNUNET_SYSERR; + } } - hdr = (const struct GNUNET_MessageHeader *) buf; - if (ntohs (hdr->size) != buf_size) + client->key_gen = key_gen; + GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); { - GNUNET_break_op (0); - free_client (client); - return; + struct GNUNET_MessageHeader synced = { + .type = htons (TALER_HELPER_EDDSA_SYNCED), + .size = htons (sizeof (synced)) + }; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Client %p synced\n", + client); + if (GNUNET_OK != + TES_transmit (client->csock, + &synced)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } } - switch (ntohs (hdr->type)) + return GNUNET_OK; +} + + +/** + * Notify @a client about all changes to the keys since + * the last generation known to the @a client. + * + * @param client the client to notify + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +eddsa_update_client_keys (struct TES_Client *client) +{ + GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Updating client %p to generation %llu\n", + client, + (unsigned long long) key_gen); + for (struct Key *key = keys_head; + NULL != key; + key = key->next) { - case TALER_HELPER_EDDSA_MT_REQ_INIT: - if (ntohs (hdr->size) != sizeof (struct GNUNET_MessageHeader)) + if (key->key_gen <= client->key_gen) { - GNUNET_break_op (0); - return; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Skipping key %s, no change since generation %llu\n", + TALER_B2S (&key->exchange_pub), + (unsigned long long) client->key_gen); + continue; } + if (key->purge) { - struct Client *client; - - client = GNUNET_new (struct Client); - client->addr = addr; - client->addr_size = addr_size; - GNUNET_CONTAINER_DLL_insert (clients_head, - clients_tail, - client); - for (struct Key *key = keys_head; - NULL != key; - key = key->next) - { - if (GNUNET_OK != - notify_client_key_add (client, - key)) - { - /* client died, skip the rest */ - client = NULL; - break; - } - } - if (NULL != client) + if (GNUNET_OK != + notify_client_key_del (client, + key)) { - struct GNUNET_MessageHeader synced = { - .type = htons (TALER_HELPER_EDDSA_SYNCED), - .size = htons (sizeof (synced)) - }; - - if (GNUNET_OK != - transmit (&client->addr, - client->addr_size, - &synced)) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Client %s must have disconnected\n", - client->addr.sun_path); - free_client (client); - } + GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); + return GNUNET_SYSERR; } } - break; - case TALER_HELPER_EDDSA_MT_REQ_SIGN: - if (ntohs (hdr->size) < sizeof (struct TALER_CRYPTO_EddsaSignRequest)) - { - GNUNET_break_op (0); - return; - } - handle_sign_request (&addr, - addr_size, - (const struct TALER_CRYPTO_EddsaSignRequest *) buf); - break; - case TALER_HELPER_EDDSA_MT_REQ_REVOKE: - if (ntohs (hdr->size) != sizeof (struct TALER_CRYPTO_EddsaRevokeRequest)) + else { - GNUNET_break_op (0); - return; + if (GNUNET_OK != + notify_client_key_add (client, + key)) + { + GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); + return GNUNET_SYSERR; + } } - handle_revoke_request (&addr, - addr_size, - (const struct - TALER_CRYPTO_EddsaRevokeRequest *) buf); - break; - default: - GNUNET_break_op (0); - return; } + client->key_gen = key_gen; + GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); + return GNUNET_OK; } @@ -979,27 +640,25 @@ read_job (void *cls) * * @return #GNUNET_OK on success */ -static int +static enum GNUNET_GenericReturnValue create_key (void) { struct Key *key; - struct GNUNET_TIME_Absolute anchor; - struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Timestamp anchor; - now = GNUNET_TIME_absolute_get (); - (void) GNUNET_TIME_round_abs (&now); - if (NULL == keys_tail) + anchor = GNUNET_TIME_timestamp_get (); + if (NULL != keys_tail) { - anchor = now; - } - else - { - anchor = GNUNET_TIME_absolute_add (keys_tail->anchor, - GNUNET_TIME_relative_subtract ( - duration, - overlap_duration)); - if (now.abs_value_us > anchor.abs_value_us) - anchor = now; + struct GNUNET_TIME_Absolute abs; + + abs = GNUNET_TIME_absolute_add (keys_tail->anchor.abs_time, + GNUNET_TIME_relative_subtract ( + duration, + overlap_duration)); + if (GNUNET_TIME_absolute_cmp (anchor.abs_time, + <, + abs)) + anchor = GNUNET_TIME_absolute_to_timestamp (abs); } key = GNUNET_new (struct Key); key->anchor = anchor; @@ -1010,7 +669,7 @@ create_key (void) GNUNET_break (0); GNUNET_free (key); GNUNET_SCHEDULER_shutdown (); - global_ret = 42; + global_ret = EXIT_FAILURE; return GNUNET_SYSERR; } return GNUNET_OK; @@ -1025,14 +684,20 @@ create_key (void) static struct GNUNET_TIME_Absolute key_action_time (void) { - if (NULL == keys_head) + struct Key *nxt; + + nxt = keys_head; + while ( (NULL != nxt) && + (nxt->purge) ) + nxt = nxt->next; + if (NULL == nxt) return GNUNET_TIME_UNIT_ZERO_ABS; return GNUNET_TIME_absolute_min ( - GNUNET_TIME_absolute_add (keys_head->anchor, + GNUNET_TIME_absolute_add (nxt->anchor.abs_time, duration), GNUNET_TIME_absolute_subtract ( GNUNET_TIME_absolute_subtract ( - GNUNET_TIME_absolute_add (keys_tail->anchor, + GNUNET_TIME_absolute_add (keys_tail->anchor.abs_time, duration), lookahead_sign), overlap_duration)); @@ -1040,55 +705,6 @@ key_action_time (void) /** - * The validity period of a key @a key has expired. Purge it. - * - * @param[in] key expired key to purge and free - */ -static void -purge_key (struct Key *key) -{ - struct Client *nxt; - - for (struct Client *client = clients_head; - NULL != client; - client = nxt) - { - nxt = client->next; - if (GNUNET_OK != - notify_client_key_del (client, - key)) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Failed to notify client about purged key, client dropped\n"); - } - } - GNUNET_CONTAINER_DLL_remove (keys_head, - keys_tail, - key); - if (0 != unlink (key->filename)) - { - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, - "unlink", - key->filename); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Purged expired private key `%s'\n", - key->filename); - } - GNUNET_free (key->filename); - if (0 != key->rc) - { - /* delay until all signing threads are done with this key */ - key->purge = true; - return; - } - GNUNET_free (key); -} - - -/** * Create new keys and expire ancient keys. * * @param cls NULL @@ -1096,35 +712,63 @@ purge_key (struct Key *key) static void update_keys (void *cls) { - (void) cls; + bool wake = false; + struct Key *nxt; + (void) cls; keygen_task = NULL; + GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); /* create new keys */ while ( (NULL == keys_tail) || - (0 == - GNUNET_TIME_absolute_get_remaining ( - GNUNET_TIME_absolute_subtract ( - GNUNET_TIME_absolute_subtract ( - GNUNET_TIME_absolute_add (keys_tail->anchor, - duration), - lookahead_sign), - overlap_duration)).rel_value_us) ) + GNUNET_TIME_absolute_is_past ( + GNUNET_TIME_absolute_subtract ( + GNUNET_TIME_absolute_subtract ( + GNUNET_TIME_absolute_add (keys_tail->anchor.abs_time, + duration), + lookahead_sign), + overlap_duration)) ) { + if (! wake) + { + key_gen++; + wake = true; + } if (GNUNET_OK != create_key ()) { + GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); GNUNET_break (0); + global_ret = EXIT_FAILURE; GNUNET_SCHEDULER_shutdown (); return; } } - /* remove expired keys */ - while ( (NULL != keys_head) && - (0 == - GNUNET_TIME_absolute_get_remaining - (GNUNET_TIME_absolute_add (keys_head->anchor, - duration)).rel_value_us) ) - purge_key (keys_head); + nxt = keys_head; + /* purge expired keys */ + while ( (NULL != nxt) && + GNUNET_TIME_absolute_is_past ( + GNUNET_TIME_absolute_add (nxt->anchor.abs_time, + duration))) + { + if (! wake) + { + key_gen++; + wake = true; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Purging past key %s (expired %s ago)\n", + TALER_B2S (&nxt->exchange_pub), + GNUNET_TIME_relative2s ( + GNUNET_TIME_absolute_get_duration ( + GNUNET_TIME_absolute_add (nxt->anchor.abs_time, + duration)), + GNUNET_YES)); + purge_key (nxt); + nxt = nxt->next; + } + GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); + if (wake) + TES_wake_clients (); keygen_task = GNUNET_SCHEDULER_add_at (key_action_time (), &update_keys, NULL); @@ -1137,8 +781,9 @@ update_keys (void *cls) * @param filename name of the file we are parsing, for logging * @param buf key material * @param buf_size number of bytes in @a buf + * @return #GNUNET_OK on success */ -static void +static enum GNUNET_GenericReturnValue parse_key (const char *filename, const void *buf, size_t buf_size) @@ -1147,7 +792,7 @@ parse_key (const char *filename, char *anchor_s; char dummy; unsigned long long anchor_ll; - struct GNUNET_TIME_Absolute anchor; + struct GNUNET_TIME_Timestamp anchor; anchor_s = strrchr (filename, '/'); @@ -1155,7 +800,7 @@ parse_key (const char *filename, { /* File in a directory without '/' in the name, this makes no sense. */ GNUNET_break (0); - return; + return GNUNET_SYSERR; } anchor_s++; if (1 != sscanf (anchor_s, @@ -1167,16 +812,18 @@ parse_key (const char *filename, GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Filename `%s' invalid for key file, skipping\n", filename); - return; + return GNUNET_SYSERR; } - anchor.abs_value_us = anchor_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us; - if (anchor_ll != anchor.abs_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us) + anchor.abs_time.abs_value_us = anchor_ll + * GNUNET_TIME_UNIT_SECONDS.rel_value_us; + if (anchor_ll != anchor.abs_time.abs_value_us + / GNUNET_TIME_UNIT_SECONDS.rel_value_us) { /* Integer overflow. Bad, invalid filename. */ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Filename `%s' invalid for key file, skipping\n", filename); - return; + return GNUNET_SYSERR; } if (buf_size != sizeof (priv)) { @@ -1184,11 +831,11 @@ parse_key (const char *filename, GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "File `%s' is malformed, skipping\n", filename); - return; + return GNUNET_SYSERR; } - memcpy (&priv, - buf, - buf_size); + GNUNET_memcpy (&priv, + buf, + buf_size); { struct GNUNET_CRYPTO_EddsaPublicKey pub; @@ -1197,17 +844,19 @@ parse_key (const char *filename, GNUNET_CRYPTO_eddsa_key_get_public (&priv, &pub); + GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); key = GNUNET_new (struct Key); key->exchange_priv.eddsa_priv = priv; key->exchange_pub.eddsa_pub = pub; key->anchor = anchor; key->filename = GNUNET_strdup (filename); + key->key_gen = key_gen; before = NULL; for (struct Key *pos = keys_head; NULL != pos; pos = pos->next) { - if (pos->anchor.abs_value_us > anchor.abs_value_us) + if (GNUNET_TIME_timestamp_cmp (pos->anchor, >, anchor)) break; before = pos; } @@ -1215,10 +864,12 @@ parse_key (const char *filename, keys_tail, before, key); + GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Imported key from `%s'\n", filename); } + return GNUNET_OK; } @@ -1228,7 +879,7 @@ parse_key (const char *filename, * @param cls NULL * @param filename name of a file in the directory */ -static int +static enum GNUNET_GenericReturnValue import_key (void *cls, const char *filename) { @@ -1238,6 +889,7 @@ import_key (void *cls, int fd; struct stat sbuf; + (void) cls; { struct stat lsbuf; @@ -1259,7 +911,7 @@ import_key (void *cls, } fd = open (filename, - O_CLOEXEC); + O_RDONLY | O_CLOEXEC); if (-1 == fd) { GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, @@ -1273,6 +925,7 @@ import_key (void *cls, GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "stat", filename); + GNUNET_break (0 == close (fd)); return GNUNET_OK; } if (! S_ISREG (sbuf.st_mode)) @@ -1280,6 +933,7 @@ import_key (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "File `%s' is not a regular file, which is not allowed for private keys!\n", filename); + GNUNET_break (0 == close (fd)); return GNUNET_OK; } if (0 != (sbuf.st_mode & (S_IWUSR | S_IRWXG | S_IRWXO))) @@ -1326,9 +980,9 @@ import_key (void *cls, GNUNET_DISK_file_close (fh); return GNUNET_OK; } - parse_key (filename, - ptr, - (size_t) sbuf.st_size); + (void) parse_key (filename, + ptr, + (size_t) sbuf.st_size); GNUNET_DISK_file_unmap (map); GNUNET_DISK_file_close (fh); return GNUNET_OK; @@ -1336,49 +990,56 @@ import_key (void *cls, /** - * Load the various duration values from #kcfg. + * Load the various duration values from @a kcfg. * + * @param cfg configuration to use * @return #GNUNET_OK on success */ -static int -load_durations (void) +static enum GNUNET_GenericReturnValue +load_durations (const struct GNUNET_CONFIGURATION_Handle *cfg) { + char *secname; + + GNUNET_asprintf (&secname, + "%s-secmod-eddsa", + section); if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (kcfg, - "taler-exchange-secmod-eddsa", + GNUNET_CONFIGURATION_get_value_time (cfg, + secname, "OVERLAP_DURATION", &overlap_duration)) { + GNUNET_free (secname); GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-eddsa", + secname, "OVERLAP_DURATION"); return GNUNET_SYSERR; } if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (kcfg, - "taler-exchange-secmod-eddsa", + GNUNET_CONFIGURATION_get_value_time (cfg, + secname, "DURATION", &duration)) { + GNUNET_free (secname); GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-eddsa", + secname, "DURATION"); return GNUNET_SYSERR; } - GNUNET_TIME_round_rel (&overlap_duration); - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (kcfg, - "taler-exchange-secmod-eddsa", + GNUNET_CONFIGURATION_get_value_time (cfg, + secname, "LOOKAHEAD_SIGN", &lookahead_sign)) { + GNUNET_free (secname); GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-eddsa", + secname, "LOOKAHEAD_SIGN"); return GNUNET_SYSERR; } - GNUNET_TIME_round_rel (&lookahead_sign); + GNUNET_free (secname); return GNUNET_OK; } @@ -1392,51 +1053,12 @@ static void do_shutdown (void *cls) { (void) cls; - if (NULL != read_task) - { - GNUNET_SCHEDULER_cancel (read_task); - read_task = NULL; - } - if (NULL != unix_sock) - { - GNUNET_break (GNUNET_OK == - GNUNET_NETWORK_socket_close (unix_sock)); - unix_sock = NULL; - } - if (0 != unlink (unixpath)) - { - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, - "unlink", - unixpath); - } - GNUNET_free (unixpath); + TES_listen_stop (); if (NULL != keygen_task) { GNUNET_SCHEDULER_cancel (keygen_task); keygen_task = NULL; } - if (NULL != done_task) - { - GNUNET_SCHEDULER_cancel (done_task); - done_task = NULL; - } - /* shut down worker threads */ - if (NULL != workers) - { - GNUNET_assert (0 == pthread_mutex_lock (&work_lock)); - in_shutdown = true; - GNUNET_assert (0 == pthread_cond_broadcast (&work_cond)); - GNUNET_assert (0 == pthread_mutex_unlock (&work_lock)); - for (unsigned int i = 0; i<num_workers; i++) - GNUNET_assert (0 == pthread_join (workers[i], - NULL)); - } - if (NULL != done_signal) - { - GNUNET_break (GNUNET_OK == - GNUNET_NETWORK_socket_close (done_signal)); - done_signal = NULL; - } } @@ -1454,11 +1076,17 @@ run (void *cls, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { + static struct TES_Callbacks cb = { + .dispatch = eddsa_work_dispatch, + .updater = eddsa_update_client_keys, + .init = eddsa_client_init + }; + char *secname; + (void) cls; (void) args; (void) cfgfile; - kcfg = cfg; - if (now.abs_value_us != now_tmp.abs_value_us) + if (GNUNET_TIME_timestamp_cmp (now, !=, now_tmp)) { /* The user gave "--now", use it! */ now = now_tmp; @@ -1466,183 +1094,71 @@ run (void *cls, else { /* get current time again, we may be timetraveling! */ - now = GNUNET_TIME_absolute_get (); - } - GNUNET_TIME_round_abs (&now); - - { - char *pfn; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (kcfg, - "taler-exchange-secmod-eddsa", - "SM_PRIV_KEY", - &pfn)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-eddsa", - "SM_PRIV_KEY"); - global_ret = 1; - return; - } - if (GNUNET_SYSERR == - GNUNET_CRYPTO_eddsa_key_from_file (pfn, - GNUNET_YES, - &smpriv.eddsa_priv)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-rsa", - "SM_PRIV_KEY", - "Could not use file to persist private key"); - GNUNET_free (pfn); - global_ret = 1; - return; - } - GNUNET_free (pfn); - GNUNET_CRYPTO_eddsa_key_get_public (&smpriv.eddsa_priv, - &smpub.eddsa_pub); + now = GNUNET_TIME_timestamp_get (); } - + GNUNET_asprintf (&secname, + "%s-secmod-eddsa", + section); if (GNUNET_OK != - load_durations ()) + load_durations (cfg)) { - global_ret = 1; + global_ret = EXIT_NOTCONFIGURED; return; } if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (kcfg, - "taler-exchange-secmod-eddsa", + GNUNET_CONFIGURATION_get_value_filename (cfg, + secname, "KEY_DIR", &keydir)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-eddsa", + secname, "KEY_DIR"); - global_ret = 1; + GNUNET_free (secname); + global_ret = EXIT_NOTCONFIGURED; return; } - - /* Create client directory and set permissions. */ - { - char *client_dir; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (kcfg, - "taler-exchange-secmod-eddsa", - "CLIENT_DIR", - &client_dir)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-eddsa", - "CLIENT_DIR"); - global_ret = 3; - return; - } - - if (GNUNET_OK != GNUNET_DISK_directory_create (client_dir)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Can't create client directory (%s)\n", - client_dir); - global_ret = 3; - return; - } - /* Set sticky group bit, so that clients will be writeable by the current service. */ - if (0 != chmod (client_dir, - S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP - | S_ISGID)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Can't set permissions for client directory (%s)\n", - client_dir); - global_ret = 3; - return; - } - - GNUNET_free (client_dir); - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (kcfg, - "taler-exchange-secmod-eddsa", - "UNIXPATH", - &unixpath)) + GNUNET_free (secname); + GNUNET_SCHEDULER_add_shutdown (&do_shutdown, + NULL); { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-eddsa", - "UNIXPATH"); - global_ret = 3; - return; + char *secname; + + GNUNET_asprintf (&secname, + "%s-secmod-eddsa", + section); + global_ret = TES_listen_start (cfg, + secname, + &cb); + GNUNET_free (secname); } - - GNUNET_assert (NULL != unixpath); - unix_sock = TES_open_socket (unixpath); - - if (NULL == unix_sock) - { - GNUNET_free (unixpath); - global_ret = 2; + if (0 != global_ret) return; - } - - GNUNET_SCHEDULER_add_shutdown (&do_shutdown, - NULL); - /* Load keys */ GNUNET_break (GNUNET_OK == GNUNET_DISK_directory_create (keydir)); GNUNET_DISK_directory_scan (keydir, &import_key, NULL); - /* start job to accept incoming requests on 'sock' */ - read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, - unix_sock, - &read_job, - NULL); - /* start job to keep keys up-to-date; MUST be run before the #read_task, + if ( (NULL != keys_head) && + (GNUNET_TIME_absolute_is_future (keys_head->anchor.abs_time)) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Existing anchor is in %s the future. Refusing to start\n", + GNUNET_TIME_relative2s ( + GNUNET_TIME_absolute_get_remaining ( + keys_head->anchor.abs_time), + GNUNET_YES)); + global_ret = EXIT_FAILURE; + GNUNET_SCHEDULER_shutdown (); + return; + } + /* start job to keep keys up-to-date; MUST be run before the #listen_task, hence with priority. */ keygen_task = GNUNET_SCHEDULER_add_with_priority ( GNUNET_SCHEDULER_PRIORITY_URGENT, &update_keys, NULL); - - /* start job to handle completed work */ - { - int fd; - - fd = eventfd (0, - EFD_NONBLOCK | EFD_CLOEXEC); - if (-1 == fd) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, - "eventfd"); - global_ret = 6; - GNUNET_SCHEDULER_shutdown (); - return; - } - done_signal = GNUNET_NETWORK_socket_box_native (fd); - } - done_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, - done_signal, - &handle_done, - NULL); - - /* start crypto workers */ - if (0 == num_workers) - num_workers = sysconf (_SC_NPROCESSORS_CONF); - if (0 == num_workers) - num_workers = 1; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Starting %u crypto workers\n", - num_workers); - workers = GNUNET_new_array (num_workers, - pthread_t); - for (unsigned int i = 0; i<num_workers; i++) - GNUNET_assert (0 == - pthread_create (&workers[i], - NULL, - &sign_worker, - NULL)); } @@ -1658,39 +1174,40 @@ main (int argc, char **argv) { struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_option_string ('s', + "section", + "SECTION", + "name of the configuration section prefix to use, default is 'taler'", + §ion), GNUNET_GETOPT_option_timetravel ('T', "timetravel"), - GNUNET_GETOPT_option_uint ('p', - "parallelism", - "NUM_WORKERS", - "number of worker threads to use", - &num_workers), - GNUNET_GETOPT_option_absolute_time ('t', - "time", - "TIMESTAMP", - "pretend it is a different time for the update", - &now_tmp), + GNUNET_GETOPT_option_timestamp ('t', + "time", + "TIMESTAMP", + "pretend it is a different time for the update", + &now_tmp), GNUNET_GETOPT_OPTION_END }; - int ret; + enum GNUNET_GenericReturnValue ret; /* Restrict permissions for the key files that we create. */ (void) umask (S_IWGRP | S_IROTH | S_IWOTH | S_IXOTH); - + section = GNUNET_strdup ("taler-exchange"); /* force linker to link against libtalerutil; if we do not do this, the linker may "optimize" libtalerutil away and skip #TALER_OS_init(), which we do need */ TALER_OS_init (); - now = now_tmp = GNUNET_TIME_absolute_get (); - ret = GNUNET_PROGRAM_run (argc, argv, + now_tmp = now = GNUNET_TIME_timestamp_get (); + ret = GNUNET_PROGRAM_run (argc, + argv, "taler-exchange-secmod-eddsa", "Handle private EDDSA key operations for a Taler exchange", options, &run, NULL); if (GNUNET_NO == ret) - return 0; + return EXIT_SUCCESS; if (GNUNET_SYSERR == ret) - return 1; + return EXIT_INVALIDARGUMENT; return global_ret; } |