Compare commits

...

10 Commits

Author SHA1 Message Date
5104b43902
Merge branch 'master' into age_restriction 2021-12-03 14:26:15 +01:00
Christian Grothoff
dfe245814c
reduce lock contention in RSA secmod 2021-12-02 17:25:57 +01:00
Christian Grothoff
ae866fc45d
-fix FTBFS 2021-12-02 14:35:45 +01:00
Christian Grothoff
3a5eb9285c
-fix FTBFS 2021-12-02 14:33:22 +01:00
Christian Grothoff
5ad1d0d3dd
-add disable invariants 2021-12-02 14:32:05 +01:00
Christian Grothoff
b3e4159c2e
more perf debug messages 2021-12-02 14:11:14 +01:00
Christian Grothoff
bbdc7649f7
add -I command line option 2021-12-02 13:31:20 +01:00
Christian Grothoff
5a7dd00125
improve suicide logic 2021-12-02 08:02:20 +01:00
Christian Grothoff
e8fc5d8d5c
-fix command to avoid timing-dependent assertion failure 2021-12-02 06:41:49 +01:00
Christian Grothoff
170402203a
make check case-insensitive 2021-12-01 17:56:47 +01:00
20 changed files with 437 additions and 162 deletions

View File

@ -5,7 +5,8 @@ PartOf=taler-exchange.target
[Service]
User=taler-exchange-aggregator
Type=simple
Restart=on-failure
Restart=always
RestartSec=100ms
ExecStart=/usr/bin/taler-exchange-aggregator -c /etc/taler/taler.conf
StandardOutput=journal
StandardError=journal

View File

@ -5,7 +5,8 @@ PartOf=taler-exchange.target
[Service]
User=taler-exchange-closer
Type=simple
Restart=on-failure
Restart=always
RestartSec=100ms
ExecStart=/usr/bin/taler-exchange-closer -c /etc/taler/taler.conf
StandardOutput=journal
StandardError=journal

View File

@ -8,7 +8,11 @@ PartOf=taler-exchange.target
[Service]
User=taler-exchange-httpd
Type=simple
Restart=on-failure
# Depending on the configuration, the service suicides and then
# needs to be restarted.
Restart=always
# Do not dally on restarts.
RestartSec=1ms
ExecStart=/usr/bin/taler-exchange-httpd -c /etc/taler/taler.conf
StandardOutput=journal
StandardError=journal

View File

@ -0,0 +1,26 @@
% This is a systemd service template.
[Unit]
Description=GNU Taler payment system exchange REST API at %I
AssertPathExists=/run/taler/exchange-httpd
Requires=taler-exchange-httpd@%i.socket taler-exchange-secmod-rsa.service taler-exchange-secmod-eddsa.service
After=postgres.service network.target taler-exchange-secmod-rsa.service taler-exchange-secmod-eddsa.service
PartOf=taler-exchange.target
[Service]
User=taler-exchange-httpd
Type=simple
# Depending on the configuration, the service suicides and then
# needs to be restarted.
Restart=always
# Do not dally on restarts.
RestartSec=1ms
EnvironmentFile=/etc/environment
ExecStart=/usr/bin/taler-exchange-httpd -c /etc/taler/taler.conf
StandardOutput=journal
StandardError=journal
PrivateTmp=no
PrivateDevices=yes
ProtectSystem=full
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,14 @@
[Unit]
Description=Taler Exchange Socket at %I
PartOf=taler-exchange-httpd@%i.service
[Socket]
ListenStream=80
Accept=no
Service=taler-exchange-httpd@%i.service
SocketUser=taler-exchange-httpd
SocketGroup=www-data
SocketMode=0660
[Install]
WantedBy=sockets.target

View File

@ -6,7 +6,8 @@ PartOf=taler-exchange.target
[Service]
User=taler-exchange-secmod-eddsa
Type=simple
Restart=on-failure
Restart=always
RestartSec=100ms
ExecStart=/usr/bin/taler-exchange-secmod-eddsa -c /etc/taler/taler.conf
StandardOutput=journal
StandardError=journal

View File

