add cmd line option to restrict timetravel, minor code cleanup of keystate logic
This commit is contained in:
parent
fb47c680b1
commit
c17909d820
@ -82,6 +82,14 @@ char *TEH_exchange_directory;
|
|||||||
*/
|
*/
|
||||||
char *TEH_revocation_directory;
|
char *TEH_revocation_directory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Are clients allowed to request /keys for times other than the
|
||||||
|
* current time? Allowing this could be abused in a DoS-attack
|
||||||
|
* as building new /keys responses is expensive. Should only be
|
||||||
|
* enabled for testcases, development and test systems.
|
||||||
|
*/
|
||||||
|
int TEH_allow_keys_timetravel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The exchange's configuration (global)
|
* The exchange's configuration (global)
|
||||||
*/
|
*/
|
||||||
@ -1183,6 +1191,10 @@ main (int argc,
|
|||||||
char *logfile = NULL;
|
char *logfile = NULL;
|
||||||
int connection_close = GNUNET_NO;
|
int connection_close = GNUNET_NO;
|
||||||
const struct GNUNET_GETOPT_CommandLineOption options[] = {
|
const struct GNUNET_GETOPT_CommandLineOption options[] = {
|
||||||
|
GNUNET_GETOPT_option_flag ('a',
|
||||||
|
"allow-timetravel",
|
||||||
|
"allow clients to request /keys for arbitrary timestamps (for testing and development only)",
|
||||||
|
&TEH_allow_keys_timetravel),
|
||||||
GNUNET_GETOPT_option_flag ('C',
|
GNUNET_GETOPT_option_flag ('C',
|
||||||
"connection-close",
|
"connection-close",
|
||||||
"force HTTP connections to be closed after each request",
|
"force HTTP connections to be closed after each request",
|
||||||
|
@ -43,6 +43,14 @@ extern struct GNUNET_CONFIGURATION_Handle *TEH_cfg;
|
|||||||
*/
|
*/
|
||||||
extern char *TEH_exchange_directory;
|
extern char *TEH_exchange_directory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Are clients allowed to request /keys for times other than the
|
||||||
|
* current time? Allowing this could be abused in a DoS-attack
|
||||||
|
* as building new /keys responses is expensive. Should only be
|
||||||
|
* enabled for testcases, development and test systems.
|
||||||
|
*/
|
||||||
|
extern int TEH_allow_keys_timetravel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main directory with revocation data.
|
* Main directory with revocation data.
|
||||||
*/
|
*/
|
||||||
|
@ -121,7 +121,7 @@ struct KeysResponseData
|
|||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Response to return if the client supports (gzip) compression.
|
* Response to return if the client supports (deflate) compression.
|
||||||
*/
|
*/
|
||||||
struct MHD_Response *response_compressed;
|
struct MHD_Response *response_compressed;
|
||||||
|
|
||||||
@ -211,15 +211,15 @@ struct ResponseFactoryContext
|
|||||||
*/
|
*/
|
||||||
struct TEH_KS_StateHandle *key_state;
|
struct TEH_KS_StateHandle *key_state;
|
||||||
|
|
||||||
/**
|
|
||||||
* Length of the @e denomkey_array.
|
|
||||||
*/
|
|
||||||
unsigned int denomkey_array_length;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Time stamp used as "now".
|
* Time stamp used as "now".
|
||||||
*/
|
*/
|
||||||
struct GNUNET_TIME_Absolute now;
|
struct GNUNET_TIME_Absolute now;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Length of the @e denomkey_array.
|
||||||
|
*/
|
||||||
|
unsigned int denomkey_array_length;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -249,7 +249,7 @@ struct TEH_KS_StateHandle
|
|||||||
struct GNUNET_CONTAINER_MultiHashMap *revoked_map;
|
struct GNUNET_CONTAINER_MultiHashMap *revoked_map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorted array of responses to /keys (sorted by cherry-picking date) of
|
* Sorted array of responses to /keys (MUST be sorted by cherry-picking date) of
|
||||||
* length @e krd_array_length;
|
* length @e krd_array_length;
|
||||||
*/
|
*/
|
||||||
struct KeysResponseData *krd_array;
|
struct KeysResponseData *krd_array;
|
||||||
@ -309,6 +309,12 @@ static struct TEH_KS_StateHandle *internal_key_state;
|
|||||||
*/
|
*/
|
||||||
static pthread_mutex_t internal_key_state_mutex = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t internal_key_state_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration value LOOKAHEAD_PROVIDE that says for how far in the
|
||||||
|
* future we want to provide exchange key information to clients.
|
||||||
|
*/
|
||||||
|
static struct GNUNET_TIME_Relative conf_duration_provide;
|
||||||
|
|
||||||
|
|
||||||
/* ************************** Clean up logic *********************** */
|
/* ************************** Clean up logic *********************** */
|
||||||
|
|
||||||
@ -368,6 +374,11 @@ destroy_response_builder (struct ResponseBuilderContext *rbc)
|
|||||||
json_decref (rbc->auditors_array);
|
json_decref (rbc->auditors_array);
|
||||||
rbc->auditors_array = NULL;
|
rbc->auditors_array = NULL;
|
||||||
}
|
}
|
||||||
|
if (NULL != rbc->hash_context)
|
||||||
|
{
|
||||||
|
GNUNET_CRYPTO_hash_context_abort (rbc->hash_context);
|
||||||
|
rbc->hash_context = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -447,7 +458,7 @@ ks_free (struct TEH_KS_StateHandle *key_state)
|
|||||||
/**
|
/**
|
||||||
* Pipe used for signaling reloading of our key state.
|
* Pipe used for signaling reloading of our key state.
|
||||||
*/
|
*/
|
||||||
static int reload_pipe[2];
|
static int reload_pipe[2] = { -1, -1 };
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -458,23 +469,15 @@ static int reload_pipe[2];
|
|||||||
static void
|
static void
|
||||||
handle_signal (int signal_number)
|
handle_signal (int signal_number)
|
||||||
{
|
{
|
||||||
ssize_t res;
|
char c = (char) signal_number; /* never seen a signal_number > 127 on any platform */
|
||||||
char c = signal_number;
|
|
||||||
|
|
||||||
res = write (reload_pipe[1],
|
(void) ! write (reload_pipe[1],
|
||||||
&c,
|
&c,
|
||||||
1);
|
1);
|
||||||
if ( (res < 0) &&
|
/* While one might like to "handle errors" here, even logging via fprintf()
|
||||||
(EINTR != errno) )
|
isn't safe inside of a signal handler. So there is nothing we safely CAN
|
||||||
{
|
do. OTOH, also very little that can go wrong in pratice. Calling _exit()
|
||||||
GNUNET_break (0);
|
on errors might be a possibility, but that might do more harm than good. *///
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (0 == res)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -482,11 +485,10 @@ handle_signal (int signal_number)
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert the public part of a denomination key issue to a JSON
|
* Convert the public part of denomination key data to a JSON object.
|
||||||
* object.
|
|
||||||
*
|
*
|
||||||
* @param pk public key of the denomination key
|
* @param pk public key of the denomination
|
||||||
* @param dki the denomination key issue
|
* @param dki the denomination key issue information
|
||||||
* @return a JSON object describing the denomination key isue (public part)
|
* @return a JSON object describing the denomination key isue (public part)
|
||||||
*/
|
*/
|
||||||
static json_t *
|
static json_t *
|
||||||
@ -511,7 +513,9 @@ denom_key_issue_to_json (
|
|||||||
TALER_amount_ntoh (&fee_refund,
|
TALER_amount_ntoh (&fee_refund,
|
||||||
&dki->properties.fee_refund);
|
&dki->properties.fee_refund);
|
||||||
return
|
return
|
||||||
json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}",
|
json_pack ("{s:o, s:o, s:o, s:o, s:o,"
|
||||||
|
" s:o, s:o, s:o, s:o, s:o,"
|
||||||
|
" s:o}",
|
||||||
"master_sig",
|
"master_sig",
|
||||||
GNUNET_JSON_from_data_auto (&dki->signature),
|
GNUNET_JSON_from_data_auto (&dki->signature),
|
||||||
"stamp_start",
|
"stamp_start",
|
||||||
@ -526,6 +530,7 @@ denom_key_issue_to_json (
|
|||||||
"stamp_expire_legal",
|
"stamp_expire_legal",
|
||||||
GNUNET_JSON_from_time_abs (GNUNET_TIME_absolute_ntoh (
|
GNUNET_JSON_from_time_abs (GNUNET_TIME_absolute_ntoh (
|
||||||
dki->properties.expire_legal)),
|
dki->properties.expire_legal)),
|
||||||
|
/* 5 entries until here */
|
||||||
"denom_pub",
|
"denom_pub",
|
||||||
GNUNET_JSON_from_rsa_public_key (pk->rsa_public_key),
|
GNUNET_JSON_from_rsa_public_key (pk->rsa_public_key),
|
||||||
"value",
|
"value",
|
||||||
@ -536,6 +541,7 @@ denom_key_issue_to_json (
|
|||||||
TALER_JSON_from_amount (&fee_deposit),
|
TALER_JSON_from_amount (&fee_deposit),
|
||||||
"fee_refresh",
|
"fee_refresh",
|
||||||
TALER_JSON_from_amount (&fee_refresh),
|
TALER_JSON_from_amount (&fee_refresh),
|
||||||
|
/* 10 entries until here */
|
||||||
"fee_refund",
|
"fee_refund",
|
||||||
TALER_JSON_from_amount (&fee_refund));
|
TALER_JSON_from_amount (&fee_refund));
|
||||||
}
|
}
|
||||||
@ -553,20 +559,37 @@ static int
|
|||||||
store_in_map (struct GNUNET_CONTAINER_MultiHashMap *map,
|
store_in_map (struct GNUNET_CONTAINER_MultiHashMap *map,
|
||||||
const struct TALER_EXCHANGEDB_DenominationKey *dki)
|
const struct TALER_EXCHANGEDB_DenominationKey *dki)
|
||||||
{
|
{
|
||||||
struct TALER_EXCHANGEDB_DenominationKey *d2;
|
/* First, we verify that the @a dki is actually well-formed. While it comes
|
||||||
int res;
|
from our own hard disk, there is the possibility of missconfiguration
|
||||||
|
(i.e. bogus file in the directory), or that the administrator used the
|
||||||
|
wrong master public key, and we should not accept entries that are not
|
||||||
|
well-formed. *///
|
||||||
{
|
{
|
||||||
const struct TALER_EXCHANGEDB_DenominationKeyInformationP *dkip;
|
const struct TALER_EXCHANGEDB_DenominationKeyInformationP *dkip;
|
||||||
struct TALER_DenominationKeyValidityPS denom_key_issue;
|
struct TALER_DenominationKeyValidityPS denom_key_issue;
|
||||||
|
|
||||||
dkip = &dki->issue;
|
dkip = &dki->issue;
|
||||||
denom_key_issue = dkip->properties;
|
denom_key_issue = dkip->properties;
|
||||||
|
/* The above is straight from our disk. We should not trust
|
||||||
|
that it is well-formed, so we setup crucial fields ourselves. */
|
||||||
denom_key_issue.purpose.purpose
|
denom_key_issue.purpose.purpose
|
||||||
= htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY);
|
= htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY);
|
||||||
denom_key_issue.purpose.size
|
denom_key_issue.purpose.size
|
||||||
= htonl (sizeof (struct TALER_DenominationKeyValidityPS));
|
= htonl (sizeof (struct TALER_DenominationKeyValidityPS));
|
||||||
denom_key_issue.master = TEH_master_public_key;
|
denom_key_issue.master = TEH_master_public_key;
|
||||||
|
|
||||||
|
/* Check that the data we read matches our expectations */
|
||||||
|
if (0 !=
|
||||||
|
GNUNET_memcmp (&denom_key_issue,
|
||||||
|
&dkip->properties))
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"Invalid fields in denomination key `%s'\n",
|
||||||
|
GNUNET_h2s (&dkip->properties.denom_hash));
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Also check the signature by the master public key */
|
||||||
if (GNUNET_SYSERR ==
|
if (GNUNET_SYSERR ==
|
||||||
GNUNET_CRYPTO_eddsa_verify (
|
GNUNET_CRYPTO_eddsa_verify (
|
||||||
TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY,
|
TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY,
|
||||||
@ -581,27 +604,36 @@ store_in_map (struct GNUNET_CONTAINER_MultiHashMap *map,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d2 = GNUNET_new (struct TALER_EXCHANGEDB_DenominationKey);
|
/* We need to make a deep copy of the @a dki, as the original was allocated
|
||||||
d2->issue = dki->issue;
|
elsewhere and will be freed by the caller. */
|
||||||
if (NULL != dki->denom_priv.rsa_private_key)
|
{
|
||||||
d2->denom_priv.rsa_private_key
|
struct TALER_EXCHANGEDB_DenominationKey *d2;
|
||||||
= GNUNET_CRYPTO_rsa_private_key_dup (dki->denom_priv.rsa_private_key);
|
|
||||||
d2->denom_pub.rsa_public_key
|
d2 = GNUNET_new (struct TALER_EXCHANGEDB_DenominationKey);
|
||||||
= GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key);
|
d2->issue = dki->issue;
|
||||||
res = GNUNET_CONTAINER_multihashmap_put (map,
|
if (GNUNET_OK !=
|
||||||
|
GNUNET_CONTAINER_multihashmap_put (map,
|
||||||
&d2->issue.properties.denom_hash,
|
&d2->issue.properties.denom_hash,
|
||||||
d2,
|
d2,
|
||||||
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
|
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
|
||||||
if (GNUNET_OK != res)
|
{
|
||||||
{
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
"Duplicate denomination key `%s'\n",
|
||||||
"Duplicate denomination key `%s'\n",
|
GNUNET_h2s (&d2->issue.properties.denom_hash));
|
||||||
GNUNET_h2s (&d2->issue.properties.denom_hash));
|
GNUNET_free (d2);
|
||||||
if (NULL != d2->denom_priv.rsa_private_key)
|
return GNUNET_NO;
|
||||||
GNUNET_CRYPTO_rsa_private_key_free (d2->denom_priv.rsa_private_key);
|
}
|
||||||
GNUNET_CRYPTO_rsa_public_key_free (d2->denom_pub.rsa_public_key);
|
|
||||||
GNUNET_free (d2);
|
/* finish *deep* part of deep copy */
|
||||||
return GNUNET_NO;
|
if (NULL != dki->denom_priv.rsa_private_key)
|
||||||
|
{
|
||||||
|
/* we might be past the withdraw period, so private key could have been deleted,
|
||||||
|
so only try to (deep) copy if non-NULL. */
|
||||||
|
d2->denom_priv.rsa_private_key
|
||||||
|
= GNUNET_CRYPTO_rsa_private_key_dup (dki->denom_priv.rsa_private_key);
|
||||||
|
}
|
||||||
|
d2->denom_pub.rsa_public_key
|
||||||
|
= GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key);
|
||||||
}
|
}
|
||||||
return GNUNET_OK;
|
return GNUNET_OK;
|
||||||
}
|
}
|
||||||
@ -624,33 +656,6 @@ struct AddRevocationContext
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the relative time value that describes how
|
|
||||||
* far in the future do we want to provide coin keys.
|
|
||||||
*
|
|
||||||
* @return the provide duration
|
|
||||||
*/
|
|
||||||
static struct GNUNET_TIME_Relative
|
|
||||||
TALER_EXCHANGE_conf_duration_provide (void)
|
|
||||||
{
|
|
||||||
struct GNUNET_TIME_Relative rel;
|
|
||||||
|
|
||||||
if (GNUNET_OK !=
|
|
||||||
GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
|
|
||||||
"exchange",
|
|
||||||
"LOOKAHEAD_PROVIDE",
|
|
||||||
&rel))
|
|
||||||
{
|
|
||||||
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
|
|
||||||
"exchange",
|
|
||||||
"LOOKAHEAD_PROVIDE",
|
|
||||||
"time value required");
|
|
||||||
GNUNET_assert (0);
|
|
||||||
}
|
|
||||||
return rel;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute transaction to add revocations.
|
* Execute transaction to add revocations.
|
||||||
*
|
*
|
||||||
@ -771,7 +776,7 @@ reload_keys_denom_iter (void *cls,
|
|||||||
}
|
}
|
||||||
|
|
||||||
horizon = GNUNET_TIME_absolute_add (rfc->now,
|
horizon = GNUNET_TIME_absolute_add (rfc->now,
|
||||||
TALER_EXCHANGE_conf_duration_provide ());
|
conf_duration_provide);
|
||||||
start = GNUNET_TIME_absolute_ntoh (dki->issue.properties.start);
|
start = GNUNET_TIME_absolute_ntoh (dki->issue.properties.start);
|
||||||
if (start.abs_value_us > horizon.abs_value_us)
|
if (start.abs_value_us > horizon.abs_value_us)
|
||||||
{
|
{
|
||||||
@ -944,8 +949,7 @@ reload_keys_sign_iter (
|
|||||||
struct GNUNET_TIME_Absolute now;
|
struct GNUNET_TIME_Absolute now;
|
||||||
struct GNUNET_TIME_Absolute horizon;
|
struct GNUNET_TIME_Absolute horizon;
|
||||||
|
|
||||||
horizon = GNUNET_TIME_relative_to_absolute (
|
horizon = GNUNET_TIME_relative_to_absolute (conf_duration_provide);
|
||||||
TALER_EXCHANGE_conf_duration_provide ());
|
|
||||||
if (GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us >
|
if (GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us >
|
||||||
horizon.abs_value_us)
|
horizon.abs_value_us)
|
||||||
{
|
{
|
||||||
@ -1127,7 +1131,9 @@ initialize_denomkey_array (void *cls,
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Comparator used to sort the `struct DenominationKeyEntry` array
|
* Comparator used to sort the `struct DenominationKeyEntry` array
|
||||||
* by the validity period's starting time of the keys.
|
* by the validity period's starting time of the keys. Must match
|
||||||
|
* the expected sorting by cherry_pick_date (which is based on the
|
||||||
|
* issue.properties.start) used in #krd_search_comparator.
|
||||||
*
|
*
|
||||||
* @param k1 a `struct DenominationKeyEntry *`
|
* @param k1 a `struct DenominationKeyEntry *`
|
||||||
* @param k2 a `struct DenominationKeyEntry *`
|
* @param k2 a `struct DenominationKeyEntry *`
|
||||||
@ -1460,7 +1466,6 @@ build_keys_response (const struct ResponseFactoryContext *rfc,
|
|||||||
&free_auditor_entry,
|
&free_auditor_entry,
|
||||||
NULL);
|
NULL);
|
||||||
GNUNET_CONTAINER_multihashmap_destroy (auditors);
|
GNUNET_CONTAINER_multihashmap_destroy (auditors);
|
||||||
GNUNET_CRYPTO_hash_context_abort (rbc.hash_context);
|
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1822,6 +1827,8 @@ make_fresh_key_state (struct GNUNET_TIME_Absolute now)
|
|||||||
|
|
||||||
if (last.abs_value_us == d.abs_value_us)
|
if (last.abs_value_us == d.abs_value_us)
|
||||||
continue;
|
continue;
|
||||||
|
/* must be monotonically increasing as per qsort() call above: */
|
||||||
|
GNUNET_assert (last.abs_value_us < d.abs_value_us);
|
||||||
last = d;
|
last = d;
|
||||||
off++;
|
off++;
|
||||||
}
|
}
|
||||||
@ -2277,11 +2284,31 @@ static struct GNUNET_SIGNAL_Context *sigchld;
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup initial #internal_key_state.
|
* Setup initial #internal_key_state and our signal handlers.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
TEH_KS_init (void)
|
TEH_KS_init (void)
|
||||||
{
|
{
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
|
||||||
|
"exchange",
|
||||||
|
"LOOKAHEAD_PROVIDE",
|
||||||
|
&conf_duration_provide))
|
||||||
|
{
|
||||||
|
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"exchange",
|
||||||
|
"LOOKAHEAD_PROVIDE",
|
||||||
|
"time value required");
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
|
if (0 == conf_duration_provide.rel_value_us)
|
||||||
|
{
|
||||||
|
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
|
||||||
|
"exchange",
|
||||||
|
"LOOKAHEAD_PROVIDE",
|
||||||
|
"value cannot be zero");
|
||||||
|
return GNUNET_SYSERR;
|
||||||
|
}
|
||||||
if (0 != pipe (reload_pipe))
|
if (0 != pipe (reload_pipe))
|
||||||
{
|
{
|
||||||
GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
|
||||||
@ -2312,7 +2339,7 @@ TEH_KS_init (void)
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finally release #internal_key_state.
|
* Finally release #internal_key_state and our signal handlers.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
TEH_KS_free (void)
|
TEH_KS_free (void)
|
||||||
@ -2322,18 +2349,43 @@ TEH_KS_free (void)
|
|||||||
/* Note: locking is no longer be required, as we are again
|
/* Note: locking is no longer be required, as we are again
|
||||||
single-threaded. */
|
single-threaded. */
|
||||||
ks = internal_key_state;
|
ks = internal_key_state;
|
||||||
if (NULL == ks)
|
if (NULL != ks)
|
||||||
return;
|
{
|
||||||
GNUNET_assert (1 == ks->refcnt);
|
GNUNET_assert (1 == ks->refcnt);
|
||||||
ks->refcnt--;
|
ks->refcnt--;
|
||||||
ks_free (ks);
|
ks_free (ks);
|
||||||
GNUNET_SIGNAL_handler_uninstall (sigusr1);
|
}
|
||||||
GNUNET_SIGNAL_handler_uninstall (sigterm);
|
if (NULL != sigusr1)
|
||||||
GNUNET_SIGNAL_handler_uninstall (sigint);
|
{
|
||||||
GNUNET_SIGNAL_handler_uninstall (sighup);
|
GNUNET_SIGNAL_handler_uninstall (sigusr1);
|
||||||
GNUNET_SIGNAL_handler_uninstall (sigchld);
|
sigusr1 = NULL;
|
||||||
GNUNET_break (0 == close (reload_pipe[0]));
|
}
|
||||||
GNUNET_break (0 == close (reload_pipe[1]));
|
if (NULL != sigterm)
|
||||||
|
{
|
||||||
|
GNUNET_SIGNAL_handler_uninstall (sigterm);
|
||||||
|
sigterm = NULL;
|
||||||
|
}
|
||||||
|
if (NULL != sigint)
|
||||||
|
{
|
||||||
|
GNUNET_SIGNAL_handler_uninstall (sigint);
|
||||||
|
sigint = NULL;
|
||||||
|
}
|
||||||
|
if (NULL != sighup)
|
||||||
|
{
|
||||||
|
GNUNET_SIGNAL_handler_uninstall (sighup);
|
||||||
|
sighup = NULL;
|
||||||
|
}
|
||||||
|
if (NULL != sigchld)
|
||||||
|
{
|
||||||
|
GNUNET_SIGNAL_handler_uninstall (sigchld);
|
||||||
|
sigchld = NULL;
|
||||||
|
}
|
||||||
|
if (-1 != reload_pipe[0])
|
||||||
|
{
|
||||||
|
GNUNET_break (0 == close (reload_pipe[0]));
|
||||||
|
GNUNET_break (0 == close (reload_pipe[1]));
|
||||||
|
reload_pipe[0] = reload_pipe[1] = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2356,10 +2408,11 @@ TEH_KS_sign (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
|
|||||||
key_state = TEH_KS_acquire (GNUNET_TIME_absolute_get ());
|
key_state = TEH_KS_acquire (GNUNET_TIME_absolute_get ());
|
||||||
if (NULL == key_state)
|
if (NULL == key_state)
|
||||||
{
|
{
|
||||||
/* This *can* happen if the exchange's keys are
|
/* This *can* happen if the exchange's keys are not properly maintained
|
||||||
not properly maintained. */
|
(i.e. administrator forgets to provision us with non-expired signing
|
||||||
|
keys or to send signal to reload keys after provisioning). */
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||||
"Cannot sign request, no valid keys available\n");
|
"Cannot sign request, no valid signing keys available. Were they properly provisioned and did you signal the exchange to reload the keys?\n");
|
||||||
return GNUNET_SYSERR;
|
return GNUNET_SYSERR;
|
||||||
}
|
}
|
||||||
*pub = key_state->current_sign_key_issue.issue.signkey_pub;
|
*pub = key_state->current_sign_key_issue.issue.signkey_pub;
|
||||||
@ -2374,8 +2427,8 @@ TEH_KS_sign (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Comparator used for a binary search for @a key in the
|
* Comparator used for a binary search by cherry_pick_date for @a key in the
|
||||||
* `struct KeysResponseData` array.
|
* `struct KeysResponseData` array. See libc's qsort() and bsearch() functions.
|
||||||
*
|
*
|
||||||
* @param key pointer to a `struct GNUNET_TIME_Absolute`
|
* @param key pointer to a `struct GNUNET_TIME_Absolute`
|
||||||
* @param value pointer to a `struct KeysResponseData` array entry
|
* @param value pointer to a `struct KeysResponseData` array entry
|
||||||
@ -2437,6 +2490,10 @@ TEH_handler_keys (const struct TEH_RequestHandler *rh,
|
|||||||
TALER_EC_KEYS_HAVE_NOT_NUMERIC,
|
TALER_EC_KEYS_HAVE_NOT_NUMERIC,
|
||||||
"last_issue_date");
|
"last_issue_date");
|
||||||
}
|
}
|
||||||
|
/* The following multiplication may overflow; but this should not really
|
||||||
|
be a problem, as giving back 'older' data than what the client asks for
|
||||||
|
(given that the client asks for data in the distant future) is not
|
||||||
|
problematic */
|
||||||
last_issue_date.abs_value_us = (uint64_t) cherrypickn * 1000000LLU;
|
last_issue_date.abs_value_us = (uint64_t) cherrypickn * 1000000LLU;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2458,11 +2515,26 @@ TEH_handler_keys (const struct TEH_RequestHandler *rh,
|
|||||||
{
|
{
|
||||||
GNUNET_break_op (0);
|
GNUNET_break_op (0);
|
||||||
return TALER_MHD_reply_with_error (connection,
|
return TALER_MHD_reply_with_error (connection,
|
||||||
MHD_HTTP_BAD_REQUEST,
|
MHD_HTTP_FORBIDDEN,
|
||||||
TALER_EC_KEYS_HAVE_NOT_NUMERIC,
|
TALER_EC_KEYS_HAVE_NOT_NUMERIC,
|
||||||
"now");
|
"now");
|
||||||
}
|
}
|
||||||
now.abs_value_us = (uint64_t) fakenown * 1000000LLU;
|
if (TEH_allow_keys_timetravel)
|
||||||
|
{
|
||||||
|
/* The following multiplication may overflow; but this should not really
|
||||||
|
be a problem, as giving back 'older' data than what the client asks for
|
||||||
|
(given that the client asks for data in the distant future) is not
|
||||||
|
problematic */
|
||||||
|
now.abs_value_us = (uint64_t) fakenown * 1000000LLU;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Option not allowed by configuration */
|
||||||
|
return TALER_MHD_reply_with_error (connection,
|
||||||
|
MHD_HTTP_BAD_REQUEST,
|
||||||
|
TALER_EC_KEYS_TIMETRAVEL_FORBIDDEN,
|
||||||
|
"timetravel not allowed by this exchange");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||||
"Handling request for /keys (%s/%s)\n",
|
"Handling request for /keys (%s/%s)\n",
|
||||||
@ -2474,11 +2546,14 @@ TEH_handler_keys (const struct TEH_RequestHandler *rh,
|
|||||||
key_state = TEH_KS_acquire (now);
|
key_state = TEH_KS_acquire (now);
|
||||||
if (NULL == key_state)
|
if (NULL == key_state)
|
||||||
{
|
{
|
||||||
TALER_LOG_ERROR ("Lacking keys to operate\n");
|
/* Maybe client picked time stamp too far in the future? In that case,
|
||||||
|
#MHD_HTTP_INTERNAL_SERVER_ERROR might be missleading, could be more like a
|
||||||
|
NOT_FOUND situation. But, OTOH, for 'sane' clients it is more likely
|
||||||
|
to be our fault, so let's speculatively assume we are to blame ;-) */
|
||||||
return TALER_MHD_reply_with_error (connection,
|
return TALER_MHD_reply_with_error (connection,
|
||||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||||
TALER_EC_EXCHANGE_BAD_CONFIGURATION,
|
TALER_EC_EXCHANGE_BAD_CONFIGURATION,
|
||||||
"no keys");
|
"no keys for requested time");
|
||||||
}
|
}
|
||||||
krd = bsearch (&last_issue_date,
|
krd = bsearch (&last_issue_date,
|
||||||
key_state->krd_array,
|
key_state->krd_array,
|
||||||
@ -2501,6 +2576,10 @@ TEH_handler_keys (const struct TEH_RequestHandler *rh,
|
|||||||
}
|
}
|
||||||
if (NULL == krd)
|
if (NULL == krd)
|
||||||
{
|
{
|
||||||
|
/* Maybe client picked time stamp too far in the future? In that case,
|
||||||
|
"INTERNAL_SERVER_ERROR" might be missleading, could be more like a
|
||||||
|
NOT_FOUND situation. But, OTOH, for 'sane' clients it is more likely
|
||||||
|
to be our fault, so let's speculatively assume we are to blame ;-) *///
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
TEH_KS_release (key_state);
|
TEH_KS_release (key_state);
|
||||||
return TALER_MHD_reply_with_error (connection,
|
return TALER_MHD_reply_with_error (connection,
|
||||||
|
@ -1051,6 +1051,13 @@ enum TALER_ErrorCode
|
|||||||
*/
|
*/
|
||||||
TALER_EC_KEYS_MISSING = 1901,
|
TALER_EC_KEYS_MISSING = 1901,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This exchange does not allow clients to request /keys for times
|
||||||
|
* other than the current (exchange) time. This reponse is provied
|
||||||
|
* with an HTTP status code of MHD_HTTP_FORBIDDEN.
|
||||||
|
*/
|
||||||
|
TALER_EC_KEYS_TIMETRAVEL_FORBIDDEN = 1902,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The backend could not find the merchant instance specified in the
|
* The backend could not find the merchant instance specified in the
|
||||||
* request. This response is provided with HTTP status code
|
* request. This response is provided with HTTP status code
|
||||||
|
@ -762,6 +762,7 @@ TALER_TESTING_setup_with_exchange_cfg (void *cls,
|
|||||||
NULL, NULL, NULL,
|
NULL, NULL, NULL,
|
||||||
"taler-exchange-httpd",
|
"taler-exchange-httpd",
|
||||||
"taler-exchange-httpd",
|
"taler-exchange-httpd",
|
||||||
|
"-a", /* some tests may need timetravel */
|
||||||
"-c", setup_ctx->config_filename,
|
"-c", setup_ctx->config_filename,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user