aboutsummaryrefslogtreecommitdiff
path: root/src/util/taler-exchange-secmod-eddsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/taler-exchange-secmod-eddsa.c')
-rw-r--r--src/util/taler-exchange-secmod-eddsa.c1147
1 files changed, 11 insertions, 1136 deletions
diff --git a/src/util/taler-exchange-secmod-eddsa.c b/src/util/taler-exchange-secmod-eddsa.c
index 6b314d21c..0f560c38a 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-2021 Taler Systems SA
+ Copyright (C) 2014-2024 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
@@ -34,1124 +34,6 @@
*/
#include "platform.h"
#include "taler_util.h"
-#include "taler-exchange-secmod-eddsa.h"
-#include <gcrypt.h>
-#include <pthread.h>
-#include "taler_error_codes.h"
-#include "taler_signatures.h"
-#include "secmod_common.h"
-#include <poll.h>
-
-
-/**
- * One particular key.
- */
-struct Key
-{
-
- /**
- * Kept in a DLL. Sorted by anchor time.
- */
- struct Key *next;
-
- /**
- * Kept in a DLL. Sorted by anchor time.
- */
- struct Key *prev;
-
- /**
- * Name of the file this key is stored under.
- */
- char *filename;
-
- /**
- * The private key.
- */
- struct TALER_ExchangePrivateKeyP exchange_priv;
-
- /**
- * The public key.
- */
- struct TALER_ExchangePublicKeyP exchange_pub;
-
- /**
- * Time at which this key is supposed to become valid.
- */
- 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
- * using this key at this time.
- */
- unsigned int rc;
-
- /**
- * Flag set to true if this key has been purged and the memory
- * must be freed as soon as @e rc hits zero.
- */
- bool purge;
-
-};
-
-
-/**
- * Head of DLL of actual keys, sorted by anchor.
- */
-static struct Key *keys_head;
-
-/**
- * Tail of DLL of actual keys.
- */
-static struct Key *keys_tail;
-
-/**
- * How long can a key be used?
- */
-static struct GNUNET_TIME_Relative duration;
-
-/**
- * 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_Timestamp now;
-
-/**
- * The time for the key update, as passed by the user
- * on the command line.
- */
-static struct GNUNET_TIME_Timestamp now_tmp;
-
-/**
- * Where do we store the keys?
- */
-static char *keydir;
-
-/**
- * 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 *section;
-
-/**
- * How much should coin creation duration overlap
- * with the next key? Basically, the starting time of two
- * keys is always #duration - #overlap_duration apart.
- */
-static struct GNUNET_TIME_Relative overlap_duration;
-
-/**
- * How long into the future do we pre-generate keys?
- */
-static struct GNUNET_TIME_Relative lookahead_sign;
-
-/**
- * Task run to generate new keys.
- */
-static struct GNUNET_SCHEDULER_Task *keygen_task;
-
-/**
- * Lock for the keys queue.
- */
-static pthread_mutex_t keys_lock;
-
-/**
- * Current key generation.
- */
-static uint64_t key_gen;
-
-
-/**
- * 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 enum GNUNET_GenericReturnValue
-notify_client_key_add (struct TES_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_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))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Client %p must have disconnected\n",
- client);
- return GNUNET_SYSERR;
- }
- 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 enum GNUNET_GenericReturnValue
-notify_client_key_del (struct TES_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 (GNUNET_OK !=
- TES_transmit (client->csock,
- &pn.header))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Client %p must have disconnected\n",
- client);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Handle @a client request @a sr to create signature. Create the
- * signature using the respective key and return the result to
- * the client.
- *
- * @param client the client making the request
- * @param sr the request details
- * @return #GNUNET_OK on success
- */
-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;
- 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))
- {
- struct TALER_CRYPTO_EddsaSignFailure sf = {
- .header.size = htons (sizeof (sr)),
- .header.type = htons (TALER_HELPER_EDDSA_MT_RES_SIGN_FAILURE),
- .ec = htonl (TALER_EC_GENERIC_PARAMETER_MALFORMED)
- };
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Signing request failed, request malformed\n");
- return TES_transmit (client->csock,
- &sf.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,
- "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;
- }
- 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 !=
- 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)
- {
- 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 TES_transmit (client->csock,
- &sres.header);
-}
-
-
-/**
- * Initialize key material for key @a key (also on disk).
- *
- * @param[in,out] key to compute key material for
- * @param position where in the DLL will the @a key go
- * @return #GNUNET_OK on success
- */
-static enum GNUNET_GenericReturnValue
-setup_key (struct Key *key,
- struct Key *position)
-{
- struct GNUNET_CRYPTO_EddsaPrivateKey priv;
- struct GNUNET_CRYPTO_EddsaPublicKey pub;
-
- GNUNET_CRYPTO_eddsa_key_create (&priv);
- GNUNET_CRYPTO_eddsa_key_get_public (&priv,
- &pub);
- GNUNET_asprintf (&key->filename,
- "%s/%llu",
- keydir,
- (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,
- &priv,
- sizeof (priv),
- GNUNET_DISK_PERM_USER_READ))
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
- "write",
- key->filename);
- return GNUNET_SYSERR;
- }
- 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;
-}
-
-
-/**
- * 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;
- }
- 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 @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 client the client making the request
- * @param rr the revocation request
- * @return #GNUNET_OK on success
- */
-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;
- 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))
- {
- key = pos;
- break;
- }
- if (NULL == key)
- {
- GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Revocation request ignored, key unknown\n");
- return GNUNET_OK;
- }
- 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);
- nkey->anchor = key->anchor;
- if (GNUNET_OK !=
- setup_key (nkey,
- key))
- {
- GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
- GNUNET_break (0);
- GNUNET_SCHEDULER_shutdown ();
- global_ret = EXIT_FAILURE;
- return GNUNET_SYSERR;
- }
- GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
- TES_wake_clients ();
- return GNUNET_OK;
-}
-
-
-/**
- * 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);
-
- switch (ntohs (hdr->type))
- {
- case TALER_HELPER_EDDSA_MT_REQ_SIGN:
- if (msize < sizeof (struct TALER_CRYPTO_EddsaSignRequest))
- {
- 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;
- }
-}
-
-
-/**
- * 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)
-{
- GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
- for (struct Key *key = keys_head;
- NULL != key;
- key = key->next)
- {
- if (GNUNET_OK !=
- notify_client_key_add (client,
- key))
- {
- GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- }
- client->key_gen = key_gen;
- GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
- {
- 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;
- }
- }
- 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)
- {
- if (key->key_gen <= client->key_gen)
- {
- 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)
- {
- if (GNUNET_OK !=
- notify_client_key_del (client,
- key))
- {
- GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
- return GNUNET_SYSERR;
- }
- }
- else
- {
- if (GNUNET_OK !=
- notify_client_key_add (client,
- key))
- {
- GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
- return GNUNET_SYSERR;
- }
- }
- }
- client->key_gen = key_gen;
- GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
- return GNUNET_OK;
-}
-
-
-/**
- * Create a new key (we do not have enough).
- *
- * @return #GNUNET_OK on success
- */
-static enum GNUNET_GenericReturnValue
-create_key (void)
-{
- struct Key *key;
- struct GNUNET_TIME_Timestamp anchor;
-
- anchor = GNUNET_TIME_timestamp_get ();
- if (NULL != keys_tail)
- {
- 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;
- if (GNUNET_OK !=
- setup_key (key,
- keys_tail))
- {
- GNUNET_break (0);
- GNUNET_free (key);
- GNUNET_SCHEDULER_shutdown ();
- global_ret = EXIT_FAILURE;
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * At what time does the current key set require its next action? Basically,
- * the minimum of the expiration time of the oldest key, and the expiration
- * time of the newest key minus the #lookahead_sign time.
- */
-static struct GNUNET_TIME_Absolute
-key_action_time (void)
-{
- 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 (nxt->anchor.abs_time,
- duration),
- GNUNET_TIME_absolute_subtract (
- GNUNET_TIME_absolute_subtract (
- GNUNET_TIME_absolute_add (keys_tail->anchor.abs_time,
- duration),
- lookahead_sign),
- overlap_duration));
-}
-
-
-/**
- * Create new keys and expire ancient keys.
- *
- * @param cls NULL
- */
-static void
-update_keys (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) ||
- 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;
- }
- }
- 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);
-}
-
-
-/**
- * Parse private key from @a filename in @a buf.
- *
- * @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 enum GNUNET_GenericReturnValue
-parse_key (const char *filename,
- const void *buf,
- size_t buf_size)
-{
- struct GNUNET_CRYPTO_EddsaPrivateKey priv;
- char *anchor_s;
- char dummy;
- unsigned long long anchor_ll;
- struct GNUNET_TIME_Timestamp anchor;
-
- anchor_s = strrchr (filename,
- '/');
- if (NULL == anchor_s)
- {
- /* File in a directory without '/' in the name, this makes no sense. */
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- anchor_s++;
- if (1 != sscanf (anchor_s,
- "%llu%c",
- &anchor_ll,
- &dummy))
- {
- /* Filenames in KEYDIR must ONLY be the anchor time in seconds! */
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Filename `%s' invalid for key file, skipping\n",
- filename);
- return GNUNET_SYSERR;
- }
- 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 GNUNET_SYSERR;
- }
- if (buf_size != sizeof (priv))
- {
- /* Parser failure. */
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "File `%s' is malformed, skipping\n",
- filename);
- return GNUNET_SYSERR;
- }
- GNUNET_memcpy (&priv,
- buf,
- buf_size);
-
- {
- struct GNUNET_CRYPTO_EddsaPublicKey pub;
- struct Key *key;
- struct Key *before;
-
- 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 (GNUNET_TIME_timestamp_cmp (pos->anchor, >, anchor))
- break;
- before = pos;
- }
- GNUNET_CONTAINER_DLL_insert_after (keys_head,
- 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;
-}
-
-
-/**
- * Import a private key from @a filename.
- *
- * @param cls NULL
- * @param filename name of a file in the directory
- */
-static enum GNUNET_GenericReturnValue
-import_key (void *cls,
- const char *filename)
-{
- struct GNUNET_DISK_FileHandle *fh;
- struct GNUNET_DISK_MapHandle *map;
- void *ptr;
- int fd;
- struct stat sbuf;
-
- (void) cls;
- {
- struct stat lsbuf;
-
- if (0 != lstat (filename,
- &lsbuf))
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
- "lstat",
- filename);
- return GNUNET_OK;
- }
- if (! S_ISREG (lsbuf.st_mode))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "File `%s' is not a regular file, which is not allowed for private keys!\n",
- filename);
- return GNUNET_OK;
- }
- }
-
- fd = open (filename,
- O_RDONLY | O_CLOEXEC);
- if (-1 == fd)
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
- "open",
- filename);
- return GNUNET_OK;
- }
- if (0 != fstat (fd,
- &sbuf))
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
- "stat",
- filename);
- GNUNET_break (0 == close (fd));
- return GNUNET_OK;
- }
- if (! S_ISREG (sbuf.st_mode))
- {
- 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)))
- {
- /* permission are NOT tight, try to patch them up! */
- if (0 !=
- fchmod (fd,
- S_IRUSR))
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
- "fchmod",
- filename);
- /* refuse to use key if file has wrong permissions */
- GNUNET_break (0 == close (fd));
- return GNUNET_OK;
- }
- }
- fh = GNUNET_DISK_get_handle_from_int_fd (fd);
- if (NULL == fh)
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
- "open",
- filename);
- GNUNET_break (0 == close (fd));
- return GNUNET_OK;
- }
- if (sbuf.st_size > 2048)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "File `%s' to big to be a private key\n",
- filename);
- GNUNET_DISK_file_close (fh);
- return GNUNET_OK;
- }
- ptr = GNUNET_DISK_file_map (fh,
- &map,
- GNUNET_DISK_MAP_TYPE_READ,
- (size_t) sbuf.st_size);
- if (NULL == ptr)
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
- "mmap",
- filename);
- GNUNET_DISK_file_close (fh);
- return GNUNET_OK;
- }
- (void) parse_key (filename,
- ptr,
- (size_t) sbuf.st_size);
- GNUNET_DISK_file_unmap (map);
- GNUNET_DISK_file_close (fh);
- return GNUNET_OK;
-}
-
-
-/**
- * Load the various duration values from @a kcfg.
- *
- * @param cfg configuration to use
- * @return #GNUNET_OK on success
- */
-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 (cfg,
- secname,
- "OVERLAP_DURATION",
- &overlap_duration))
- {
- GNUNET_free (secname);
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- secname,
- "OVERLAP_DURATION");
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (cfg,
- secname,
- "DURATION",
- &duration))
- {
- GNUNET_free (secname);
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- secname,
- "DURATION");
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_time (cfg,
- secname,
- "LOOKAHEAD_SIGN",
- &lookahead_sign))
- {
- GNUNET_free (secname);
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- secname,
- "LOOKAHEAD_SIGN");
- return GNUNET_SYSERR;
- }
- GNUNET_free (secname);
- return GNUNET_OK;
-}
-
-
-/**
- * Function run on shutdown. Stops the various jobs (nicely).
- *
- * @param cls NULL
- */
-static void
-do_shutdown (void *cls)
-{
- (void) cls;
- TES_listen_stop ();
- if (NULL != keygen_task)
- {
- GNUNET_SCHEDULER_cancel (keygen_task);
- keygen_task = NULL;
- }
-}
-
-
-/**
- * Main function that will be run under the GNUnet scheduler.
- *
- * @param cls closure
- * @param args remaining command-line arguments
- * @param cfgfile name of the configuration file used (for saving, can be NULL!)
- * @param cfg configuration
- */
-static void
-run (void *cls,
- char *const *args,
- 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;
- if (GNUNET_TIME_timestamp_cmp (now, !=, now_tmp))
- {
- /* The user gave "--now", use it! */
- now = now_tmp;
- }
- else
- {
- /* get current time again, we may be timetraveling! */
- now = GNUNET_TIME_timestamp_get ();
- }
- GNUNET_asprintf (&secname,
- "%s-secmod-eddsa",
- section);
- if (GNUNET_OK !=
- load_durations (cfg))
- {
- global_ret = EXIT_NOTCONFIGURED;
- return;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (cfg,
- secname,
- "KEY_DIR",
- &keydir))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- secname,
- "KEY_DIR");
- GNUNET_free (secname);
- global_ret = EXIT_NOTCONFIGURED;
- return;
- }
- GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
- NULL);
- global_ret = TES_listen_start (cfg,
- secname,
- &cb);
- if (0 != global_ret)
- return;
- /* Load keys */
- GNUNET_break (GNUNET_OK ==
- GNUNET_DISK_directory_create (keydir));
- GNUNET_DISK_directory_scan (keydir,
- &import_key,
- NULL);
- 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);
-}
/**
@@ -1165,38 +47,31 @@ int
main (int argc,
char **argv)
{
+ struct TALER_SECMOD_Options opts = {
+ .max_workers = 16,
+ .section = "taler-exchange"
+ };
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_timestamp ('t',
- "time",
- "TIMESTAMP",
- "pretend it is a different time for the update",
- &now_tmp),
+ TALER_SECMOD_OPTIONS (&opts),
GNUNET_GETOPT_OPTION_END
};
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");
- now_tmp = now = GNUNET_TIME_timestamp_get ();
+ opts.global_now_tmp
+ = opts.global_now = GNUNET_TIME_timestamp_get ();
ret = GNUNET_PROGRAM_run (TALER_EXCHANGE_project_data (),
argc,
argv,
"taler-exchange-secmod-eddsa",
"Handle private EDDSA key operations for a Taler exchange",
options,
- &run,
- NULL);
+ &TALER_SECMOD_eddsa_run,
+ &opts);
if (GNUNET_NO == ret)
return EXIT_SUCCESS;
if (GNUNET_SYSERR == ret)
return EXIT_INVALIDARGUMENT;
- return global_ret;
+ return opts.global_ret;
}