summaryrefslogtreecommitdiff
path: root/src/util/taler-exchange-secmod-rsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/taler-exchange-secmod-rsa.c')
-rw-r--r--src/util/taler-exchange-secmod-rsa.c2020
1 files changed, 1028 insertions, 992 deletions
diff --git a/src/util/taler-exchange-secmod-rsa.c b/src/util/taler-exchange-secmod-rsa.c
index 2aabaddc0..c80e2e3c4 100644
--- a/src/util/taler-exchange-secmod-rsa.c
+++ b/src/util/taler-exchange-secmod-rsa.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2020 Taler Systems SA
+ Copyright (C) 2014-2022 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
@@ -20,13 +20,12 @@
*
* Key design points:
* - EVERY thread of the exchange will have its own pair of connections to the
- * crypto helpers. This way, every threat will also have its own /keys state
+ * crypto helpers. This way, every thread will also have its own /keys state
* and avoid the need to synchronize on those.
* - auditor signatures and master signatures are to be kept in the exchange DB,
* 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.
+ * threads for crypto-workers which do the signing in parallel, 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 +36,10 @@
#include "taler-exchange-secmod-rsa.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>
/**
@@ -78,22 +77,32 @@ struct DenominationKey
/**
* The private key of the denomination.
*/
- struct TALER_DenominationPrivateKey denom_priv;
+ struct GNUNET_CRYPTO_RsaPrivateKey *denom_priv;
/**
* The public key of the denomination.
*/
- struct TALER_DenominationPublicKey denom_pub;
+ struct GNUNET_CRYPTO_RsaPublicKey *denom_pub;
+
+ /**
+ * Message to transmit to clients to introduce this public key.
+ */
+ struct TALER_CRYPTO_RsaKeyAvailableNotification *an;
/**
* Hash of this denomination's public key.
*/
- struct GNUNET_HashCode h_denom_pub;
+ struct TALER_RsaPubHashP h_rsa;
/**
* 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
@@ -155,131 +164,155 @@ struct Denomination
/**
- * Actively worked on client request.
+ * A semaphore.
*/
-struct WorkItem;
+struct Semaphore
+{
+ /**
+ * Mutex for the semaphore.
+ */
+ pthread_mutex_t mutex;
+
+ /**
+ * Condition variable for the semaphore.
+ */
+ pthread_cond_t cv;
+
+ /**
+ * Counter of the semaphore.
+ */
+ unsigned int ctr;
+};
/**
- * Information we keep for a client connected to us.
+ * Job in a batch sign request.
*/
-struct Client
-{
+struct BatchJob;
+/**
+ * Handle for a thread that does work in batch signing.
+ */
+struct Worker
+{
/**
* Kept in a DLL.
*/
- struct Client *next;
+ struct Worker *prev;
/**
* Kept in a DLL.
*/
- struct Client *prev;
+ struct Worker *next;
/**
- * Client address.
+ * Job this worker should do next.
*/
- struct sockaddr_un addr;
+ struct BatchJob *job;
/**
- * Number of bytes used in @e addr.
+ * Semaphore to signal the worker that a job is available.
*/
- socklen_t addr_size;
-
-};
-
-
-struct WorkItem
-{
+ struct Semaphore sem;
/**
- * Kept in a DLL.
+ * Handle for this thread.
*/
- struct WorkItem *next;
+ pthread_t pt;
/**
- * Kept in a DLL.
+ * Set to true if the worker should terminate.
*/
- struct WorkItem *prev;
+ bool do_shutdown;
+};
- /**
- * Key to be used for this operation.
- */
- struct DenominationKey *dk;
+/**
+ * Job in a batch sign request.
+ */
+struct BatchJob
+{
/**
- * RSA signature over @e blinded_msg using @e dk. Result of doing the
- * work. Initially NULL.
+ * Request we are working on.
*/
- struct GNUNET_CRYPTO_RsaSignature *rsa_signature;
+ const struct TALER_CRYPTO_SignRequest *sr;
/**
- * Coin_ev value to sign.
+ * Thread doing the work.
*/
- void *blinded_msg;
+ struct Worker *worker;
/**
- * Number of bytes in #blinded_msg.
+ * Result with the signature.
*/
- size_t blinded_msg_size;
+ struct GNUNET_CRYPTO_RsaSignature *rsa_signature;
/**
- * Client address.
+ * Semaphore to signal that the job is finished.
*/
- struct sockaddr_un addr;
+ struct Semaphore sem;
/**
- * Number of bytes used in @e addr.
+ * Computation status.
*/
- socklen_t addr_size;
+ enum TALER_ErrorCode ec;
};
/**
- * Return value from main().
+ * Head of DLL of workers ready for more work.
*/
-static int global_ret;
+static struct Worker *worker_head;
/**
- * Private key of this security module. Used to sign denomination key
- * announcements.
+ * Tail of DLL of workers ready for more work.
*/
-static struct TALER_SecurityModulePrivateKeyP smpriv;
+static struct Worker *worker_tail;
/**
- * Public key of this security module.
+ * Lock for manipulating the worker DLL.
*/
-static struct TALER_SecurityModulePublicKeyP smpub;
+static pthread_mutex_t worker_lock;
/**
- * Number of worker threads to use. Default (0) is to use one per CPU core
- * available.
- * Length of the #workers array.
+ * Total number of workers that were started.
*/
-static unsigned int num_workers;
+static unsigned int workers;
+
+/**
+ * Semaphore used to grab a worker.
+ */
+static struct Semaphore worker_sem;
+
+/**
+ * Return value from main().
+ */
+static int global_ret;
/**
* 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-rsa".
*/
-static char *keydir;
+static char *section;
/**
* How much should coin creation (@e duration_withdraw) duration overlap
@@ -310,529 +343,523 @@ static struct Denomination *denom_tail;
static struct GNUNET_CONTAINER_MultiHashMap *keys;
/**
- * Our listen socket.
+ * Task run to generate new keys.
*/
-static struct GNUNET_NETWORK_Handle *unix_sock;
+static struct GNUNET_SCHEDULER_Task *keygen_task;
/**
- * Path where we are listening.
+ * Lock for the keys queue.
*/
-static char *unixpath;
+static pthread_mutex_t keys_lock;
/**
- * Task run to accept new inbound connections.
+ * Current key generation.
*/
-static struct GNUNET_SCHEDULER_Task *read_task;
+static uint64_t key_gen;
/**
- * Task run to generate new keys.
+ * Number of workers to launch. Note that connections to
+ * exchanges are NOT workers.
*/
-static struct GNUNET_SCHEDULER_Task *keygen_task;
+static unsigned int max_workers = 16;
-/**
- * Head of DLL of clients connected to us.
- */
-static struct Client *clients_head;
/**
- * Tail of DLL of clients connected to us.
+ * Generate the announcement message for @a dk.
+ *
+ * @param[in,out] dk denomination key to generate the announcement for
*/
-static struct Client *clients_tail;
+static void
+generate_response (struct DenominationKey *dk)
+{
+ struct Denomination *denom = dk->denom;
+ size_t nlen = strlen (denom->section) + 1;
+ struct TALER_CRYPTO_RsaKeyAvailableNotification *an;
+ size_t buf_len;
+ void *buf;
+ void *p;
+ size_t tlen;
-/**
- * Head of DLL with pending signing operations.
- */
-static struct WorkItem *work_head;
+ buf_len = GNUNET_CRYPTO_rsa_public_key_encode (dk->denom_pub,
+ &buf);
+ GNUNET_assert (buf_len < UINT16_MAX);
+ GNUNET_assert (nlen < UINT16_MAX);
+ tlen = buf_len + nlen + sizeof (*an);
+ GNUNET_assert (tlen < UINT16_MAX);
+ an = GNUNET_malloc (tlen);
+ an->header.size = htons ((uint16_t) tlen);
+ an->header.type = htons (TALER_HELPER_RSA_MT_AVAIL);
+ an->pub_size = htons ((uint16_t) buf_len);
+ an->section_name_len = htons ((uint16_t) nlen);
+ an->anchor_time = GNUNET_TIME_timestamp_hton (dk->anchor);
+ an->duration_withdraw = GNUNET_TIME_relative_hton (denom->duration_withdraw);
+ TALER_exchange_secmod_rsa_sign (&dk->h_rsa,
+ denom->section,
+ dk->anchor,
+ denom->duration_withdraw,
+ &TES_smpriv,
+ &an->secm_sig);
+ an->secm_pub = TES_smpub;
+ p = (void *) &an[1];
+ GNUNET_memcpy (p,
+ buf,
+ buf_len);
+ GNUNET_free (buf);
+ GNUNET_memcpy (p + buf_len,
+ denom->section,
+ nlen);
+ dk->an = an;
+}
-/**
- * Tail of DLL with pending signing operations.
- */
-static struct WorkItem *work_tail;
/**
- * Lock for the work queue.
+ * Do the actual signing work.
+ *
+ * @param h_rsa key to sign with
+ * @param bm blinded message to sign
+ * @param[out] rsa_signaturep set to the RSA signature
+ * @return #TALER_EC_NONE on success
*/
-static pthread_mutex_t work_lock;
+static enum TALER_ErrorCode
+do_sign (const struct TALER_RsaPubHashP *h_rsa,
+ const struct GNUNET_CRYPTO_RsaBlindedMessage *bm,
+ struct GNUNET_CRYPTO_RsaSignature **rsa_signaturep)
+{
+ struct DenominationKey *dk;
+ struct GNUNET_CRYPTO_RsaSignature *rsa_signature;
+ struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
-/**
- * Condition variable for the semaphore of the work queue.
- */
-static pthread_cond_t work_cond = PTHREAD_COND_INITIALIZER;
+ GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
+ dk = GNUNET_CONTAINER_multihashmap_get (keys,
+ &h_rsa->hash);
+ if (NULL == dk)
+ {
+ GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Signing request failed, denomination key %s unknown\n",
+ GNUNET_h2s (&h_rsa->hash));
+ return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
+ }
+ if (GNUNET_TIME_absolute_is_future (dk->anchor.abs_time))
+ {
+ /* it is too early */
+ GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Signing request failed, denomination key %s is not yet valid\n",
+ GNUNET_h2s (&h_rsa->hash));
+ return TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY;
+ }
-/**
- * Number of items in the work queue. Also used as the semaphore counter.
- */
-static unsigned long long work_counter;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Received request to sign over %u bytes with key %s\n",
+ (unsigned int) bm->blinded_msg_size,
+ GNUNET_h2s (&h_rsa->hash));
+ GNUNET_assert (dk->rc < UINT_MAX);
+ dk->rc++;
+ GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
+ rsa_signature
+ = GNUNET_CRYPTO_rsa_sign_blinded (dk->denom_priv,
+ bm);
+ GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
+ GNUNET_assert (dk->rc > 0);
+ dk->rc--;
+ GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
+ if (NULL == rsa_signature)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Signing request failed, worker failed to produce signature\n");
+ return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
+ }
-/**
- * Head of DLL with completed signing operations.
- */
-static struct WorkItem *done_head;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Sending RSA signature after %s\n",
+ GNUNET_TIME_relative2s (
+ GNUNET_TIME_absolute_get_duration (now),
+ GNUNET_YES));
+ *rsa_signaturep = rsa_signature;
+ return TALER_EC_NONE;
+}
-/**
- * Tail of DLL with completed signing operations.
- */
-static struct WorkItem *done_tail;
/**
- * Lock for the done queue.
+ * Generate error response that signing failed.
+ *
+ * @param client client to send response to
+ * @param ec error code to include
+ * @return #GNUNET_OK on success
*/
-static pthread_mutex_t done_lock;
+static enum GNUNET_GenericReturnValue
+fail_sign (struct TES_Client *client,
+ enum TALER_ErrorCode ec)
+{
+ struct TALER_CRYPTO_SignFailure sf = {
+ .header.size = htons (sizeof (sf)),
+ .header.type = htons (TALER_HELPER_RSA_MT_RES_SIGN_FAILURE),
+ .ec = htonl (ec)
+ };
-/**
- * Task waiting for work to be done.
- */
-static struct GNUNET_SCHEDULER_Task *done_task;
+ return TES_transmit (client->csock,
+ &sf.header);
+}
-/**
- * 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.
+ * Generate signature response.
+ *
+ * @param client client to send response to
+ * @param[in] rsa_signature signature to send, freed by this function
+ * @return #GNUNET_OK on success
*/
-static volatile bool in_shutdown;
+static enum GNUNET_GenericReturnValue
+send_signature (struct TES_Client *client,
+ struct GNUNET_CRYPTO_RsaSignature *rsa_signature)
+{
+ struct TALER_CRYPTO_SignResponse *sr;
+ void *buf;
+ size_t buf_size;
+ size_t tsize;
+ enum GNUNET_GenericReturnValue ret;
-/**
- * Array of #num_workers sign_worker() threads.
- */
-static pthread_t *workers;
+ buf_size = GNUNET_CRYPTO_rsa_signature_encode (rsa_signature,
+ &buf);
+ GNUNET_CRYPTO_rsa_signature_free (rsa_signature);
+ tsize = sizeof (*sr) + buf_size;
+ GNUNET_assert (tsize < UINT16_MAX);
+ sr = GNUNET_malloc (tsize);
+ sr->header.size = htons (tsize);
+ sr->header.type = htons (TALER_HELPER_RSA_MT_RES_SIGNATURE);
+ GNUNET_memcpy (&sr[1],
+ buf,
+ buf_size);
+ GNUNET_free (buf);
+ ret = TES_transmit (client->csock,
+ &sr->header);
+ GNUNET_free (sr);
+ return ret;
+}
/**
- * Main function of a worker thread that signs.
+ * Handle @a client request @a sr to create signature. Create the
+ * signature using the respective key and return the result to
+ * the client.
*
- * @param cls NULL
- * @return NULL
+ * @param client the client making the request
+ * @param sr the request details
+ * @return #GNUNET_OK on success
*/
-static void *
-sign_worker (void *cls)
+static enum GNUNET_GenericReturnValue
+handle_sign_request (struct TES_Client *client,
+ const struct TALER_CRYPTO_SignRequest *sr)
{
- (void) cls;
- GNUNET_assert (0 == pthread_mutex_lock (&work_lock));
- while (! in_shutdown)
- {
- struct WorkItem *wi;
+ struct GNUNET_CRYPTO_RsaBlindedMessage bm = {
+ .blinded_msg = (void *) &sr[1],
+ .blinded_msg_size = ntohs (sr->header.size) - sizeof (*sr)
+ };
+ struct GNUNET_CRYPTO_RsaSignature *rsa_signature;
+ enum TALER_ErrorCode ec;
- 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));
- wi->rsa_signature
- = GNUNET_CRYPTO_rsa_sign_blinded (wi->dk->denom_priv.rsa_private_key,
- wi->blinded_msg,
- wi->blinded_msg_size);
- /* 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));
+ ec = do_sign (&sr->h_rsa,
+ &bm,
+ &rsa_signature);
+ if (TALER_EC_NONE != ec)
+ {
+ return fail_sign (client,
+ ec);
}
- GNUNET_assert (0 ==
- pthread_mutex_unlock (&work_lock));
- return NULL;
+ return send_signature (client,
+ rsa_signature);
}
/**
- * Free @a client, releasing all (remaining) state.
+ * Initialize a semaphore @a sem with a value of @a val.
*
- * @param[in] client data to free
+ * @param[out] sem semaphore to initialize
+ * @param val initial value of the semaphore
*/
static void
-free_client (struct Client *client)
+sem_init (struct Semaphore *sem,
+ unsigned int val)
{
- GNUNET_CONTAINER_DLL_remove (clients_head,
- clients_tail,
- client);
- GNUNET_free (client);
+ GNUNET_assert (0 ==
+ pthread_mutex_init (&sem->mutex,
+ NULL));
+ GNUNET_assert (0 ==
+ pthread_cond_init (&sem->cv,
+ NULL));
+ sem->ctr = val;
}
/**
- * Function run to read incoming requests from a client.
+ * Decrement semaphore, blocks until this is possible.
*
- * @param cls the `struct Client`
+ * @param[in,out] sem semaphore to decrement
*/
static void
-read_job (void *cls);
+sem_down (struct Semaphore *sem)
+{
+ GNUNET_assert (0 == pthread_mutex_lock (&sem->mutex));
+ while (0 == sem->ctr)
+ {
+ pthread_cond_wait (&sem->cv,
+ &sem->mutex);
+ }
+ sem->ctr--;
+ GNUNET_assert (0 == pthread_mutex_unlock (&sem->mutex));
+}
/**
- * Free @a dk. It must already have been removed from #keys and the
- * denomination's DLL.
+ * Increment semaphore, blocks until this is possible.
*
- * @param[in] dk key to free
+ * @param[in,out] sem semaphore to decrement
*/
static void
-free_dk (struct DenominationKey *dk)
+sem_up (struct Semaphore *sem)
{
- GNUNET_free (dk->filename);
- GNUNET_CRYPTO_rsa_private_key_free (dk->denom_priv.rsa_private_key);
- GNUNET_CRYPTO_rsa_public_key_free (dk->denom_pub.rsa_public_key);
- GNUNET_free (dk);
+ GNUNET_assert (0 == pthread_mutex_lock (&sem->mutex));
+ sem->ctr++;
+ GNUNET_assert (0 == pthread_mutex_unlock (&sem->mutex));
+ pthread_cond_signal (&sem->cv);
}
/**
- * 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.
+ * Release resources used by @a sem.
*
- * @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
- * @return #GNUNET_OK on success
+ * @param[in] sem semaphore to release (except the memory itself)
*/
-static int
-transmit (const struct sockaddr_un *addr,
- socklen_t addr_size,
- const struct GNUNET_MessageHeader *hdr)
+static void
+sem_done (struct Semaphore *sem)
{
- for (unsigned int i = 0; i<100; i++)
- {
- 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_strerror (GNUNET_ERROR_TYPE_WARNING,
- "sendto");
- return GNUNET_SYSERR;
+ GNUNET_break (0 == pthread_cond_destroy (&sem->cv));
+ GNUNET_break (0 == pthread_mutex_destroy (&sem->mutex));
}
/**
- * Process completed tasks that are in the #done_head queue, sending
- * the result back to the client (and resuming the client).
+ * Main logic of a worker thread. Grabs work, does it,
+ * grabs more work.
*
- * @param cls NULL
+ * @param cls a `struct Worker *`
+ * @returns cls
*/
-static void
-handle_done (void *cls)
+static void *
+worker (void *cls)
{
- uint64_t data;
- (void) cls;
-
- /* 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)
- {
- struct WorkItem *wi = done_head;
-
- GNUNET_CONTAINER_DLL_remove (done_head,
- done_tail,
- wi);
- GNUNET_assert (0 == pthread_mutex_unlock (&done_lock));
- if (NULL == wi->rsa_signature)
+ struct Worker *w = cls;
+
+ while (true)
+ {
+ GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
+ GNUNET_CONTAINER_DLL_insert (worker_head,
+ worker_tail,
+ w);
+ GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
+ sem_up (&worker_sem);
+ sem_down (&w->sem);
+ if (w->do_shutdown)
+ break;
{
- struct TALER_CRYPTO_SignFailure sf = {
- .header.size = htons (sizeof (sf)),
- .header.type = htons (TALER_HELPER_RSA_MT_RES_SIGN_FAILURE),
- .ec = htonl (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE)
+ struct BatchJob *bj = w->job;
+ const struct TALER_CRYPTO_SignRequest *sr = bj->sr;
+ struct GNUNET_CRYPTO_RsaBlindedMessage bm = {
+ .blinded_msg = (void *) &sr[1],
+ .blinded_msg_size = ntohs (sr->header.size) - sizeof (*sr)
};
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Signing request failed, worker failed to produce signature\n");
- (void) transmit (&wi->addr,
- wi->addr_size,
- &sf.header);
+ bj->ec = do_sign (&sr->h_rsa,
+ &bm,
+ &bj->rsa_signature);
+ sem_up (&bj->sem);
+ w->job = NULL;
}
- else
- {
- struct TALER_CRYPTO_SignResponse *sr;
- void *buf;
- size_t buf_size;
- size_t tsize;
-
- buf_size = GNUNET_CRYPTO_rsa_signature_encode (wi->rsa_signature,
- &buf);
- GNUNET_CRYPTO_rsa_signature_free (wi->rsa_signature);
- wi->rsa_signature = NULL;
- tsize = sizeof (*sr) + buf_size;
- GNUNET_assert (tsize < UINT16_MAX);
- sr = GNUNET_malloc (tsize);
- sr->header.size = htons (tsize);
- sr->header.type = htons (TALER_HELPER_RSA_MT_RES_SIGNATURE);
- memcpy (&sr[1],
- buf,
- buf_size);
- GNUNET_free (buf);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Sending RSA signature\n");
- (void) transmit (&wi->addr,
- wi->addr_size,
- &sr->header);
- GNUNET_free (sr);
- }
- {
- struct DenominationKey *dk = wi->dk;
-
- dk->rc--;
- if ( (0 == dk->rc) &&
- (dk->purge) )
- free_dk (dk);
- }
- GNUNET_free (wi->blinded_msg);
- GNUNET_free (wi);
- GNUNET_assert (0 == pthread_mutex_lock (&done_lock));
}
- GNUNET_assert (0 == pthread_mutex_unlock (&done_lock));
-
+ return w;
}
/**
- * Handle @a client request @a sr to create signature. Create the
- * signature using the respective key and return the result to
- * the client.
+ * Start batch job @a bj to sign @a sr.
*
- * @param addr address of the client making the request
- * @param addr_size number of bytes in @a addr
- * @param sr the request details
+ * @param sr signature request to answer
+ * @param[out] bj job data structure
*/
static void
-handle_sign_request (const struct sockaddr_un *addr,
- socklen_t addr_size,
- const struct TALER_CRYPTO_SignRequest *sr)
+start_job (const struct TALER_CRYPTO_SignRequest *sr,
+ struct BatchJob *bj)
{
- struct DenominationKey *dk;
- struct WorkItem *wi;
- const void *blinded_msg = &sr[1];
- size_t blinded_msg_size = ntohs (sr->header.size) - sizeof (*sr);
+ sem_init (&bj->sem,
+ 0);
+ bj->sr = sr;
+ sem_down (&worker_sem);
+ GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
+ bj->worker = worker_head;
+ GNUNET_CONTAINER_DLL_remove (worker_head,
+ worker_tail,
+ bj->worker);
+ GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
+ bj->worker->job = bj;
+ sem_up (&bj->worker->sem);
+}
- dk = GNUNET_CONTAINER_multihashmap_get (keys,
- &sr->h_denom_pub);
- if (NULL == dk)
- {
- struct TALER_CRYPTO_SignFailure sf = {
- .header.size = htons (sizeof (sr)),
- .header.type = htons (TALER_HELPER_RSA_MT_RES_SIGN_FAILURE),
- .ec = htonl (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN)
- };
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Signing request failed, denomination key %s unknown\n",
- GNUNET_h2s (&sr->h_denom_pub));
- (void) transmit (addr,
- addr_size,
- &sf.header);
- return;
- }
- if (0 !=
- GNUNET_TIME_absolute_get_remaining (dk->anchor).rel_value_us)
+/**
+ * Finish a job @a bj for a @a client.
+ *
+ * @param client who made the request
+ * @param[in,out] bj job to finish
+ */
+static void
+finish_job (struct TES_Client *client,
+ struct BatchJob *bj)
+{
+ sem_down (&bj->sem);
+ sem_done (&bj->sem);
+ if (TALER_EC_NONE != bj->ec)
{
- /* it is too early */
- struct TALER_CRYPTO_SignFailure sf = {
- .header.size = htons (sizeof (sr)),
- .header.type = htons (TALER_HELPER_RSA_MT_RES_SIGN_FAILURE),
- .ec = htonl (TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY)
- };
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Signing request failed, denomination key %s is not yet valid\n",
- GNUNET_h2s (&sr->h_denom_pub));
- (void) transmit (addr,
- addr_size,
- &sf.header);
+ fail_sign (client,
+ bj->ec);
return;
}
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Received request to sign over %u bytes with key %s\n",
- (unsigned int) blinded_msg_size,
- GNUNET_h2s (&sr->h_denom_pub));
- wi = GNUNET_new (struct WorkItem);
- wi->addr = *addr;
- wi->addr_size = addr_size;
- wi->dk = dk;
- dk->rc++;
- wi->blinded_msg = GNUNET_memdup (blinded_msg,
- blinded_msg_size);
- wi->blinded_msg_size = blinded_msg_size;
- 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));
+ GNUNET_assert (NULL != bj->rsa_signature);
+ send_signature (client,
+ bj->rsa_signature);
+ bj->rsa_signature = NULL; /* freed in send_signature */
}
/**
- * Notify @a client about @a dk becoming available.
+ * Handle @a client request @a sr to create a batch of signature. Creates the
+ * signatures using the respective key and return the results to the client.
*
- * @param[in,out] client the client to notify; possible freed if transmission fails
- * @param dk the key to notify @a client about
+ * @param client the client making the request
+ * @param bsr the request details
* @return #GNUNET_OK on success
*/
-static int
-notify_client_dk_add (struct Client *client,
- const struct DenominationKey *dk)
+static enum GNUNET_GenericReturnValue
+handle_batch_sign_request (struct TES_Client *client,
+ const struct TALER_CRYPTO_BatchSignRequest *bsr)
{
- struct Denomination *denom = dk->denom;
- size_t nlen = strlen (denom->section) + 1;
- struct TALER_CRYPTO_RsaKeyAvailableNotification *an;
- size_t buf_len;
- void *buf;
- void *p;
- size_t tlen;
+ uint32_t bs = ntohl (bsr->batch_size);
+ uint16_t size = ntohs (bsr->header.size) - sizeof (*bsr);
+ const void *off = (const void *) &bsr[1];
+ unsigned int idx = 0;
+ struct BatchJob jobs[bs];
+ bool failure = false;
- buf_len = GNUNET_CRYPTO_rsa_public_key_encode (dk->denom_pub.rsa_public_key,
- &buf);
- GNUNET_assert (buf_len < UINT16_MAX);
- GNUNET_assert (nlen < UINT16_MAX);
- tlen = buf_len + nlen + sizeof (*an);
- GNUNET_assert (tlen < UINT16_MAX);
- an = GNUNET_malloc (tlen);
- an->header.size = htons ((uint16_t) tlen);
- an->header.type = htons (TALER_HELPER_RSA_MT_AVAIL);
- an->pub_size = htons ((uint16_t) buf_len);
- an->section_name_len = htons ((uint16_t) nlen);
- an->anchor_time = GNUNET_TIME_absolute_hton (dk->anchor);
- an->duration_withdraw = GNUNET_TIME_relative_hton (denom->duration_withdraw);
- TALER_exchange_secmod_rsa_sign (&dk->h_denom_pub,
- denom->section,
- dk->anchor,
- denom->duration_withdraw,
- &smpriv,
- &an->secm_sig);
- an->secm_pub = smpub;
- p = (void *) &an[1];
- memcpy (p,
- buf,
- buf_len);
- GNUNET_free (buf);
- memcpy (p + buf_len,
- denom->section,
- nlen);
+ if (bs > TALER_MAX_FRESH_COINS)
{
- int ret = GNUNET_OK;
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ while ( (bs > 0) &&
+ (size > sizeof (struct TALER_CRYPTO_SignRequest)) )
+ {
+ const struct TALER_CRYPTO_SignRequest *sr = off;
+ uint16_t s = ntohs (sr->header.size);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Sending RSA denomination key %s (%s)\n",
- GNUNET_h2s (&dk->h_denom_pub),
- denom->section);
- if (GNUNET_OK !=
- transmit (&client->addr,
- client->addr_size,
- &an->header))
+ if (s > size)
{
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Client %s must have disconnected\n",
- client->addr.sun_path);
- free_client (client);
- ret = GNUNET_SYSERR;
+ failure = true;
+ bs = idx;
+ break;
}
- GNUNET_free (an);
- return ret;
+ start_job (sr,
+ &jobs[idx++]);
+ off += s;
+ size -= s;
+ }
+ GNUNET_break_op (0 == size);
+ bs = GNUNET_MIN (bs,
+ idx);
+ for (unsigned int i = 0; i<bs; i++)
+ finish_job (client,
+ &jobs[i]);
+ if (failure)
+ {
+ struct TALER_CRYPTO_SignFailure sf = {
+ .header.size = htons (sizeof (sf)),
+ .header.type = htons (TALER_HELPER_RSA_MT_RES_BATCH_FAILURE),
+ .ec = htonl (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE)
+ };
+
+ GNUNET_break (0);
+ return TES_transmit (client->csock,
+ &sf.header);
}
+ return GNUNET_OK;
}
/**
- * Notify @a client about @a dk being purged.
+ * Start worker thread for batch processing.
*
- * @param[in,out] client the client to notify; possible freed if transmission fails
- * @param dk the key to notify @a client about
* @return #GNUNET_OK on success
*/
-static int
-notify_client_dk_del (struct Client *client,
- const struct DenominationKey *dk)
+static enum GNUNET_GenericReturnValue
+start_worker (void)
{
- struct TALER_CRYPTO_RsaKeyPurgeNotification pn = {
- .header.type = htons (TALER_HELPER_RSA_MT_PURGE),
- .header.size = htons (sizeof (pn)),
- .h_denom_pub = dk->h_denom_pub
- };
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Sending RSA denomination expiration %s\n",
- GNUNET_h2s (&dk->h_denom_pub));
- if (GNUNET_OK !=
- transmit (&client->addr,
- client->addr_size,
- &pn.header))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Client %s must have disconnected\n",
- client->addr.sun_path);
- free_client (client);
+ struct Worker *w;
+
+ w = GNUNET_new (struct Worker);
+ sem_init (&w->sem,
+ 0);
+ if (0 != pthread_create (&w->pt,
+ NULL,
+ &worker,
+ w))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+ "pthread_create");
+ GNUNET_free (w);
return GNUNET_SYSERR;
}
+ workers++;
return GNUNET_OK;
}
/**
+ * Stop all worker threads.
+ */
+static void
+stop_workers (void)
+{
+ while (workers > 0)
+ {
+ struct Worker *w;
+ void *result;
+
+ sem_down (&worker_sem);
+ GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
+ w = worker_head;
+ GNUNET_CONTAINER_DLL_remove (worker_head,
+ worker_tail,
+ w);
+ GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
+ w->do_shutdown = true;
+ sem_up (&w->sem);
+ pthread_join (w->pt,
+ &result);
+ GNUNET_assert (result == w);
+ sem_done (&w->sem);
+ GNUNET_free (w);
+ workers--;
+ }
+}
+
+
+/**
* Initialize key material for denomination key @a dk (also on disk).
*
* @param[in,out] dk denomination key to compute key material for
* @param position where in the DLL will the @a dk go
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
setup_key (struct DenominationKey *dk,
struct DenominationKey *position)
{
@@ -847,7 +874,7 @@ setup_key (struct DenominationKey *dk,
{
GNUNET_break (0);
GNUNET_SCHEDULER_shutdown ();
- global_ret = 40;
+ global_ret = EXIT_FAILURE;
return GNUNET_SYSERR;
}
pub = GNUNET_CRYPTO_rsa_private_key_get_public (priv);
@@ -860,12 +887,12 @@ setup_key (struct DenominationKey *dk,
buf_size = GNUNET_CRYPTO_rsa_private_key_encode (priv,
&buf);
GNUNET_CRYPTO_rsa_public_key_hash (pub,
- &dk->h_denom_pub);
+ &dk->h_rsa.hash);
GNUNET_asprintf (&dk->filename,
"%s/%s/%llu",
keydir,
denom->section,
- (unsigned long long) (dk->anchor.abs_value_us
+ (unsigned long long) (dk->anchor.abs_time.abs_value_us
/ GNUNET_TIME_UNIT_SECONDS.rel_value_us));
if (GNUNET_OK !=
GNUNET_DISK_fn_write (dk->filename,
@@ -883,25 +910,28 @@ setup_key (struct DenominationKey *dk,
}
GNUNET_free (buf);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Setup fresh private key %s at %s in `%s'\n",
- GNUNET_h2s (&dk->h_denom_pub),
- GNUNET_STRINGS_absolute_time_to_string (dk->anchor),
- dk->filename);
- dk->denom_priv.rsa_private_key = priv;
- dk->denom_pub.rsa_public_key = pub;
-
+ "Setup fresh private key %s at %s in `%s' (generation #%llu)\n",
+ GNUNET_h2s (&dk->h_rsa.hash),
+ GNUNET_TIME_timestamp2s (dk->anchor),
+ dk->filename,
+ (unsigned long long) key_gen);
+ dk->denom_priv = priv;
+ dk->denom_pub = pub;
+ dk->key_gen = key_gen;
+ generate_response (dk);
if (GNUNET_OK !=
GNUNET_CONTAINER_multihashmap_put (
keys,
- &dk->h_denom_pub,
+ &dk->h_rsa.hash,
dk,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Duplicate private key created! Terminating.\n");
- GNUNET_CRYPTO_rsa_private_key_free (dk->denom_priv.rsa_private_key);
- GNUNET_CRYPTO_rsa_public_key_free (dk->denom_pub.rsa_public_key);
+ GNUNET_CRYPTO_rsa_private_key_free (dk->denom_priv);
+ GNUNET_CRYPTO_rsa_public_key_free (dk->denom_pub);
GNUNET_free (dk->filename);
+ GNUNET_free (dk->an);
GNUNET_free (dk);
return GNUNET_SYSERR;
}
@@ -909,62 +939,74 @@ setup_key (struct DenominationKey *dk,
denom->keys_tail,
position,
dk);
+ 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_dk_add (client,
- dk))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Failed to notify client about new key, client dropped\n");
- }
- }
- }
- return GNUNET_OK;
+/**
+ * The withdraw period of a key @a dk has expired. Purge it.
+ *
+ * @param[in] dk expired denomination key to purge
+ */
+static void
+purge_key (struct DenominationKey *dk)
+{
+ if (dk->purge)
+ return;
+ if (0 != unlink (dk->filename))
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+ "unlink",
+ dk->filename);
+ GNUNET_free (dk->filename);
+ dk->purge = true;
+ dk->key_gen = key_gen;
}
/**
- * 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
*/
-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_RevokeRequest *rr)
{
struct DenominationKey *dk;
struct DenominationKey *ndk;
struct Denomination *denom;
+ (void) client;
+ GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
dk = GNUNET_CONTAINER_multihashmap_get (keys,
- &rr->h_denom_pub);
+ &rr->h_rsa.hash);
if (NULL == dk)
{
+ GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Revocation request ignored, denomination key %s unknown\n",
- GNUNET_h2s (&rr->h_denom_pub));
- return;
+ GNUNET_h2s (&rr->h_rsa.hash));
+ return GNUNET_OK;
+ }
+ if (dk->purge)
+ {
+ GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Revocation request ignored, denomination key %s already revoked\n",
+ GNUNET_h2s (&rr->h_rsa.hash));
+ return GNUNET_OK;
}
- /* kill existing key, done first to ensure this always happens */
- if (0 != unlink (dk->filename))
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
- "unlink",
- dk->filename);
+ key_gen++;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Revoking key %s, bumping generation to %llu\n",
+ GNUNET_h2s (&rr->h_rsa.hash),
+ (unsigned long long) key_gen);
+ purge_key (dk);
+
/* Setup replacement key */
denom = dk->denom;
ndk = GNUNET_new (struct DenominationKey);
@@ -974,171 +1016,233 @@ handle_revoke_request (const struct sockaddr_un *addr,
setup_key (ndk,
dk))
{
+ 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 */
- dk->purge = true;
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CONTAINER_multihashmap_remove (
- keys,
- &dk->h_denom_pub,
- dk));
- GNUNET_CONTAINER_DLL_remove (denom->keys_head,
- denom->keys_tail,
- dk);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Revocation of denomination key %s complete\n",
- GNUNET_h2s (&rr->h_denom_pub));
- /* 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
+rsa_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_RSA_MT_REQ_SIGN:
+ if (msize <= sizeof (struct TALER_CRYPTO_SignRequest))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return handle_sign_request (
+ client,
+ (const struct TALER_CRYPTO_SignRequest *) hdr);
+ case TALER_HELPER_RSA_MT_REQ_REVOKE:
+ if (msize != sizeof (struct TALER_CRYPTO_RevokeRequest))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return handle_revoke_request (
+ client,
+ (const struct TALER_CRYPTO_RevokeRequest *) hdr);
+ case TALER_HELPER_RSA_MT_REQ_BATCH_SIGN:
+ if (msize <= sizeof (struct TALER_CRYPTO_BatchSignRequest))
{
- nxt = client->next;
- if (GNUNET_OK !=
- notify_client_dk_del (client,
- dk))
- 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_batch_sign_request (
+ client,
+ (const struct TALER_CRYPTO_BatchSignRequest *) hdr);
+ default:
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
}
- if (0 == dk->rc)
- free_dk (dk);
}
-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
+rsa_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_log_strerror (GNUNET_ERROR_TYPE_WARNING,
- "recv");
- return;
+ size_t obs = 0;
+ char *buf;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Initializing new client %p\n",
+ client);
+ GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
+ for (struct Denomination *denom = denom_head;
+ NULL != denom;
+ denom = denom->next)
+ {
+ for (struct DenominationKey *dk = denom->keys_head;
+ NULL != dk;
+ dk = dk->next)
+ {
+ GNUNET_assert (obs + ntohs (dk->an->header.size)
+ > obs);
+ obs += ntohs (dk->an->header.size);
+ }
}
- if (0 == buf_size)
+ buf = GNUNET_malloc (obs);
+ obs = 0;
+ for (struct Denomination *denom = denom_head;
+ NULL != denom;
+ denom = denom->next)
{
- return;
+ for (struct DenominationKey *dk = denom->keys_head;
+ NULL != dk;
+ dk = dk->next)
+ {
+ GNUNET_memcpy (&buf[obs],
+ dk->an,
+ ntohs (dk->an->header.size));
+ GNUNET_assert (obs + ntohs (dk->an->header.size)
+ > obs);
+ obs += ntohs (dk->an->header.size);
+ }
}
- if (buf_size < sizeof (struct GNUNET_MessageHeader))
+ client->key_gen = key_gen;
+ GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
+ if (GNUNET_OK !=
+ TES_transmit_raw (client->csock,
+ obs,
+ buf))
{
- GNUNET_break_op (0);
- return;
+ GNUNET_free (buf);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Client %p must have disconnected\n",
+ client);
+ return GNUNET_SYSERR;
}
- hdr = (const struct GNUNET_MessageHeader *) buf;
- if (ntohs (hdr->size) != buf_size)
+ GNUNET_free (buf);
{
- GNUNET_break_op (0);
- free_client (client);
- return;
+ struct GNUNET_MessageHeader synced = {
+ .type = htons (TALER_HELPER_RSA_SYNCED),
+ .size = htons (sizeof (synced))
+ };
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Sending RSA SYNCED message to %p\n",
+ client);
+ if (GNUNET_OK !=
+ TES_transmit (client->csock,
+ &synced))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
}
- switch (ntohs (hdr->type))
- {
- case TALER_HELPER_RSA_MT_REQ_INIT:
- if (ntohs (hdr->size) != sizeof (struct GNUNET_MessageHeader))
+ 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
+rsa_update_client_keys (struct TES_Client *client)
+{
+ size_t obs = 0;
+ char *buf;
+ enum GNUNET_GenericReturnValue ret;
+
+ GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
+ for (struct Denomination *denom = denom_head;
+ NULL != denom;
+ denom = denom->next)
+ {
+ for (struct DenominationKey *key = denom->keys_head;
+ NULL != key;
+ key = key->next)
{
- GNUNET_break_op (0);
- return;
+ if (key->key_gen <= client->key_gen)
+ continue;
+ if (key->purge)
+ obs += sizeof (struct TALER_CRYPTO_RsaKeyPurgeNotification);
+ else
+ obs += ntohs (key->an->header.size);
}
+ }
+ if (0 == obs)
+ {
+ /* nothing to do */
+ client->key_gen = key_gen;
+ GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
+ return GNUNET_OK;
+ }
+ buf = GNUNET_malloc (obs);
+ obs = 0;
+ for (struct Denomination *denom = denom_head;
+ NULL != denom;
+ denom = denom->next)
+ {
+ for (struct DenominationKey *key = denom->keys_head;
+ NULL != key;
+ key = key->next)
{
- 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 Denomination *denom = denom_head;
- NULL != denom;
- denom = denom->next)
+ if (key->key_gen <= client->key_gen)
+ continue;
+ if (key->purge)
{
- for (struct DenominationKey *dk = denom->keys_head;
- NULL != dk;
- dk = dk->next)
- {
- if (GNUNET_OK !=
- notify_client_dk_add (client,
- dk))
- {
- /* client died, skip the rest */
- client = NULL;
- break;
- }
- }
- if (NULL == client)
- break;
- }
- if (NULL != client)
- {
- struct GNUNET_MessageHeader synced = {
- .type = htons (TALER_HELPER_RSA_SYNCED),
- .size = htons (sizeof (synced))
+ struct TALER_CRYPTO_RsaKeyPurgeNotification pn = {
+ .header.type = htons (TALER_HELPER_RSA_MT_PURGE),
+ .header.size = htons (sizeof (pn)),
+ .h_rsa = key->h_rsa
};
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Sending RSA SYNCED message\n");
- 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_memcpy (&buf[obs],
+ &pn,
+ sizeof (pn));
+ GNUNET_assert (obs + sizeof (pn)
+ > obs);
+ obs += sizeof (pn);
+ }
+ else
+ {
+ GNUNET_memcpy (&buf[obs],
+ key->an,
+ ntohs (key->an->header.size));
+ GNUNET_assert (obs + ntohs (key->an->header.size)
+ > obs);
+ obs += ntohs (key->an->header.size);
}
}
- break;
- case TALER_HELPER_RSA_MT_REQ_SIGN:
- if (ntohs (hdr->size) <= sizeof (struct TALER_CRYPTO_SignRequest))
- {
- GNUNET_break_op (0);
- return;
- }
- handle_sign_request (&addr,
- addr_size,
- (const struct TALER_CRYPTO_SignRequest *) buf);
- break;
- case TALER_HELPER_RSA_MT_REQ_REVOKE:
- if (ntohs (hdr->size) != sizeof (struct TALER_CRYPTO_RevokeRequest))
- {
- GNUNET_break_op (0);
- return;
- }
- handle_revoke_request (&addr,
- addr_size,
- (const struct TALER_CRYPTO_RevokeRequest *) buf);
- break;
- default:
- GNUNET_break_op (0);
- return;
}
+ client->key_gen = key_gen;
+ GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
+ ret = TES_transmit_raw (client->csock,
+ obs,
+ buf);
+ GNUNET_free (buf);
+ return ret;
}
@@ -1149,25 +1253,25 @@ read_job (void *cls)
* @param now current time to use (to get many keys to use the exact same time)
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
create_key (struct Denomination *denom,
- struct GNUNET_TIME_Absolute now)
+ struct GNUNET_TIME_Timestamp now)
{
struct DenominationKey *dk;
- struct GNUNET_TIME_Absolute anchor;
+ struct GNUNET_TIME_Timestamp anchor;
- if (NULL == denom->keys_tail)
- {
- anchor = now;
- }
- else
+ anchor = now;
+ // FIXME: round down to multiple of 'anchor_round' value from configuration
+ if (NULL != denom->keys_tail)
{
- anchor = GNUNET_TIME_absolute_add (denom->keys_tail->anchor,
- GNUNET_TIME_relative_subtract (
- denom->duration_withdraw,
- overlap_duration));
- if (now.abs_value_us > anchor.abs_value_us)
- anchor = now;
+ struct GNUNET_TIME_Absolute abs;
+
+ abs = GNUNET_TIME_absolute_add (denom->keys_tail->anchor.abs_time,
+ GNUNET_TIME_relative_subtract (
+ denom->duration_withdraw,
+ overlap_duration));
+ if (GNUNET_TIME_absolute_cmp (now.abs_time, <, abs))
+ anchor = GNUNET_TIME_absolute_to_timestamp (abs);
}
dk = GNUNET_new (struct DenominationKey);
dk->denom = denom;
@@ -1176,12 +1280,12 @@ create_key (struct Denomination *denom,
setup_key (dk,
denom->keys_tail))
{
+ GNUNET_break (0);
GNUNET_free (dk);
GNUNET_SCHEDULER_shutdown ();
- global_ret = 42;
+ global_ret = EXIT_FAILURE;
return GNUNET_SYSERR;
}
-
return GNUNET_OK;
}
@@ -1197,72 +1301,24 @@ create_key (struct Denomination *denom,
static struct GNUNET_TIME_Absolute
denomination_action_time (const struct Denomination *denom)
{
- if (NULL == denom->keys_head)
+ struct DenominationKey *head = denom->keys_head;
+ struct DenominationKey *tail = denom->keys_tail;
+ struct GNUNET_TIME_Absolute tt;
+
+ if (NULL == head)
return GNUNET_TIME_UNIT_ZERO_ABS;
+ tt = GNUNET_TIME_absolute_subtract (
+ GNUNET_TIME_absolute_subtract (
+ GNUNET_TIME_absolute_add (tail->anchor.abs_time,
+ denom->duration_withdraw),
+ lookahead_sign),
+ overlap_duration);
+ if (head->rc > 0)
+ return tt; /* head expiration does not count due to rc > 0 */
return GNUNET_TIME_absolute_min (
- GNUNET_TIME_absolute_add (denom->keys_head->anchor,
+ GNUNET_TIME_absolute_add (head->anchor.abs_time,
denom->duration_withdraw),
- GNUNET_TIME_absolute_subtract (
- GNUNET_TIME_absolute_subtract (
- GNUNET_TIME_absolute_add (denom->keys_tail->anchor,
- denom->duration_withdraw),
- lookahead_sign),
- overlap_duration));
-}
-
-
-/**
- * The withdraw period of a key @a dk has expired. Purge it.
- *
- * @param[in] dk expired denomination key to purge and free
- */
-static void
-purge_key (struct DenominationKey *dk)
-{
- struct Denomination *denom = dk->denom;
- struct Client *nxt;
-
- for (struct Client *client = clients_head;
- NULL != client;
- client = nxt)
- {
- nxt = client->next;
- if (GNUNET_OK !=
- notify_client_dk_del (client,
- dk))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Failed to notify client about purged key, client dropped\n");
- }
- }
- GNUNET_CONTAINER_DLL_remove (denom->keys_head,
- denom->keys_tail,
- dk);
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CONTAINER_multihashmap_remove (keys,
- &dk->h_denom_pub,
- dk));
- if (0 != unlink (dk->filename))
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
- "unlink",
- dk->filename);
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Purged expired private key `%s'\n",
- dk->filename);
- }
- GNUNET_free (dk->filename);
- if (0 != dk->rc)
- {
- /* delay until all signing threads are done with this key */
- dk->purge = true;
- return;
- }
- GNUNET_CRYPTO_rsa_private_key_free (dk->denom_priv.rsa_private_key);
- GNUNET_free (dk);
+ tt);
}
@@ -1273,37 +1329,83 @@ purge_key (struct DenominationKey *dk)
*
* @param[in,out] denom denomination to update material for
* @param now current time to use (to get many keys to use the exact same time)
+ * @param[in,out] wake set to true if we should wake the clients
+ * @return #GNUNET_OK on success
*/
-static void
+static enum GNUNET_GenericReturnValue
update_keys (struct Denomination *denom,
- struct GNUNET_TIME_Absolute now)
+ struct GNUNET_TIME_Timestamp now,
+ bool *wake)
{
/* create new denomination keys */
+ if (NULL != denom->keys_tail)
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Updating keys of denomination `%s', last key %s valid for another %s\n",
+ denom->section,
+ GNUNET_h2s (&denom->keys_tail->h_rsa.hash),
+ GNUNET_TIME_relative2s (
+ GNUNET_TIME_absolute_get_remaining (
+ GNUNET_TIME_absolute_subtract (
+ GNUNET_TIME_absolute_add (
+ denom->keys_tail->anchor.abs_time,
+ denom->duration_withdraw),
+ overlap_duration)),
+ GNUNET_YES));
while ( (NULL == denom->keys_tail) ||
- (0 ==
- GNUNET_TIME_absolute_get_remaining (
- GNUNET_TIME_absolute_subtract (
- GNUNET_TIME_absolute_subtract (
- GNUNET_TIME_absolute_add (denom->keys_tail->anchor,
- denom->duration_withdraw),
- lookahead_sign),
- overlap_duration)).rel_value_us) )
+ GNUNET_TIME_absolute_is_past (
+ GNUNET_TIME_absolute_subtract (
+ GNUNET_TIME_absolute_subtract (
+ GNUNET_TIME_absolute_add (denom->keys_tail->anchor.abs_time,
+ denom->duration_withdraw),
+ lookahead_sign),
+ overlap_duration)) )
+ {
+ if (! *wake)
+ {
+ key_gen++;
+ *wake = true;
+ }
if (GNUNET_OK !=
create_key (denom,
now))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to create keys for `%s'\n",
- denom->section);
- return;
+ GNUNET_break (0);
+ global_ret = EXIT_FAILURE;
+ GNUNET_SCHEDULER_shutdown ();
+ return GNUNET_SYSERR;
}
+ }
/* remove expired denomination keys */
while ( (NULL != denom->keys_head) &&
- (0 ==
- GNUNET_TIME_absolute_get_remaining
- (GNUNET_TIME_absolute_add (denom->keys_head->anchor,
- denom->duration_withdraw)).rel_value_us) )
- purge_key (denom->keys_head);
+ GNUNET_TIME_absolute_is_past
+ (GNUNET_TIME_absolute_add (denom->keys_head->anchor.abs_time,
+ denom->duration_withdraw)) )
+ {
+ struct DenominationKey *key = denom->keys_head;
+ struct DenominationKey *nxt = key->next;
+
+ if (0 != key->rc)
+ break; /* later */
+ GNUNET_CONTAINER_DLL_remove (denom->keys_head,
+ denom->keys_tail,
+ key);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_remove (
+ keys,
+ &key->h_rsa.hash,
+ key));
+ if ( (! key->purge) &&
+ (0 != unlink (key->filename)) )
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+ "unlink",
+ key->filename);
+ GNUNET_free (key->filename);
+ GNUNET_CRYPTO_rsa_private_key_free (key->denom_priv);
+ GNUNET_CRYPTO_rsa_public_key_free (key->denom_pub);
+ GNUNET_free (key->an);
+ GNUNET_free (key);
+ key = nxt;
+ }
/* Update position of 'denom' in #denom_head DLL: sort by action time */
{
@@ -1319,16 +1421,16 @@ update_keys (struct Denomination *denom,
NULL != pos;
pos = pos->next)
{
- if (denomination_action_time (pos).abs_value_us >= at.abs_value_us)
+ if (GNUNET_TIME_absolute_cmp (denomination_action_time (pos), >=, at))
break;
before = pos;
}
-
GNUNET_CONTAINER_DLL_insert_after (denom_head,
denom_tail,
before,
denom);
}
+ return GNUNET_OK;
}
@@ -1342,16 +1444,29 @@ update_denominations (void *cls)
{
struct Denomination *denom;
struct GNUNET_TIME_Absolute now;
+ struct GNUNET_TIME_Timestamp t;
+ bool wake = false;
(void) cls;
keygen_task = NULL;
now = GNUNET_TIME_absolute_get ();
- (void) GNUNET_TIME_round_abs (&now);
+ t = GNUNET_TIME_absolute_to_timestamp (now);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Updating denominations ...\n");
+ GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
do {
denom = denom_head;
- update_keys (denom,
- now);
+ if (GNUNET_OK !=
+ update_keys (denom,
+ t,
+ &wake))
+ return;
} while (denom != denom_head);
+ GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Updating denominations finished ...\n");
+ if (wake)
+ TES_wake_clients ();
keygen_task = GNUNET_SCHEDULER_add_at (denomination_action_time (denom),
&update_denominations,
NULL);
@@ -1376,7 +1491,7 @@ parse_key (struct Denomination *denom,
char *anchor_s;
char dummy;
unsigned long long anchor_ll;
- struct GNUNET_TIME_Absolute anchor;
+ struct GNUNET_TIME_Timestamp anchor;
anchor_s = strrchr (filename,
'/');
@@ -1398,8 +1513,10 @@ parse_key (struct Denomination *denom,
filename);
return;
}
- 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,
@@ -1431,26 +1548,28 @@ parse_key (struct Denomination *denom,
return;
}
dk = GNUNET_new (struct DenominationKey);
- dk->denom_priv.rsa_private_key = priv;
+ dk->denom_priv = priv;
dk->denom = denom;
dk->anchor = anchor;
dk->filename = GNUNET_strdup (filename);
GNUNET_CRYPTO_rsa_public_key_hash (pub,
- &dk->h_denom_pub);
- dk->denom_pub.rsa_public_key = pub;
+ &dk->h_rsa.hash);
+ dk->denom_pub = pub;
+ generate_response (dk);
if (GNUNET_OK !=
GNUNET_CONTAINER_multihashmap_put (
keys,
- &dk->h_denom_pub,
+ &dk->h_rsa.hash,
dk,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Duplicate private key %s detected in file `%s'. Skipping.\n",
- GNUNET_h2s (&dk->h_denom_pub),
+ GNUNET_h2s (&dk->h_rsa.hash),
filename);
GNUNET_CRYPTO_rsa_private_key_free (priv);
GNUNET_CRYPTO_rsa_public_key_free (pub);
+ GNUNET_free (dk->an);
GNUNET_free (dk);
return;
}
@@ -1459,7 +1578,9 @@ parse_key (struct Denomination *denom,
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;
}
@@ -1469,7 +1590,7 @@ parse_key (struct Denomination *denom,
dk);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Imported key %s from `%s'\n",
- GNUNET_h2s (&dk->h_denom_pub),
+ GNUNET_h2s (&dk->h_rsa.hash),
filename);
}
}
@@ -1481,8 +1602,9 @@ parse_key (struct Denomination *denom,
*
* @param[in,out] cls a `struct Denomiantion`
* @param filename name of a file in the directory
+ * @return #GNUNET_OK (always, continue to iterate)
*/
-static int
+static enum GNUNET_GenericReturnValue
import_key (void *cls,
const char *filename)
{
@@ -1514,7 +1636,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,
@@ -1528,6 +1650,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))
@@ -1535,6 +1658,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)))
@@ -1561,10 +1685,10 @@ import_key (void *cls,
GNUNET_break (0 == close (fd));
return GNUNET_OK;
}
- if (sbuf.st_size > 2048)
+ if (sbuf.st_size > 16 * 1024)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "File `%s' to big to be a private key\n",
+ "File `%s' too big to be a private key\n",
filename);
GNUNET_DISK_file_close (fh);
return GNUNET_OK;
@@ -1595,18 +1719,24 @@ import_key (void *cls,
* Parse configuration for denomination type parameters. Also determines
* our anchor by looking at the existing denominations of the same type.
*
+ * @param cfg configuration to use
* @param ct section in the configuration file giving the denomination type parameters
* @param[out] denom set to the denomination parameters from the configuration
* @return #GNUNET_OK on success, #GNUNET_SYSERR if the configuration is invalid
*/
-static int
-parse_denomination_cfg (const char *ct,
+static enum GNUNET_GenericReturnValue
+parse_denomination_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *ct,
struct Denomination *denom)
{
unsigned long long rsa_keysize;
+ char *secname;
+ GNUNET_asprintf (&secname,
+ "%s-secmod-rsa",
+ section);
if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (kcfg,
+ GNUNET_CONFIGURATION_get_value_time (cfg,
ct,
"DURATION_WITHDRAW",
&denom->duration_withdraw))
@@ -1614,20 +1744,22 @@ parse_denomination_cfg (const char *ct,
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
ct,
"DURATION_WITHDRAW");
+ GNUNET_free (secname);
return GNUNET_SYSERR;
}
- GNUNET_TIME_round_rel (&denom->duration_withdraw);
- if (overlap_duration.rel_value_us >=
- denom->duration_withdraw.rel_value_us)
+ if (GNUNET_TIME_relative_cmp (overlap_duration,
+ >=,
+ denom->duration_withdraw))
{
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- "taler-exchange-secmod-rsa",
+ section,
"OVERLAP_DURATION",
"Value given must be smaller than value for DURATION_WITHDRAW!");
+ GNUNET_free (secname);
return GNUNET_SYSERR;
}
if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (kcfg,
+ GNUNET_CONFIGURATION_get_value_number (cfg,
ct,
"RSA_KEYSIZE",
&rsa_keysize))
@@ -1635,6 +1767,7 @@ parse_denomination_cfg (const char *ct,
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
ct,
"RSA_KEYSIZE");
+ GNUNET_free (secname);
return GNUNET_SYSERR;
}
if ( (rsa_keysize > 4 * 2048) ||
@@ -1644,8 +1777,10 @@ parse_denomination_cfg (const char *ct,
ct,
"RSA_KEYSIZE",
"Given RSA keysize outside of permitted range [1024,8192]\n");
+ GNUNET_free (secname);
return GNUNET_SYSERR;
}
+ GNUNET_free (secname);
denom->rsa_keysize = (unsigned int) rsa_keysize;
denom->section = GNUNET_strdup (ct);
return GNUNET_OK;
@@ -1657,15 +1792,21 @@ parse_denomination_cfg (const char *ct,
*/
struct LoadContext
{
+
+ /**
+ * Configuration to use.
+ */
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
/**
* Current time to use.
*/
- struct GNUNET_TIME_Absolute now;
+ struct GNUNET_TIME_Timestamp t;
/**
* Status, to be set to #GNUNET_SYSERR on failure
*/
- int ret;
+ enum GNUNET_GenericReturnValue ret;
};
@@ -1682,6 +1823,8 @@ load_denominations (void *cls,
{
struct LoadContext *ctx = cls;
struct Denomination *denom;
+ bool wake = true;
+ char *cipher;
if ( (0 != strncasecmp (denomination_alias,
"coin_",
@@ -1690,9 +1833,27 @@ load_denominations (void *cls,
"coin-",
strlen ("coin-"))) )
return; /* not a denomination type definition */
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (ctx->cfg,
+ denomination_alias,
+ "CIPHER",
+ &cipher))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ denomination_alias,
+ "CIPHER");
+ return;
+ }
+ if (0 != strcmp (cipher, "RSA"))
+ {
+ GNUNET_free (cipher);
+ return; /* Ignore denominations of other types than CS */
+ }
+ GNUNET_free (cipher);
denom = GNUNET_new (struct Denomination);
if (GNUNET_OK !=
- parse_denomination_cfg (denomination_alias,
+ parse_denomination_cfg (ctx->cfg,
+ denomination_alias,
denom))
{
ctx->ret = GNUNET_SYSERR;
@@ -1720,43 +1881,50 @@ load_denominations (void *cls,
denom_tail,
denom);
update_keys (denom,
- ctx->now);
+ ctx->t,
+ &wake);
}
/**
- * Load the various duration values from #kcfg.
+ * Load the various duration values from @a cfg
*
+ * @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-rsa",
+ section);
if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (kcfg,
- "taler-exchange-secmod-rsa",
+ GNUNET_CONFIGURATION_get_value_time (cfg,
+ secname,
"OVERLAP_DURATION",
&overlap_duration))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "taler-exchange-secmod-rsa",
+ secname,
"OVERLAP_DURATION");
+ GNUNET_free (secname);
return GNUNET_SYSERR;
}
- GNUNET_TIME_round_rel (&overlap_duration);
-
if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (kcfg,
- "taler-exchange-secmod-rsa",
+ GNUNET_CONFIGURATION_get_value_time (cfg,
+ secname,
"LOOKAHEAD_SIGN",
&lookahead_sign))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "taler-exchange-secmod-rsa",
+ secname,
"LOOKAHEAD_SIGN");
+ GNUNET_free (secname);
return GNUNET_SYSERR;
}
- GNUNET_TIME_round_rel (&lookahead_sign);
+ GNUNET_free (secname);
return GNUNET_OK;
}
@@ -1770,51 +1938,14 @@ 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;
- }
+ stop_workers ();
+ sem_done (&worker_sem);
}
@@ -1832,11 +1963,17 @@ run (void *cls,
const char *cfgfile,
const struct GNUNET_CONFIGURATION_Handle *cfg)
{
+ static struct TES_Callbacks cb = {
+ .dispatch = rsa_work_dispatch,
+ .updater = rsa_update_client_keys,
+ .init = rsa_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;
@@ -1844,206 +1981,100 @@ 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-rsa",
- "SM_PRIV_KEY",
- &pfn))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "taler-exchange-secmod-rsa",
- "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);
- }
-
- if (GNUNET_OK !=
- load_durations ())
- {
- global_ret = 1;
- return;
+ now = GNUNET_TIME_timestamp_get ();
}
+ GNUNET_asprintf (&secname,
+ "%s-secmod-rsa",
+ section);
if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (kcfg,
- "taler-exchange-secmod-rsa",
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ secname,
"KEY_DIR",
&keydir))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "taler-exchange-secmod-rsa",
+ 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-rsa",
- "CLIENT_DIR",
- &client_dir))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "taler-exchange-secmod-rsa",
- "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);
- }
-
+ GNUNET_free (secname);
if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (kcfg,
- "taler-exchange-secmod-rsa",
- "UNIXPATH",
- &unixpath))
+ load_durations (cfg))
{
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "taler-exchange-secmod-rsa",
- "UNIXPATH");
- global_ret = 3;
+ global_ret = EXIT_NOTCONFIGURED;
return;
}
-
- GNUNET_assert (NULL != unixpath);
- unix_sock = TES_open_socket (unixpath);
-
- if (NULL == unix_sock)
{
- GNUNET_free (unixpath);
- global_ret = 2;
- return;
- }
+ char *secname;
+ GNUNET_asprintf (&secname,
+ "%s-secmod-rsa",
+ section);
+ global_ret = TES_listen_start (cfg,
+ secname,
+ &cb);
+ GNUNET_free (secname);
+ }
+ if (0 != global_ret)
+ return;
+ sem_init (&worker_sem,
+ 0);
GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
NULL);
+ if (0 == max_workers)
+ {
+ long lret;
+
+ lret = sysconf (_SC_NPROCESSORS_CONF);
+ if (lret <= 0)
+ lret = 1;
+ max_workers = (unsigned int) lret;
+ }
+ for (unsigned int i = 0; i<max_workers; i++)
+ if (GNUNET_OK !=
+ start_worker ())
+ {
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
/* Load denominations */
keys = GNUNET_CONTAINER_multihashmap_create (65536,
GNUNET_YES);
{
struct LoadContext lc = {
+ .cfg = cfg,
.ret = GNUNET_OK,
- .now = GNUNET_TIME_absolute_get ()
+ .t = now
};
- (void) GNUNET_TIME_round_abs (&lc.now);
- GNUNET_CONFIGURATION_iterate_sections (kcfg,
+ GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
+ GNUNET_CONFIGURATION_iterate_sections (cfg,
&load_denominations,
&lc);
+ GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
if (GNUNET_OK != lc.ret)
{
- global_ret = 4;
+ global_ret = EXIT_FAILURE;
GNUNET_SCHEDULER_shutdown ();
return;
}
}
if (NULL == denom_head)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "No denominations configured\n");
- global_ret = 5;
- GNUNET_SCHEDULER_shutdown ();
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "No RSA denominations configured\n");
+ TES_wake_clients ();
return;
}
-
- /* 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,
+ /* 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_denominations,
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));
}
@@ -2059,30 +2090,35 @@ 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'",
+ &section),
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_uint ('w',
+ "workers",
+ "COUNT",
+ "use COUNT workers for parallel processing of batch requests",
+ &max_workers),
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 ();
+ now_tmp = now = GNUNET_TIME_timestamp_get ();
ret = GNUNET_PROGRAM_run (argc, argv,
"taler-exchange-secmod-rsa",
"Handle private RSA key operations for a Taler exchange",
@@ -2090,8 +2126,8 @@ main (int argc,
&run,
NULL);
if (GNUNET_NO == ret)
- return 0;
+ return EXIT_SUCCESS;
if (GNUNET_SYSERR == ret)
- return 1;
+ return EXIT_INVALIDARGUMENT;
return global_ret;
}