diff options
Diffstat (limited to 'src/util/taler-exchange-secmod-eddsa.c')
-rw-r--r-- | src/util/taler-exchange-secmod-eddsa.c | 1147 |
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'", - §ion), - 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; } |