@ -6,7 +6,8 @@ PartOf=taler-exchange.target
[Service]
User=taler-exchange-secmod-rsa
Type=simple
Restart=on-failure
Restart=always
RestartSec=100ms
ExecStart=/usr/bin/taler-exchange-secmod-rsa -c /etc/taler/taler.conf
StandardOutput=journal
StandardError=journal

View File

@ -6,7 +6,8 @@ PartOf=taler-exchange.target
[Service]
User=taler-exchange-wire
Type=simple
Restart=on-failure
Restart=always
RestartSec=100ms
ExecStart=/usr/bin/taler-exchange-transfer -c /etc/taler/taler.conf
StandardOutput=journal
StandardError=journal

View File

@ -6,7 +6,8 @@ PartOf=taler-exchange.target
[Service]
User=taler-exchange-wire
Type=simple
Restart=on-failure
Restart=always
RestartSec=100ms
ExecStart=/usr/bin/taler-exchange-wirewatch -c /etc/taler/taler.conf
StandardOutput=journal
StandardError=journal

View File

@ -0,0 +1,16 @@
[Unit]
Description=GNU Taler payment system exchange wirewatch service
After=network.target
PartOf=taler-exchange.target
[Service]
User=taler-exchange-wire
Type=simple
Restart=always
RestartSec=100ms
ExecStart=/usr/bin/taler-exchange-wirewatch -c /etc/taler/taler.conf
StandardOutput=journal
StandardError=journal
PrivateTmp=yes
PrivateDevices=yes
ProtectSystem=full

View File

@ -40,6 +40,9 @@ PORT = 8081
# transfers to enable tracking.
BASE_URL = http://localhost:8081/
# Maximum number of requests this process should handle before
# committing suicide.
# MAX_REQUESTS =
# How long should the aggregator sleep if it has nothing to do?
AGGREGATOR_IDLE_SLEEP_INTERVAL = 60 s

View File

@ -76,6 +76,11 @@ static int allow_address_reuse;
*/
const struct GNUNET_CONFIGURATION_Handle *TEH_cfg;
/**
* Handle to the HTTP server.
*/
static struct MHD_Daemon *mhd;
/**
* Our KYC configuration.
*/
@ -122,6 +127,17 @@ static unsigned int connection_timeout = 30;
*/
static int connection_close;
/**
* -I command-line flag given?
*/
int TEH_check_invariants_flag;
/**
* True if we should commit suicide once all active
* connections are finished.
*/
bool TEH_suicide;
/**
* Value to return from main()
*/
@ -137,6 +153,11 @@ static uint16_t serve_port;
*/
static unsigned long long req_count;
/**
* Counter for the number of open connections.
*/
static unsigned long long active_connections;
/**
* Limit for the number of requests this HTTP may process before restarting.
* (This was added as one way of dealing with unavoidable memory fragmentation
@ -262,6 +283,45 @@ handle_post_coins (struct TEH_RequestContext *rc,
}
/**
* Increments our request counter and checks if this
* process should commit suicide.
*/
static void
check_suicide (void)
{
int fd;
pid_t chld;
unsigned long long cnt;
cnt = req_count++;
if (req_max != cnt)
return;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Restarting exchange service after %llu requests\n",
cnt);
/* Stop accepting new connections */
fd = MHD_quiesce_daemon (mhd);
GNUNET_break (0 == close (fd));
/* Continue handling existing connections in child,
so that this process can die and be replaced by
systemd with a fresh one */
chld = fork ();
if (-1 == chld)
{
GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
"fork");
_exit (1);
}
if (0 != chld)
{
/* We are the parent, instant-suicide! */
_exit (0);
}
TEH_suicide = true;
}
/**
* Function called whenever MHD is done with a request. If the
* request was a POST, we may have stored a `struct Buffer *` in the
@ -290,6 +350,7 @@ handle_mhd_completion_callback (void *cls,
return;
GNUNET_async_scope_enter (&rc->async_scope_id,
&old_scope);
check_suicide ();
TEH_check_invariants ();
if (NULL != rc->rh_cleaner)
rc->rh_cleaner (rc);
@ -1642,8 +1703,19 @@ connection_done (void *cls,
(void) cls;
(void) connection;
(void) socket_context;
unsigned long long cnt;
switch (toe)
{
case MHD_CONNECTION_NOTIFY_STARTED:
active_connections++;
break;
case MHD_CONNECTION_NOTIFY_CLOSED:
active_connections--;
if (TEH_suicide &&
(0 == active_connections) )
GNUNET_SCHEDULER_shutdown ();
break;
}
#if HAVE_DEVELOPER
/* We only act if the connection is closed. */
if (MHD_CONNECTION_NOTIFY_CLOSED != toe)
@ -1651,15 +1723,6 @@ connection_done (void *cls,
if (NULL != input_filename)
GNUNET_SCHEDULER_shutdown ();
#endif
cnt = req_count++;
if (req_max == cnt)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Restarting exchange service after %llu requests\n",
cnt);
(void) kill (getpid (),
SIGTERM);
}
}
@ -1780,46 +1843,42 @@ run (void *cls,
GNUNET_SCHEDULER_shutdown ();
return;
}
{
struct MHD_Daemon *mhd;
mhd = MHD_start_daemon (MHD_USE_SUSPEND_RESUME
| MHD_USE_PIPE_FOR_SHUTDOWN
| MHD_USE_DEBUG | MHD_USE_DUAL_STACK
| MHD_USE_TCP_FASTOPEN,
(-1 == fh) ? serve_port : 0,
NULL, NULL,
&handle_mhd_request, NULL,
MHD_OPTION_LISTEN_BACKLOG_SIZE,
(unsigned int) 1024,
MHD_OPTION_LISTEN_SOCKET,
fh,
MHD_OPTION_EXTERNAL_LOGGER,
&TALER_MHD_handle_logs,
NULL,
MHD_OPTION_NOTIFY_COMPLETED,
&handle_mhd_completion_callback,
NULL,
MHD_OPTION_NOTIFY_CONNECTION,
&connection_done,
NULL,
MHD_OPTION_CONNECTION_TIMEOUT,
connection_timeout,
(0 == allow_address_reuse)
mhd = MHD_start_daemon (MHD_USE_SUSPEND_RESUME
| MHD_USE_PIPE_FOR_SHUTDOWN
| MHD_USE_DEBUG | MHD_USE_DUAL_STACK
| MHD_USE_TCP_FASTOPEN,
(-1 == fh) ? serve_port : 0,
NULL, NULL,
&handle_mhd_request, NULL,
MHD_OPTION_LISTEN_BACKLOG_SIZE,
(unsigned int) 1024,
MHD_OPTION_LISTEN_SOCKET,
fh,
MHD_OPTION_EXTERNAL_LOGGER,
&TALER_MHD_handle_logs,
NULL,
MHD_OPTION_NOTIFY_COMPLETED,
&handle_mhd_completion_callback,
NULL,
MHD_OPTION_NOTIFY_CONNECTION,
&connection_done,
NULL,
MHD_OPTION_CONNECTION_TIMEOUT,
connection_timeout,
(0 == allow_address_reuse)
? MHD_OPTION_END
: MHD_OPTION_LISTENING_ADDRESS_REUSE,
(unsigned int) allow_address_reuse,
MHD_OPTION_END);
if (NULL == mhd)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to launch HTTP service. Is the port in use?\n");
GNUNET_SCHEDULER_shutdown ();
return;
}
global_ret = EXIT_SUCCESS;
TALER_MHD_daemon_start (mhd);
(unsigned int) allow_address_reuse,
MHD_OPTION_END);
if (NULL == mhd)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to launch HTTP service. Is the port in use?\n");
GNUNET_SCHEDULER_shutdown ();
return;
}
global_ret = EXIT_SUCCESS;
TALER_MHD_daemon_start (mhd);
atexit (&write_stats);
#if HAVE_DEVELOPER
@ -1849,6 +1908,10 @@ main (int argc,
"connection-close",
"force HTTP connections to be closed after each request",
&connection_close),
GNUNET_GETOPT_option_flag ('I',
"check-invariants",
"enable expensive invariant checks",
&TEH_check_invariants_flag),
GNUNET_GETOPT_option_flag ('r',
"allow-reuse-address",
"allow multiple HTTPDs to listen to the same port",

View File

@ -144,6 +144,11 @@ extern const struct GNUNET_CONFIGURATION_Handle *TEH_cfg;
*/
extern char *TEH_exchange_directory;
/**
* -I command-line flag given?
*/
extern int TEH_check_invariants_flag;
/**
* Are clients allowed to request /keys for times other than the
* current time? Allowing this could be abused in a DoS-attack
@ -157,6 +162,13 @@ extern int TEH_allow_keys_timetravel;
*/
extern char *TEH_revocation_directory;
/**
* True if we should commit suicide once all active
* connections are finished. Also forces /keys requests
* to terminate if they are long-polling.
*/
extern bool TEH_suicide;
/**
* Master public key (according to the
* configuration in the exchange directory).

View File

@ -36,6 +36,12 @@
#define SKR_LIMIT 32
/**
* When do we forcefully timeout a /keys request?
*/
#define KEYS_TIMEOUT GNUNET_TIME_UNIT_MINUTES
/**
* Taler protocol version in the format CURRENT:REVISION:AGE
* as used by GNU libtool. See
@ -355,6 +361,11 @@ struct SuspendedKeysRequests
* The suspended connection.
*/
struct MHD_Connection *connection;
/**
* When does this request timeout?
*/
struct GNUNET_TIME_Absolute timeout;
};
@ -398,6 +409,11 @@ static unsigned int skr_size;
*/
static struct MHD_Connection *skr_connection;
/**
* Task to force timeouts on /keys requests.
*/
static struct GNUNET_SCHEDULER_Task *keys_tt;
/**
* For how long should a signing key be legally retained?
* Configuration value.
@ -419,6 +435,40 @@ static struct TALER_SecurityModulePublicKeyP esign_sm_pub;
*/
static bool terminating;
/**
* Function called to forcefully resume suspended keys requests.
*
* @param cls unused, NULL
*/
static void
keys_timeout_cb (void *cls)
{
struct SuspendedKeysRequests *skr;
(void) cls;
keys_tt = NULL;
while (NULL != (skr = skr_head))
{
if (GNUNET_TIME_absolute_is_future (skr->timeout))
break;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Resuming /keys request due to timeout\n");
GNUNET_CONTAINER_DLL_remove (skr_head,
skr_tail,
skr);
MHD_resume_connection (skr->connection);
TALER_MHD_daemon_trigger ();
GNUNET_free (skr);
}
if (NULL == skr)
return;
keys_tt = GNUNET_SCHEDULER_add_at (skr->timeout,
&keys_timeout_cb,
NULL);
}
/**
* Suspend /keys request while we (hopefully) are waiting to be
* provisioned with key material.
@ -445,6 +495,13 @@ suspend_request (struct MHD_Connection *connection)
GNUNET_CONTAINER_DLL_insert (skr_head,
skr_tail,
skr);
skr->timeout = GNUNET_TIME_relative_to_absolute (KEYS_TIMEOUT);
if (NULL == keys_tt)
{
keys_tt = GNUNET_SCHEDULER_add_at (skr->timeout,
&keys_timeout_cb,
NULL);
}
skr_size++;
if (skr_size > SKR_LIMIT)
{
@ -477,9 +534,8 @@ check_dk (void *cls,
{
struct TEH_DenominationKey *dk = value;
(void) cls;
(void) hc;
(void) value;
GNUNET_assert (TALER_DENOMINATION_INVALID != dk->denom_pub.cipher);
if (TALER_DENOMINATION_RSA == dk->denom_pub.cipher)
GNUNET_assert (GNUNET_CRYPTO_rsa_public_key_check (
@ -493,6 +549,8 @@ TEH_check_invariants ()
{
struct TEH_KeyStateHandle *ksh;
if (0 == TEH_check_invariants_flag)
return;
ksh = TEH_keys_get_state ();
if (NULL == ksh)
return;
@ -1073,6 +1131,11 @@ TEH_keys_init ()
void
TEH_keys_finished ()
{
if (NULL != keys_tt)
{
GNUNET_SCHEDULER_cancel (keys_tt);
keys_tt = NULL;
}
if (NULL != key_state)
destroy_key_state (key_state,
true);
@ -2282,13 +2345,17 @@ TEH_keys_get_handler (struct TEH_RequestContext *rc,
ksh = TEH_keys_get_state ();
if (NULL == ksh)
{
if ( (SKR_LIMIT == skr_size) &&
(rc->connection == skr_connection) )
if ( ( (SKR_LIMIT == skr_size) &&
(rc->connection == skr_connection) ) ||
TEH_suicide)
{
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
"too many connections suspended on /keys");
return TALER_MHD_reply_with_error (
rc->connection,
MHD_HTTP_SERVICE_UNAVAILABLE,
TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
TEH_suicide
? "server terminating"
: "too many connections suspended waiting on /keys");
}
return suspend_request (rc->connection);
}
@ -2688,7 +2755,7 @@ TEH_keys_management_get_keys_handler (const struct TEH_RequestHandler *rh,
if (NULL == ksh)
{
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
MHD_HTTP_SERVICE_UNAVAILABLE,
TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
"no key state");
}

View File

@ -271,6 +271,7 @@ refreshes_reveal_transaction (void *cls,
/* Obtain basic information about the refresh operation and what
gamma we committed to. */
// FIXME: why do we do 'get_melt' twice?
qs = TEH_plugin->get_melt (TEH_plugin->cls,
&rctx->rc,
&melt);
@ -611,6 +612,7 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,
{
enum GNUNET_DB_QueryStatus qs;
// FIXME: why do we do 'get_melt' twice?
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
(qs = TEH_plugin->get_melt (TEH_plugin->cls,
&rctx->rc,
@ -682,9 +684,13 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,
rctx->dks = dks;
rctx->link_sigs = link_sigs;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Optimistically creating %u signatures\n",
(unsigned int) rctx->num_fresh_coins);
/* sign _early_ (optimistic!) to keep out of transaction scope! */
rctx->ev_sigs = GNUNET_new_array (rctx->num_fresh_coins,
struct TALER_BlindedDenominationSignature);
// FIXME: this is sequential, modify logic to enable parallel signing!
for (unsigned int i = 0; i<rctx->num_fresh_coins; i++)
{
enum TALER_ErrorCode ec = TALER_EC_NONE;
@ -705,6 +711,8 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,
}
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Signatures ready, starting DB interaction\n");
/* We try the three transactions a few times, as theoretically
the pre-check might be satisfied by a concurrent transaction
voiding our final commit due to uniqueness violation; naturally,

View File

@ -37,6 +37,11 @@ struct AuthchangeState
* What is the new authorization token to send?
*/
const char *auth_token;
/**
* Old context, clean up on termination.
*/
struct GNUNET_CURL_Context *old_ctx;
};
@ -55,11 +60,7 @@ authchange_run (void *cls,
struct AuthchangeState *ss = cls;
(void) cmd;
if (NULL != is->ctx)
{
GNUNET_CURL_fini (is->ctx);
is->ctx = NULL;
}
ss->old_ctx = is->ctx;
if (NULL != is->rc)
{
GNUNET_CURL_gnunet_rc_destroy (is->rc);
@ -101,6 +102,11 @@ authchange_cleanup (void *cls,
struct AuthchangeState *ss = cls;
(void) cmd;
if (NULL != ss->old_ctx)
{
GNUNET_CURL_fini (ss->old_ctx);
ss->old_ctx = NULL;
}
GNUNET_free (ss);
}

View File

@ -42,11 +42,11 @@ TALER_mhd_is_https (struct MHD_Connection *connection)
if (NULL != forwarded_proto)
{
if (0 == strcmp (forwarded_proto,
"https"))
if (0 == strcasecmp (forwarded_proto,
"https"))
return GNUNET_YES;
if (0 == strcmp (forwarded_proto,
"http"))
if (0 == strcasecmp (forwarded_proto,
"http"))
return GNUNET_NO;
GNUNET_break (0);
return GNUNET_SYSERR;

View File

@ -74,17 +74,15 @@ static volatile bool in_shutdown;
enum GNUNET_GenericReturnValue
TES_transmit (int sock,
const struct GNUNET_MessageHeader *hdr)
TES_transmit_raw (int sock,
size_t end,
const void *pos)
{
ssize_t off = 0;
const void *pos = hdr;
uint16_t end = ntohs (hdr->size);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Sending message of type %u and length %u\n",
(unsigned int) ntohs (hdr->type),
(unsigned int) ntohs (hdr->size));
"Sending message of length %u\n",
(unsigned int) end);
while (off < end)
{
ssize_t ret = send (sock,
@ -118,6 +116,20 @@ TES_transmit (int sock,
}
enum GNUNET_GenericReturnValue
TES_transmit (int sock,
const struct GNUNET_MessageHeader *hdr)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Sending message of type %u and length %u\n",
(unsigned int) ntohs (hdr->type),
(unsigned int) ntohs (hdr->size));
return TES_transmit_raw (sock,
ntohs (hdr->size),
hdr);
}
struct GNUNET_NETWORK_Handle *
TES_open_socket (const char *unixpath)
{

View File

@ -51,6 +51,19 @@ TES_transmit (int sock,
const struct GNUNET_MessageHeader *hdr);
/**
* Transmit @a end bytes from @a pos on @a sock.
*
* @param sock where to send the data
* @param end how many bytes to send
* @param pos first address with data
* @return #GNUNET_OK on success
*/
enum GNUNET_GenericReturnValue
TES_transmit_raw (int sock,
size_t end,
const void *pos);
/**
* Information we keep for a client connected to us.
*/

View File

@ -85,6 +85,11 @@ struct DenominationKey
*/
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.
*/
@ -214,7 +219,6 @@ static struct GNUNET_CONTAINER_MultiHashMap *keys;
*/
static struct GNUNET_SCHEDULER_Task *keygen_task;
/**
* Lock for the keys queue.
*/
@ -227,15 +231,12 @@ static uint64_t key_gen;
/**
* Notify @a client about @a dk becoming available.
* Generate the announcement message for @a dk.
*
* @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
* @param[in,out] denomination key to generate the announcement for
*/
static enum GNUNET_GenericReturnValue
notify_client_dk_add (struct TES_Client *client,
const struct DenominationKey *dk)
static void
generate_response (struct DenominationKey *dk)
{
struct Denomination *denom = dk->denom;
size_t nlen = strlen (denom->section) + 1;
@ -273,55 +274,7 @@ notify_client_dk_add (struct TES_Client *client,
memcpy (p + buf_len,
denom->section,
nlen);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Sending RSA denomination key %s (%s)\n",
GNUNET_h2s (&dk->h_rsa.hash),
denom->section);
if (GNUNET_OK !=
TES_transmit (client->csock,
&an->header))
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Client %p must have disconnected\n",
client);
GNUNET_free (an);
return GNUNET_SYSERR;
}
GNUNET_free (an);
return GNUNET_OK;
}
/**
* Notify @a client about @a dk being purged.
*
* @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 enum GNUNET_GenericReturnValue
notify_client_dk_del (struct TES_Client *client,
const struct DenominationKey *dk)
{
struct TALER_CRYPTO_RsaKeyPurgeNotification pn = {
.header.type = htons (TALER_HELPER_RSA_MT_PURGE),
.header.size = htons (sizeof (pn)),
.h_rsa = dk->h_rsa
};
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Sending RSA denomination expiration %s\n",
GNUNET_h2s (&dk->h_rsa.hash));
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;
dk->an = an;
}
@ -342,6 +295,7 @@ handle_sign_request (struct TES_Client *client,
const void *blinded_msg = &sr[1];
size_t blinded_msg_size = ntohs (sr->header.size) - sizeof (*sr);
struct GNUNET_CRYPTO_RsaSignature *rsa_signature;
struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
dk = GNUNET_CONTAINER_multihashmap_get (keys,
@ -407,6 +361,7 @@ handle_sign_request (struct TES_Client *client,
return TES_transmit (client->csock,
&sf.header);
}
{
struct TALER_CRYPTO_SignResponse *sr;
void *buf;
@ -427,7 +382,10 @@ handle_sign_request (struct TES_Client *client,
buf_size);
GNUNET_free (buf);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Sending RSA signature\n");
"Sending RSA signature after %s\n",
GNUNET_STRINGS_relative_time_to_string (
GNUNET_TIME_absolute_get_duration (now),
GNUNET_YES));
ret = TES_transmit (client->csock,
&sr->header);
GNUNET_free (sr);
@ -502,6 +460,7 @@ setup_key (struct DenominationKey *dk,
dk->denom_priv = priv;
dk->denom_pub = pub;
dk->key_gen = key_gen;
generate_response (dk);
if (GNUNET_OK !=
GNUNET_CONTAINER_multihashmap_put (
keys,
@ -514,6 +473,7 @@ setup_key (struct DenominationKey *dk,
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;
}
@ -660,6 +620,12 @@ rsa_work_dispatch (struct TES_Client *client,
static enum GNUNET_GenericReturnValue
rsa_client_init (struct TES_Client *client)
{
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;
@ -669,20 +635,39 @@ rsa_client_init (struct TES_Client *client)
NULL != dk;
dk = dk->next)
{
if (GNUNET_OK !=
notify_client_dk_add (client,
dk))
{
GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Client %p must have disconnected\n",
client);
return GNUNET_SYSERR;
}
obs += ntohs (dk->an->header.size);
}
}
buf = GNUNET_malloc (obs);
obs = 0;
for (struct Denomination *denom = denom_head;
NULL != denom;
denom = denom->next)
{
for (struct DenominationKey *dk = denom->keys_head;
NULL != dk;
dk = dk->next)
{
memcpy (&buf[obs],
dk->an,
ntohs (dk->an->header.size));
obs += ntohs (dk->an->header.size);
}
}
client->key_gen = key_gen;
GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
if (GNUNET_OK !=
TES_transmit_raw (client->csock,
obs,
buf))
{
GNUNET_free (buf);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Client %p must have disconnected\n",
client);
return GNUNET_SYSERR;
}
GNUNET_free (buf);
{
struct GNUNET_MessageHeader synced = {
.type = htons (TALER_HELPER_RSA_SYNCED),
@ -714,7 +699,36 @@ rsa_client_init (struct TES_Client *client)
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)
{
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)
@ -727,29 +741,33 @@ rsa_update_client_keys (struct TES_Client *client)
continue;
if (key->purge)
{
if (GNUNET_OK !=
notify_client_dk_del (client,
key))
{
GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
return GNUNET_SYSERR;
}
struct TALER_CRYPTO_RsaKeyPurgeNotification pn = {
.header.type = htons (TALER_HELPER_RSA_MT_PURGE),
.header.size = htons (sizeof (pn)),
.h_rsa = key->h_rsa
};
memcpy (&buf[obs],
&pn,
sizeof (pn));
obs += sizeof (pn);
}
else
{
if (GNUNET_OK !=
notify_client_dk_add (client,
key))
{
GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
return GNUNET_SYSERR;
}
memcpy (&buf[obs],
key->an,
ntohs (key->an->header.size));
obs += ntohs (key->an->header.size);
}
}
}
client->key_gen = key_gen;
GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
return GNUNET_OK;
ret = TES_transmit_raw (client->csock,
obs,
buf);
GNUNET_free (buf);
return ret;
}
@ -896,6 +914,7 @@ update_keys (struct Denomination *denom,
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;
}
@ -943,6 +962,8 @@ update_denominations (void *cls)
keygen_task = NULL;
now = GNUNET_TIME_absolute_get ();
(void) GNUNET_TIME_round_abs (&now);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Updating denominations ...\n");
GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
do {
denom = denom_head;
@ -953,6 +974,8 @@ update_denominations (void *cls)
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),
@ -1041,6 +1064,7 @@ parse_key (struct Denomination *denom,
TALER_rsa_pub_hash (pub,
&dk->h_rsa);
dk->denom_pub = pub;
generate_response (dk);
if (GNUNET_OK !=
GNUNET_CONTAINER_multihashmap_put (
keys,
@ -1054,6 +1078,7 @@ parse_key (struct Denomination *denom,
filename);
GNUNET_CRYPTO_rsa_private_key_free (priv);
GNUNET_CRYPTO_rsa_public_key_free (pub);
GNUNET_free (dk->an);
GNUNET_free (dk);
return;
}