activating implementation of #6175

This commit is contained in:
Christian Grothoff 2020-12-14 15:42:32 +01:00
parent 468fc9d1a1
commit b5d88fc2d1
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
43 changed files with 1043 additions and 477 deletions

@ -1 +1 @@
Subproject commit 3501eb7b857d573258c1ab1c42d7e827c36cec9d Subproject commit 912dc84dc52a1291b635e19da32c7c824719f8d4

View File

@ -10,9 +10,9 @@ make
cd ../../.. cd ../../..
if ! diff contrib/gana/gnu-taler-error-codes/taler_error_codes.h src/include/taler_error_codes.h > /dev/null if ! diff contrib/gana/gnu-taler-error-codes/taler_error_codes.h src/include/taler_error_codes.h > /dev/null
then then
echo "Deploying latest new GANA database..."
cp contrib/gana/gnu-taler-error-codes/taler_error_codes.h src/include/taler_error_codes.h cp contrib/gana/gnu-taler-error-codes/taler_error_codes.h src/include/taler_error_codes.h
cp contrib/gana/gnu-taler-error-codes/taler_error_codes.c src/util/taler_error_codes.c fi
else if ! diff contrib/gana/gnu-taler-error-codes/taler_error_codes.c src/util/taler_error_codes.c > /dev/null
echo "GANA database already up-to-date" then
cp contrib/gana/gnu-taler-error-codes/taler_error_codes.c src/util/taler_error_codes.c
fi fi

View File

@ -116,6 +116,11 @@ mv a2e.dat $ABD
# Launch services # Launch services
echo "Launching services" echo "Launching services"
taler-bank-manage-testing $CONF postgres:///$TARGET_DB serve & taler-bank-manage-testing $CONF postgres:///$TARGET_DB serve &
TFN=`which taler-exchange-httpd`
TBINPFX=`dirname $TFN`
TLIBEXEC=${BINPFX}/../lib/libexec/taler/
$TLIBEXEC/taler-helper-crypto-eddsa -c $CONF 2> taler-helper-crypto-eddsa.log &
$TLIBEXEC/taler-helper-crypto-rsa -c $CONF 2> taler-helper-crypto-rsa.log &
taler-exchange-httpd -c $CONF 2> taler-exchange-httpd.log & taler-exchange-httpd -c $CONF 2> taler-exchange-httpd.log &
taler-merchant-httpd -c $CONF -L INFO 2> taler-merchant-httpd.log & taler-merchant-httpd -c $CONF -L INFO 2> taler-merchant-httpd.log &
taler-exchange-wirewatch -c $CONF 2> taler-exchange-wirewatch.log & taler-exchange-wirewatch -c $CONF 2> taler-exchange-wirewatch.log &

View File

@ -104,6 +104,11 @@ mv a2e.dat $ABD
# Launch services # Launch services
echo "Launching services" echo "Launching services"
taler-bank-manage-testing $CONF postgres:///$TARGET_DB serve &> revocation-bank.log & taler-bank-manage-testing $CONF postgres:///$TARGET_DB serve &> revocation-bank.log &
TFN=`which taler-exchange-httpd`
TBINPFX=`dirname $TFN`
TLIBEXEC=${BINPFX}/../lib/libexec/taler/
$TLIBEXEC/taler-helper-crypto-eddsa -c $CONF 2> taler-helper-crypto-eddsa.log &
$TLIBEXEC/taler-helper-crypto-rsa -c $CONF 2> taler-helper-crypto-rsa.log &
taler-exchange-httpd -c $CONF 2> taler-exchange-httpd.log & taler-exchange-httpd -c $CONF 2> taler-exchange-httpd.log &
EXCHANGE_PID=$! EXCHANGE_PID=$!
taler-merchant-httpd -c $CONF -L INFO 2> taler-merchant-httpd.log & taler-merchant-httpd -c $CONF -L INFO 2> taler-merchant-httpd.log &

View File

@ -562,8 +562,8 @@ handle_post_management (const struct TEH_RequestHandler *rh,
return r404 (connection, return r404 (connection,
"/management/denominations/$HDP/revoke"); "/management/denominations/$HDP/revoke");
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (args[2], GNUNET_STRINGS_string_to_data (args[1],
strlen (args[2]), strlen (args[1]),
&h_denom_pub, &h_denom_pub,
sizeof (h_denom_pub))) sizeof (h_denom_pub)))
{ {
@ -571,7 +571,7 @@ handle_post_management (const struct TEH_RequestHandler *rh,
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST, MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED, TALER_EC_GENERIC_PARAMETER_MALFORMED,
args[2]); args[1]);
} }
return TEH_handler_management_denominations_HDP_revoke (connection, return TEH_handler_management_denominations_HDP_revoke (connection,
&h_denom_pub, &h_denom_pub,
@ -591,8 +591,8 @@ handle_post_management (const struct TEH_RequestHandler *rh,
return r404 (connection, return r404 (connection,
"/management/signkeys/$HDP/revoke"); "/management/signkeys/$HDP/revoke");
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (args[2], GNUNET_STRINGS_string_to_data (args[1],
strlen (args[2]), strlen (args[1]),
&exchange_pub, &exchange_pub,
sizeof (exchange_pub))) sizeof (exchange_pub)))
{ {
@ -600,7 +600,7 @@ handle_post_management (const struct TEH_RequestHandler *rh,
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST, MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED, TALER_EC_GENERIC_PARAMETER_MALFORMED,
args[2]); args[1]);
} }
return TEH_handler_management_signkeys_EP_revoke (connection, return TEH_handler_management_signkeys_EP_revoke (connection,
&exchange_pub, &exchange_pub,
@ -805,7 +805,7 @@ handle_mhd_request (void *cls,
{ {
.url = "keys", .url = "keys",
.method = MHD_HTTP_METHOD_GET, .method = MHD_HTTP_METHOD_GET,
.handler.get = &TEH_handler_keys, // FIXME => TEH_keys_get_handler .handler.get = &TEH_keys_get_handler,
}, },
/* Requests for wiring information */ /* Requests for wiring information */
{ {
@ -1427,6 +1427,7 @@ run_single_request (void)
} }
MHD_run (mhd); MHD_run (mhd);
} }
TEH_resume_keys_requests ();
MHD_stop_daemon (mhd); MHD_stop_daemon (mhd);
mhd = NULL; mhd = NULL;
if (cld != waitpid (cld, if (cld != waitpid (cld,
@ -1463,6 +1464,7 @@ run_main_loop (int fh,
= MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_PIPE_FOR_SHUTDOWN = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_PIPE_FOR_SHUTDOWN
| MHD_USE_DEBUG | MHD_USE_DUAL_STACK | MHD_USE_DEBUG | MHD_USE_DUAL_STACK
| MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_INTERNAL_POLLING_THREAD
| MHD_ALLOW_SUSPEND_RESUME
| MHD_USE_TCP_FASTOPEN, | MHD_USE_TCP_FASTOPEN,
(-1 == fh) ? serve_port : 0, (-1 == fh) ? serve_port : 0,
NULL, NULL, NULL, NULL,
@ -1484,11 +1486,17 @@ run_main_loop (int fh,
} }
atexit (&write_stats); atexit (&write_stats);
ret = TEH_keys_init ();
if (GNUNET_OK == ret)
{
ret = TEH_KS_loop (); ret = TEH_KS_loop ();
TEH_keys_done ();
}
switch (ret) switch (ret)
{ {
case GNUNET_OK: case GNUNET_OK:
case GNUNET_SYSERR: case GNUNET_SYSERR:
TEH_resume_keys_requests ();
MHD_stop_daemon (mhd); MHD_stop_daemon (mhd);
break; break;
case GNUNET_NO: case GNUNET_NO:
@ -1544,11 +1552,13 @@ run_main_loop (int fh,
num_connections) num_connections)
sleep (1); sleep (1);
/* Now we're really done, practice clean shutdown */ /* Now we're really done, practice clean shutdown */
TEH_resume_keys_requests ();
MHD_stop_daemon (mhd); MHD_stop_daemon (mhd);
} }
break; break;
default: default:
GNUNET_break (0); GNUNET_break (0);
TEH_resume_keys_requests ();
MHD_stop_daemon (mhd); MHD_stop_daemon (mhd);
break; break;
} }

View File

@ -78,6 +78,11 @@ extern struct TALER_EXCHANGEDB_Plugin *TEH_plugin;
*/ */
extern char *TEH_currency; extern char *TEH_currency;
/**
* Are we shutting down?
*/
extern volatile bool MHD_terminating;
/** /**
* @brief Struct describing an URL and the handler for it. * @brief Struct describing an URL and the handler for it.
*/ */

View File

@ -33,6 +33,7 @@
#include "taler-exchange-httpd_deposit.h" #include "taler-exchange-httpd_deposit.h"
#include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd_responses.h"
#include "taler-exchange-httpd_keystate.h" #include "taler-exchange-httpd_keystate.h"
#include "taler-exchange-httpd_keys.h"
/** /**
@ -75,18 +76,18 @@ reply_deposit_success (struct MHD_Connection *connection,
.coin_pub = *coin_pub, .coin_pub = *coin_pub,
.merchant = *merchant .merchant = *merchant
}; };
enum TALER_ErrorCode ec;
TALER_amount_hton (&dc.amount_without_fee, TALER_amount_hton (&dc.amount_without_fee,
amount_without_fee); amount_without_fee);
if (GNUNET_OK != if (TALER_EC_NONE !=
TEH_KS_sign (&dc, (ec = TEH_keys_exchange_sign (&dc,
&pub, &pub,
&sig)) &sig)))
{ {
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_ec (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR, ec,
TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION, NULL);
"no keys");
} }
return TALER_MHD_reply_json_pack ( return TALER_MHD_reply_json_pack (
connection, connection,
@ -430,9 +431,10 @@ TEH_handler_deposit (struct MHD_Connection *connection,
/* check denomination exists and is valid */ /* check denomination exists and is valid */
{ {
struct TEH_KS_StateHandle *key_state; struct TEH_KS_StateHandle *key_state;
struct TALER_EXCHANGEDB_DenominationKey *dki; struct TEH_DenominationKey *dk;
enum TALER_ErrorCode ec; enum TALER_ErrorCode ec;
unsigned int hc; unsigned int hc;
struct GNUNET_TIME_Absolute now;
key_state = TEH_KS_acquire (dc.exchange_timestamp); key_state = TEH_KS_acquire (dc.exchange_timestamp);
if (NULL == key_state) if (NULL == key_state)
@ -444,12 +446,10 @@ TEH_handler_deposit (struct MHD_Connection *connection,
TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION, TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION,
"no keys"); "no keys");
} }
dki = TEH_KS_denomination_key_lookup_by_hash (key_state, dk = TEH_keys_denomination_by_hash (&deposit.coin.denom_pub_hash,
&deposit.coin.denom_pub_hash,
TEH_KS_DKU_DEPOSIT,
&ec, &ec,
&hc); &hc);
if (NULL == dki) if (NULL == dk)
{ {
TALER_LOG_DEBUG ("Unknown denomination key in /deposit request\n"); TALER_LOG_DEBUG ("Unknown denomination key in /deposit request\n");
TEH_KS_release (key_state); TEH_KS_release (key_state);
@ -459,8 +459,42 @@ TEH_handler_deposit (struct MHD_Connection *connection,
ec, ec,
NULL); NULL);
} }
TALER_amount_ntoh (&deposit.deposit_fee, now = GNUNET_TIME_absolute_get ();
&dki->issue.properties.fee_deposit); if (now.abs_value_us >= dk->meta.expire_deposit.abs_value_us)
{
/* This denomination is past the expiration time for deposits */
TEH_KS_release (key_state);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_GONE,
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
NULL);
}
if (now.abs_value_us < dk->meta.start.abs_value_us)
{
/* This denomination is not yet valid */
TEH_KS_release (key_state);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_PRECONDITION_FAILED,
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE,
NULL);
}
if (dk->recoup_possible)
{
/* This denomination has been revoked */
TEH_KS_release (key_state);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_GONE,
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED,
NULL);
}
deposit.deposit_fee = dk->meta.fee_deposit;
if (GNUNET_YES != if (GNUNET_YES !=
TALER_amount_cmp_currency (&deposit.amount_with_fee, TALER_amount_cmp_currency (&deposit.amount_with_fee,
&deposit.deposit_fee) ) &deposit.deposit_fee) )
@ -476,7 +510,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
/* check coin signature */ /* check coin signature */
if (GNUNET_YES != if (GNUNET_YES !=
TALER_test_coin_valid (&deposit.coin, TALER_test_coin_valid (&deposit.coin,
&dki->denom_pub)) &dk->denom_pub))
{ {
TALER_LOG_WARNING ("Invalid coin passed for /deposit\n"); TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
TEH_KS_release (key_state); TEH_KS_release (key_state);
@ -486,8 +520,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
TALER_EC_EXCHANGE_DENOMINATION_SIGNATURE_INVALID, TALER_EC_EXCHANGE_DENOMINATION_SIGNATURE_INVALID,
NULL); NULL);
} }
TALER_amount_ntoh (&dc.value, dc.value = dk->meta.value;
&dki->issue.properties.value);
TEH_KS_release (key_state); TEH_KS_release (key_state);
} }
if (0 < TALER_amount_cmp (&deposit.deposit_fee, if (0 < TALER_amount_cmp (&deposit.deposit_fee,

View File

@ -27,6 +27,7 @@
#include "taler_mhd_lib.h" #include "taler_mhd_lib.h"
#include "taler_signatures.h" #include "taler_signatures.h"
#include "taler-exchange-httpd_keystate.h" #include "taler-exchange-httpd_keystate.h"
#include "taler-exchange-httpd_keys.h"
#include "taler-exchange-httpd_deposits_get.h" #include "taler-exchange-httpd_deposits_get.h"
#include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd_responses.h"
@ -65,18 +66,18 @@ reply_deposit_details (struct MHD_Connection *connection,
.coin_pub = *coin_pub, .coin_pub = *coin_pub,
.execution_time = GNUNET_TIME_absolute_hton (exec_time) .execution_time = GNUNET_TIME_absolute_hton (exec_time)
}; };
enum TALER_ErrorCode ec;
TALER_amount_hton (&cw.coin_contribution, TALER_amount_hton (&cw.coin_contribution,
coin_contribution); coin_contribution);
if (GNUNET_OK != if (TALER_EC_NONE !=
TEH_KS_sign (&cw, (ec = TEH_keys_exchange_sign (&cw,
&pub, &pub,
&sig)) &sig)))
{ {
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_ec (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR, ec,
TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION, NULL);
"no keys");
} }
return TALER_MHD_reply_json_pack (connection, return TALER_MHD_reply_json_pack (connection,
MHD_HTTP_OK, MHD_HTTP_OK,

View File

@ -232,17 +232,7 @@ struct SigningKey
}; };
/** struct TEH_KeyStateHandle
* Snapshot of the (coin and signing) keys (including private keys) of
* the exchange. There can be multiple instances of this struct, as it is
* reference counted and only destroyed once the last user is done
* with it. The current instance is acquired using
* #TEH_KS_acquire(). Using this function increases the
* reference count. The contents of this structure (except for the
* reference counter) should be considered READ-ONLY until it is
* ultimately destroyed (as there can be many concurrent users).
*/
struct KeyStateHandle
{ {
/** /**
@ -307,7 +297,30 @@ struct KeyStateHandle
/** /**
* Thread-local. Contains a pointer to `struct KeyStateHandle` or NULL. * Entry of /keys requests that are currently suspended because we are
* waiting for /keys to become ready.
*/
struct SuspendedKeysRequests
{
/**
* Kept in a DLL.
*/
struct SuspendedKeysRequests *next;
/**
* Kept in a DLL.
*/
struct SuspendedKeysRequests *prev;
/**
* The suspended connection.
*/
struct MHD_Connection *connection;
};
/**
* Thread-local. Contains a pointer to `struct TEH_KeyStateHandle` or NULL.
* Stores the per-thread latest generation of our key state. * Stores the per-thread latest generation of our key state.
*/ */
static pthread_key_t key_state; static pthread_key_t key_state;
@ -321,6 +334,16 @@ static pthread_key_t key_state;
*/ */
static volatile uint64_t key_generation; static volatile uint64_t key_generation;
/**
* Head of DLL of suspended /keys requests.
*/
static struct SuspendedKeysRequests *skr_head;
/**
* Tail of DLL of suspended /keys requests.
*/
static struct SuspendedKeysRequests *skr_tail;
/** /**
* For how long should a signing key be legally retained? * For how long should a signing key be legally retained?
* Configuration value. * Configuration value.
@ -343,6 +366,73 @@ static struct TALER_SecurityModulePublicKeyP esign_sm_pub;
*/ */
static pthread_mutex_t sm_pub_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t sm_pub_mutex = PTHREAD_MUTEX_INITIALIZER;
/**
* Mutex protecting access to #skr_head and #skr_tail.
* (Could be split into two locks if ever needed.)
*/
static pthread_mutex_t skr_mutex = PTHREAD_MUTEX_INITIALIZER;
/**
* Are we shutting down?
*/
static bool terminating;
/**
* Did we ever initialize #key_state?
*/
static bool key_state_available;
/**
* Suspend /keys request while we (hopefully) are waiting to be
* provisioned with key material.
*
* @param[in] connection to suspend
*/
static MHD_RESULT
suspend_request (struct MHD_Connection *connection)
{
struct SuspendedKeysRequests *skr;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Suspending /keys request until key material changes\n");
GNUNET_assert (0 == pthread_mutex_lock (&skr_mutex));
if (terminating)
{
GNUNET_assert (0 == pthread_mutex_unlock (&skr_mutex));
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
"Exchange terminating");
}
skr = GNUNET_new (struct SuspendedKeysRequests);
skr->connection = connection;
MHD_suspend_connection (connection);
GNUNET_CONTAINER_DLL_insert (skr_head,
skr_tail,
skr);
GNUNET_assert (0 == pthread_mutex_unlock (&skr_mutex));
return MHD_YES;
}
void
TEH_resume_keys_requests (void)
{
struct SuspendedKeysRequests *skr;
GNUNET_assert (0 == pthread_mutex_lock (&skr_mutex));
while (NULL != (skr = skr_head))
{
GNUNET_CONTAINER_DLL_remove (skr_head,
skr_tail,
skr);
MHD_resume_connection (skr->connection);
GNUNET_free (skr);
}
GNUNET_assert (0 == pthread_mutex_unlock (&skr_mutex));
}
/** /**
* Clear memory for responses to "/keys" in @a ksh. * Clear memory for responses to "/keys" in @a ksh.
@ -350,7 +440,7 @@ static pthread_mutex_t sm_pub_mutex = PTHREAD_MUTEX_INITIALIZER;
* @param[in,out] ksh key state to update * @param[in,out] ksh key state to update
*/ */
static void static void
clear_response_cache (struct KeyStateHandle *ksh) clear_response_cache (struct TEH_KeyStateHandle *ksh)
{ {
for (unsigned int i = 0; i<ksh->krd_array_length; i++) for (unsigned int i = 0; i<ksh->krd_array_length; i++)
{ {
@ -530,6 +620,12 @@ helper_denom_cb (
struct HelperDenomination *hd; struct HelperDenomination *hd;
check_denom_sm_pub (sm_pub); check_denom_sm_pub (sm_pub);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"RSA helper announces key %s for denomination type %s with validity %s\n",
GNUNET_h2s (h_denom_pub),
section_name,
GNUNET_STRINGS_relative_time_to_string (validity_duration,
GNUNET_NO));
hd = GNUNET_CONTAINER_multihashmap_get (hs->denom_keys, hd = GNUNET_CONTAINER_multihashmap_get (hs->denom_keys,
h_denom_pub); h_denom_pub);
if (NULL != hd) if (NULL != hd)
@ -594,6 +690,11 @@ helper_esign_cb (
struct GNUNET_PeerIdentity pid; struct GNUNET_PeerIdentity pid;
check_esign_sm_pub (sm_pub); check_esign_sm_pub (sm_pub);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"EdDSA helper announces signing key %s with validity %s\n",
TALER_B2S (exchange_pub),
GNUNET_STRINGS_relative_time_to_string (validity_duration,
GNUNET_NO));
pid.public_key = exchange_pub->eddsa_pub; pid.public_key = exchange_pub->eddsa_pub;
hsk = GNUNET_CONTAINER_multipeermap_get (hs->esign_keys, hsk = GNUNET_CONTAINER_multipeermap_get (hs->esign_keys,
&pid); &pid);
@ -675,7 +776,7 @@ sync_key_helpers (struct HelperState *hs)
/** /**
* Free denomination key data. * Free denomination key data.
* *
* @param cls a `struct KeyStateHandle`, unused * @param cls a `struct TEH_KeyStateHandle`, unused
* @param h_denom_pub hash of the denomination public key, unused * @param h_denom_pub hash of the denomination public key, unused
* @param value a `struct TEH_DenominationKey` to free * @param value a `struct TEH_DenominationKey` to free
* @return #GNUNET_OK (continue to iterate) * @return #GNUNET_OK (continue to iterate)
@ -706,7 +807,7 @@ clear_denomination_cb (void *cls,
/** /**
* Free denomination key data. * Free denomination key data.
* *
* @param cls a `struct KeyStateHandle`, unused * @param cls a `struct TEH_KeyStateHandle`, unused
* @param h_denom_pub hash of the denomination public key, unused * @param h_denom_pub hash of the denomination public key, unused
* @param value a `struct SigningKey` to free * @param value a `struct SigningKey` to free
* @return #GNUNET_OK (continue to iterate) * @return #GNUNET_OK (continue to iterate)
@ -733,7 +834,7 @@ clear_signkey_cb (void *cls,
* @param free_helper true to also release the helper state * @param free_helper true to also release the helper state
*/ */
static void static void
destroy_key_state (struct KeyStateHandle *ksh, destroy_key_state (struct TEH_KeyStateHandle *ksh,
bool free_helper) bool free_helper)
{ {
clear_response_cache (ksh); clear_response_cache (ksh);
@ -762,12 +863,12 @@ destroy_key_state (struct KeyStateHandle *ksh,
* Free all resources associated with @a cls. Called when * Free all resources associated with @a cls. Called when
* the respective pthread is destroyed. * the respective pthread is destroyed.
* *
* @param[in] cls a `struct KeyStateHandle`. * @param[in] cls a `struct TEH_KeyStateHandle`.
*/ */
static void static void
destroy_key_state_cb (void *cls) destroy_key_state_cb (void *cls)
{ {
struct KeyStateHandle *ksh = cls; struct TEH_KeyStateHandle *ksh = cls;
destroy_key_state (ksh, destroy_key_state (ksh,
true); true);
@ -786,6 +887,7 @@ TEH_keys_init ()
pthread_key_create (&key_state, pthread_key_create (&key_state,
&destroy_key_state_cb)) &destroy_key_state_cb))
return GNUNET_SYSERR; return GNUNET_SYSERR;
key_state_available = true;
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_time (TEH_cfg, GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
"exchange", "exchange",
@ -801,21 +903,33 @@ TEH_keys_init ()
} }
/**
* Close down keys submodule.
*/
void void
TEH_keys_done () TEH_keys_done ()
{
GNUNET_assert (0 == pthread_mutex_lock (&skr_mutex));
terminating = true;
GNUNET_assert (0 == pthread_mutex_unlock (&skr_mutex));
}
/**
* Fully clean up our state.
*/
void __attribute__ ((destructor))
TEH_keys_finished ()
{
if (key_state_available)
{ {
GNUNET_assert (0 == GNUNET_assert (0 ==
pthread_key_delete (key_state)); pthread_key_delete (key_state));
} }
}
/** /**
* Function called with information about the exchange's denomination keys. * Function called with information about the exchange's denomination keys.
* *
* @param cls closure with a `struct KeyStateHandle *` * @param cls closure with a `struct TEH_KeyStateHandle *`
* @param denom_pub public key of the denomination * @param denom_pub public key of the denomination
* @param h_denom_pub hash of @a denom_pub * @param h_denom_pub hash of @a denom_pub
* @param meta meta data information about the denomination type (value, expirations, fees) * @param meta meta data information about the denomination type (value, expirations, fees)
@ -832,7 +946,7 @@ denomination_info_cb (
const struct TALER_MasterSignatureP *master_sig, const struct TALER_MasterSignatureP *master_sig,
bool recoup_possible) bool recoup_possible)
{ {
struct KeyStateHandle *ksh = cls; struct TEH_KeyStateHandle *ksh = cls;
struct TEH_DenominationKey *dk; struct TEH_DenominationKey *dk;
dk = GNUNET_new (struct TEH_DenominationKey); dk = GNUNET_new (struct TEH_DenominationKey);
@ -854,7 +968,7 @@ denomination_info_cb (
/** /**
* Function called with information about the exchange's online signing keys. * Function called with information about the exchange's online signing keys.
* *
* @param cls closure with a `struct KeyStateHandle *` * @param cls closure with a `struct TEH_KeyStateHandle *`
* @param exchange_pub the public key * @param exchange_pub the public key
* @param meta meta data information about the denomination type (expirations) * @param meta meta data information about the denomination type (expirations)
* @param master_sig master signature affirming the validity of this denomination * @param master_sig master signature affirming the validity of this denomination
@ -866,7 +980,7 @@ signkey_info_cb (
const struct TALER_EXCHANGEDB_SignkeyMetaData *meta, const struct TALER_EXCHANGEDB_SignkeyMetaData *meta,
const struct TALER_MasterSignatureP *master_sig) const struct TALER_MasterSignatureP *master_sig)
{ {
struct KeyStateHandle *ksh = cls; struct TEH_KeyStateHandle *ksh = cls;
struct SigningKey *sk; struct SigningKey *sk;
struct GNUNET_PeerIdentity pid; struct GNUNET_PeerIdentity pid;
@ -884,10 +998,66 @@ signkey_info_cb (
} }
/**
* Closure for #get_auditor_sigs.
*/
struct GetAuditorSigsContext
{
/**
* Where to store the matching signatures.
*/
json_t *denom_keys;
/**
* Public key of the auditor to match against.
*/
const struct TALER_AuditorPublicKeyP *auditor_pub;
};
/**
* Extract the auditor signatures matching the auditor's public
* key from the @a value and generate the respective JSON.
*
* @param cls a `struct GetAuditorSigsContext`
* @param h_denom_pub hash of the denomination public key
* @param value a `struct TEH_DenominationKey`
* @return #GNUNET_OK (continue to iterate)
*/
static int
get_auditor_sigs (void *cls,
const struct GNUNET_HashCode *h_denom_pub,
void *value)
{
struct GetAuditorSigsContext *ctx = cls;
struct TEH_DenominationKey *dk = value;
for (struct TEH_AuditorSignature *as = dk->as_head;
NULL != as;
as = as->next)
{
if (0 !=
GNUNET_memcmp (ctx->auditor_pub,
&as->apub))
continue;
GNUNET_break (0 ==
json_array_append_new (
ctx->denom_keys,
json_pack (
"{s:o, s:o}",
"denom_pub_h",
GNUNET_JSON_from_data_auto (h_denom_pub),
"auditor_sig",
GNUNET_JSON_from_data_auto (&as->asig))));
}
return GNUNET_OK;
}
/** /**
* Function called with information about the exchange's auditors. * Function called with information about the exchange's auditors.
* *
* @param cls closure with a `struct KeyStateHandle *` * @param cls closure with a `struct TEH_KeyStateHandle *`
* @param auditor_pub the public key of the auditor * @param auditor_pub the public key of the auditor
* @param auditor_url URL of the REST API of the auditor * @param auditor_url URL of the REST API of the auditor
* @param auditor_name human readable official name of the auditor * @param auditor_name human readable official name of the auditor
@ -899,18 +1069,26 @@ auditor_info_cb (
const char *auditor_url, const char *auditor_url,
const char *auditor_name) const char *auditor_name)
{ {
struct KeyStateHandle *ksh = cls; struct TEH_KeyStateHandle *ksh = cls;
struct GetAuditorSigsContext ctx;
ctx.denom_keys = json_array ();
ctx.auditor_pub = auditor_pub;
GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map,
&get_auditor_sigs,
&ctx);
GNUNET_break (0 == GNUNET_break (0 ==
json_array_append_new ( json_array_append_new (
ksh->auditors, ksh->auditors,
json_pack ("{s:s, s:o, s:s}", json_pack ("{s:s, s:o, s:s, s:o}",
"name", "auditor_name",
auditor_name, auditor_name,
"auditor_pub", "auditor_pub",
GNUNET_JSON_from_data_auto (auditor_pub), GNUNET_JSON_from_data_auto (auditor_pub),
"url", "auditor_url",
auditor_url))); auditor_url,
"denomination_keys",
ctx.denom_keys)));
} }
@ -918,7 +1096,7 @@ auditor_info_cb (
* Function called with information about the denominations * Function called with information about the denominations
* audited by the exchange's auditors. * audited by the exchange's auditors.
* *
* @param cls closure with a `struct KeyStateHandle *` * @param cls closure with a `struct TEH_KeyStateHandle *`
* @param auditor_pub the public key of an auditor * @param auditor_pub the public key of an auditor
* @param h_denom_pub hash of a denomination key audited by this auditor * @param h_denom_pub hash of a denomination key audited by this auditor
* @param auditor_sig signature from the auditor affirming this * @param auditor_sig signature from the auditor affirming this
@ -930,7 +1108,7 @@ auditor_denom_cb (
const struct GNUNET_HashCode *h_denom_pub, const struct GNUNET_HashCode *h_denom_pub,
const struct TALER_AuditorSignatureP *auditor_sig) const struct TALER_AuditorSignatureP *auditor_sig)
{ {
struct KeyStateHandle *ksh = cls; struct TEH_KeyStateHandle *ksh = cls;
struct TEH_DenominationKey *dk; struct TEH_DenominationKey *dk;
struct TEH_AuditorSignature *as; struct TEH_AuditorSignature *as;
@ -959,13 +1137,13 @@ auditor_denom_cb (
* @param[in] hs helper state to (re)use, NULL if not available * @param[in] hs helper state to (re)use, NULL if not available
* @return NULL on error (i.e. failed to access database) * @return NULL on error (i.e. failed to access database)
*/ */
static struct KeyStateHandle * static struct TEH_KeyStateHandle *
build_key_state (struct HelperState *hs) build_key_state (struct HelperState *hs)
{ {
struct KeyStateHandle *ksh; struct TEH_KeyStateHandle *ksh;
enum GNUNET_DB_QueryStatus qs; enum GNUNET_DB_QueryStatus qs;
ksh = GNUNET_new (struct KeyStateHandle); ksh = GNUNET_new (struct TEH_KeyStateHandle);
ksh->reload_time = GNUNET_TIME_absolute_get (); ksh->reload_time = GNUNET_TIME_absolute_get ();
GNUNET_TIME_round_abs (&ksh->reload_time); GNUNET_TIME_round_abs (&ksh->reload_time);
/* We must use the key_generation from when we STARTED the process! */ /* We must use the key_generation from when we STARTED the process! */
@ -1215,7 +1393,7 @@ get_date_string (struct GNUNET_TIME_Absolute at,
* @return #GNUNET_OK on success * @return #GNUNET_OK on success
*/ */
static int static int
setup_general_response_headers (const struct KeyStateHandle *ksh, setup_general_response_headers (const struct TEH_KeyStateHandle *ksh,
struct MHD_Response *response) struct MHD_Response *response)
{ {
char dat[128]; char dat[128];
@ -1262,9 +1440,10 @@ setup_general_response_headers (const struct KeyStateHandle *ksh,
* @param signkeys list of sign keys to return * @param signkeys list of sign keys to return
* @param recoup list of revoked keys to return * @param recoup list of revoked keys to return
* @param denoms list of denominations to return * @param denoms list of denominations to return
* @return #GNUNET_OK on success
*/ */
static void static int
create_krd (struct KeyStateHandle *ksh, create_krd (struct TEH_KeyStateHandle *ksh,
const struct GNUNET_HashCode *denom_keys_hash, const struct GNUNET_HashCode *denom_keys_hash,
struct GNUNET_TIME_Absolute last_cpd, struct GNUNET_TIME_Absolute last_cpd,
json_t *signkeys, json_t *signkeys,
@ -1284,15 +1463,23 @@ create_krd (struct KeyStateHandle *ksh,
.list_issue_date = GNUNET_TIME_absolute_hton (last_cpd), .list_issue_date = GNUNET_TIME_absolute_hton (last_cpd),
.hc = *denom_keys_hash .hc = *denom_keys_hash
}; };
enum TALER_ErrorCode ec;
TEH_keys_exchange_sign (&ks, if (TALER_EC_NONE !=
(ec = TEH_keys_exchange_sign (&ks,
&exchange_pub, &exchange_pub,
&exchange_sig); &exchange_sig)))
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Could not create key response data: cannot sign (%s)\n",
TALER_ErrorCode_get_hint (ec));
return GNUNET_SYSERR;
}
} }
keys = json_pack ( keys = json_pack (
"{s:s, s:o, s:o, s:O, s:O," "{s:s, s:o, s:o, s:O, s:O,"
" s:O, s:o, s:o, s:o, s:o}", " s:O, s:O, s:o, s:o, s:o}",
/* 1-5 */ /* 1-5 */
"version", EXCHANGE_PROTOCOL_VERSION, "version", EXCHANGE_PROTOCOL_VERSION,
"master_public_key", GNUNET_JSON_from_data_auto (&TEH_master_public_key), "master_public_key", GNUNET_JSON_from_data_auto (&TEH_master_public_key),
@ -1352,9 +1539,11 @@ create_krd (struct KeyStateHandle *ksh,
setup_general_response_headers (ksh, setup_general_response_headers (ksh,
krd.response_compressed)); krd.response_compressed));
} }
krd.cherry_pick_date = last_cpd;
GNUNET_array_append (ksh->krd_array, GNUNET_array_append (ksh->krd_array,
ksh->krd_array_length, ksh->krd_array_length,
krd); krd);
return GNUNET_OK;
} }
@ -1364,11 +1553,11 @@ create_krd (struct KeyStateHandle *ksh,
* This function is to recompute all (including cherry-picked) responses we * This function is to recompute all (including cherry-picked) responses we
* might want to return, based on the state already in @a ksh. * might want to return, based on the state already in @a ksh.
* *
*
* @param[in,out] ksh state handle to update * @param[in,out] ksh state handle to update
* @return #GNUNET_OK on success
*/ */
static void static int
update_keys_response (struct KeyStateHandle *ksh) update_keys_response (struct TEH_KeyStateHandle *ksh)
{ {
json_t *recoup; json_t *recoup;
struct SignKeyCtx sctx; struct SignKeyCtx sctx;
@ -1417,12 +1606,24 @@ update_keys_response (struct KeyStateHandle *ksh)
GNUNET_CRYPTO_hash_context_finish ( GNUNET_CRYPTO_hash_context_finish (
GNUNET_CRYPTO_hash_context_copy (hash_context), GNUNET_CRYPTO_hash_context_copy (hash_context),
&hc); &hc);
if (GNUNET_OK !=
create_krd (ksh, create_krd (ksh,
&hc, &hc,
last_cpd, last_cpd,
sctx.signkeys, sctx.signkeys,
recoup, recoup,
denoms); denoms))
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to generate key response data for %s\n",
GNUNET_STRINGS_absolute_time_to_string (last_cpd));
GNUNET_CRYPTO_hash_context_abort (hash_context);
GNUNET_CONTAINER_heap_destroy (heap);
json_decref (denoms);
json_decref (sctx.signkeys);
json_decref (recoup);
return GNUNET_SYSERR;
}
last_cpd = dk->meta.start; last_cpd = dk->meta.start;
} }
GNUNET_CRYPTO_hash_context_read (hash_context, GNUNET_CRYPTO_hash_context_read (hash_context,
@ -1468,16 +1669,28 @@ update_keys_response (struct KeyStateHandle *ksh)
GNUNET_CRYPTO_hash_context_finish (hash_context, GNUNET_CRYPTO_hash_context_finish (hash_context,
&hc); &hc);
if (GNUNET_OK !=
create_krd (ksh, create_krd (ksh,
&hc, &hc,
last_cpd, last_cpd,
sctx.signkeys, sctx.signkeys,
recoup, recoup,
denoms); denoms))
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to generate key response data for %s\n",
GNUNET_STRINGS_absolute_time_to_string (last_cpd));
json_decref (denoms);
json_decref (sctx.signkeys);
json_decref (recoup);
return GNUNET_SYSERR;
}
} }
json_decref (sctx.signkeys); json_decref (sctx.signkeys);
json_decref (recoup); json_decref (recoup);
json_decref (denoms); json_decref (denoms);
return GNUNET_OK;
} }
@ -1486,21 +1699,17 @@ TEH_keys_update_states ()
{ {
__sync_fetch_and_add (&key_generation, __sync_fetch_and_add (&key_generation,
1); 1);
TEH_resume_keys_requests ();
} }
/** struct TEH_KeyStateHandle *
* Return the current key state for this thread. Possibly re-builds the key TEH_get_key_state (void)
* state if we have reason to believe that something changed.
*
* @return NULL on error
*/
static struct KeyStateHandle *
get_key_state (void)
{ {
struct KeyStateHandle *old_ksh; struct TEH_KeyStateHandle *old_ksh;
struct KeyStateHandle *ksh; struct TEH_KeyStateHandle *ksh;
GNUNET_assert (key_state_available);
old_ksh = pthread_getspecific (key_state); old_ksh = pthread_getspecific (key_state);
if (NULL == old_ksh) if (NULL == old_ksh)
{ {
@ -1540,21 +1749,34 @@ get_key_state (void)
struct TEH_DenominationKey * struct TEH_DenominationKey *
TEH_keys_denomination_by_hash ( TEH_keys_denomination_by_hash (const struct GNUNET_HashCode *h_denom_pub,
const struct GNUNET_HashCode *h_denom_pub,
enum TALER_ErrorCode *ec, enum TALER_ErrorCode *ec,
unsigned int *hc) unsigned int *hc)
{ {
struct KeyStateHandle *ksh; struct TEH_KeyStateHandle *ksh;
struct TEH_DenominationKey *dk;
ksh = get_key_state (); ksh = TEH_get_key_state ();
if (NULL == ksh) if (NULL == ksh)
{ {
*hc = MHD_HTTP_INTERNAL_SERVER_ERROR; *hc = MHD_HTTP_INTERNAL_SERVER_ERROR;
*ec = TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING; *ec = TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
return NULL; return NULL;
} }
return TEH_keys_denomination_by_hash2 (ksh,
h_denom_pub,
ec,
hc);
}
struct TEH_DenominationKey *
TEH_keys_denomination_by_hash2 (struct TEH_KeyStateHandle *ksh,
const struct GNUNET_HashCode *h_denom_pub,
enum TALER_ErrorCode *ec,
unsigned int *hc)
{
struct TEH_DenominationKey *dk;
dk = GNUNET_CONTAINER_multihashmap_get (ksh->denomkey_map, dk = GNUNET_CONTAINER_multihashmap_get (ksh->denomkey_map,
h_denom_pub); h_denom_pub);
if (NULL == dk) if (NULL == dk)
@ -1568,16 +1790,15 @@ TEH_keys_denomination_by_hash (
struct TALER_DenominationSignature struct TALER_DenominationSignature
TEH_keys_denomination_sign ( TEH_keys_denomination_sign (const struct GNUNET_HashCode *h_denom_pub,
const struct GNUNET_HashCode *h_denom_pub,
const void *msg, const void *msg,
size_t msg_size, size_t msg_size,
enum TALER_ErrorCode *ec) enum TALER_ErrorCode *ec)
{ {
struct KeyStateHandle *ksh; struct TEH_KeyStateHandle *ksh;
struct TALER_DenominationSignature none = { NULL }; struct TALER_DenominationSignature none = { NULL };
ksh = get_key_state (); ksh = TEH_get_key_state ();
if (NULL == ksh) if (NULL == ksh)
{ {
*ec = TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING; *ec = TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
@ -1592,12 +1813,11 @@ TEH_keys_denomination_sign (
void void
TEH_keys_denomination_revoke ( TEH_keys_denomination_revoke (const struct GNUNET_HashCode *h_denom_pub)
const struct GNUNET_HashCode *h_denom_pub)
{ {
struct KeyStateHandle *ksh; struct TEH_KeyStateHandle *ksh;
ksh = get_key_state (); ksh = TEH_get_key_state ();
if (NULL == ksh) if (NULL == ksh)
{ {
GNUNET_break (0); GNUNET_break (0);
@ -1615,10 +1835,10 @@ TEH_keys_exchange_sign_ (const struct
struct TALER_ExchangePublicKeyP *pub, struct TALER_ExchangePublicKeyP *pub,
struct TALER_ExchangeSignatureP *sig) struct TALER_ExchangeSignatureP *sig)
{ {
struct KeyStateHandle *ksh; struct TEH_KeyStateHandle *ksh;
enum TALER_ErrorCode ec; enum TALER_ErrorCode ec;
ksh = get_key_state (); ksh = TEH_get_key_state ();
if (NULL == ksh) if (NULL == ksh)
{ {
/* This *can* happen if the exchange's crypto helper is not running /* This *can* happen if the exchange's crypto helper is not running
@ -1646,9 +1866,10 @@ TEH_keys_exchange_sign_ (const struct
&pid); &pid);
if (NULL == sk) if (NULL == sk)
{ {
GNUNET_break (0);
/* just to be safe, zero out the (valid) signature, as the key /* just to be safe, zero out the (valid) signature, as the key
should no longer be used */ should not or no longer be used */
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Cannot sign, offline key signatures are missing!\n");
memset (sig, memset (sig,
0, 0,
sizeof (*sig)); sizeof (*sig));
@ -1662,9 +1883,9 @@ TEH_keys_exchange_sign_ (const struct
void void
TEH_keys_exchange_revoke (const struct TALER_ExchangePublicKeyP *exchange_pub) TEH_keys_exchange_revoke (const struct TALER_ExchangePublicKeyP *exchange_pub)
{ {
struct KeyStateHandle *ksh; struct TEH_KeyStateHandle *ksh;
ksh = get_key_state (); ksh = TEH_get_key_state ();
if (NULL == ksh) if (NULL == ksh)
{ {
GNUNET_break (0); GNUNET_break (0);
@ -1742,19 +1963,19 @@ TEH_keys_get_handler (const struct TEH_RequestHandler *rh,
} }
{ {
struct KeyStateHandle *ksh; struct TEH_KeyStateHandle *ksh;
const struct KeysResponseData *krd; const struct KeysResponseData *krd;
ksh = get_key_state (); ksh = TEH_get_key_state ();
if (NULL == ksh) if (NULL == ksh)
{ {
GNUNET_break (0); return suspend_request (connection);
return TALER_MHD_reply_with_error (connection, }
MHD_HTTP_INTERNAL_SERVER_ERROR, if (GNUNET_OK !=
TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING, update_keys_response (ksh))
"no key state"); {
return suspend_request (connection);
} }
update_keys_response (ksh);
krd = bsearch (&last_issue_date, krd = bsearch (&last_issue_date,
ksh->krd_array, ksh->krd_array,
ksh->krd_array_length, ksh->krd_array_length,
@ -1927,11 +2148,11 @@ TEH_keys_load_fees (const struct GNUNET_HashCode *h_denom_pub,
struct TALER_DenominationPublicKey *denom_pub, struct TALER_DenominationPublicKey *denom_pub,
struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta) struct TALER_EXCHANGEDB_DenominationKeyMetaData *meta)
{ {
struct KeyStateHandle *ksh; struct TEH_KeyStateHandle *ksh;
struct HelperDenomination *hd; struct HelperDenomination *hd;
int ok; int ok;
ksh = get_key_state (); ksh = TEH_get_key_state ();
if (NULL == ksh) if (NULL == ksh)
{ {
GNUNET_break (0); GNUNET_break (0);
@ -1959,11 +2180,11 @@ int
TEH_keys_get_timing (const struct TALER_ExchangePublicKeyP *exchange_pub, TEH_keys_get_timing (const struct TALER_ExchangePublicKeyP *exchange_pub,
struct TALER_EXCHANGEDB_SignkeyMetaData *meta) struct TALER_EXCHANGEDB_SignkeyMetaData *meta)
{ {
struct KeyStateHandle *ksh; struct TEH_KeyStateHandle *ksh;
struct HelperSignkey *hsk; struct HelperSignkey *hsk;
struct GNUNET_PeerIdentity pid; struct GNUNET_PeerIdentity pid;
ksh = get_key_state (); ksh = TEH_get_key_state ();
if (NULL == ksh) if (NULL == ksh)
{ {
GNUNET_break (0); GNUNET_break (0);
@ -1990,7 +2211,7 @@ struct FutureBuilderContext
/** /**
* Our key state. * Our key state.
*/ */
struct KeyStateHandle *ksh; struct TEH_KeyStateHandle *ksh;
/** /**
* Array of denomination keys. * Array of denomination keys.
@ -2044,7 +2265,10 @@ add_future_denomkey_cb (void *cls,
0 == 0 ==
json_array_append_new ( json_array_append_new (
fbc->denoms, fbc->denoms,
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, s:s}",
/* 1-5 */
"value", "value",
TALER_JSON_from_amount (&meta.value), TALER_JSON_from_amount (&meta.value),
"stamp_start", "stamp_start",
@ -2055,8 +2279,9 @@ add_future_denomkey_cb (void *cls,
GNUNET_JSON_from_time_abs (meta.expire_deposit), GNUNET_JSON_from_time_abs (meta.expire_deposit),
"stamp_expire_legal", "stamp_expire_legal",
GNUNET_JSON_from_time_abs (meta.expire_legal), GNUNET_JSON_from_time_abs (meta.expire_legal),
/* 6-10 */
"denom_pub", "denom_pub",
GNUNET_JSON_from_rsa_public_key (dk->denom_pub.rsa_public_key), GNUNET_JSON_from_rsa_public_key (hd->denom_pub.rsa_public_key),
"fee_withdraw", "fee_withdraw",
TALER_JSON_from_amount (&meta.fee_withdraw), TALER_JSON_from_amount (&meta.fee_withdraw),
"fee_deposit", "fee_deposit",
@ -2065,8 +2290,11 @@ add_future_denomkey_cb (void *cls,
TALER_JSON_from_amount (&meta.fee_refresh), TALER_JSON_from_amount (&meta.fee_refresh),
"fee_refund", "fee_refund",
TALER_JSON_from_amount (&meta.fee_refund), TALER_JSON_from_amount (&meta.fee_refund),
/* 11- */
"denom_secmod_sig", "denom_secmod_sig",
GNUNET_JSON_from_data_auto (&hd->sm_sig)))); GNUNET_JSON_from_data_auto (&hd->sm_sig),
"section_name",
hd->section_name)));
return GNUNET_OK; return GNUNET_OK;
} }
@ -2123,10 +2351,10 @@ MHD_RESULT
TEH_keys_management_get_handler (const struct TEH_RequestHandler *rh, TEH_keys_management_get_handler (const struct TEH_RequestHandler *rh,
struct MHD_Connection *connection) struct MHD_Connection *connection)
{ {
struct KeyStateHandle *ksh; struct TEH_KeyStateHandle *ksh;
json_t *reply; json_t *reply;
ksh = get_key_state (); ksh = TEH_get_key_state ();
if (NULL == ksh) if (NULL == ksh)
{ {
GNUNET_break (0); GNUNET_break (0);
@ -2143,6 +2371,8 @@ TEH_keys_management_get_handler (const struct TEH_RequestHandler *rh,
.signkeys = json_array () .signkeys = json_array ()
}; };
GNUNET_assert (NULL != fbc.denoms);
GNUNET_assert (NULL != fbc.signkeys);
GNUNET_CONTAINER_multihashmap_iterate (ksh->helpers.denom_keys, GNUNET_CONTAINER_multihashmap_iterate (ksh->helpers.denom_keys,
&add_future_denomkey_cb, &add_future_denomkey_cb,
&fbc); &fbc);
@ -2161,6 +2391,11 @@ TEH_keys_management_get_handler (const struct TEH_RequestHandler *rh,
GNUNET_JSON_from_data_auto (&denom_sm_pub), GNUNET_JSON_from_data_auto (&denom_sm_pub),
"signkey_secmod_public_key", "signkey_secmod_public_key",
GNUNET_JSON_from_data_auto (&esign_sm_pub)); GNUNET_JSON_from_data_auto (&esign_sm_pub));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Returning GET /management/keys response:\n");
json_dumpf (reply,
stderr,
JSON_INDENT (2));
if (NULL == reply) if (NULL == reply)
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR, MHD_HTTP_INTERNAL_SERVER_ERROR,

View File

@ -83,6 +83,33 @@ struct TEH_DenominationKey
}; };
/**
* Snapshot of the (coin and signing) keys (including private keys) of
* the exchange. There can be multiple instances of this struct, as it is
* reference counted and only destroyed once the last user is done
* with it. The current instance is acquired using
* #TEH_KS_acquire(). Using this function increases the
* reference count. The contents of this structure (except for the
* reference counter) should be considered READ-ONLY until it is
* ultimately destroyed (as there can be many concurrent users).
*/
struct TEH_KeyStateHandle;
/**
* Return the current key state for this thread. Possibly re-builds the key
* state if we have reason to believe that something changed.
*
* The result is ONLY valid until the next call to
* #TEH_keys_denomination_by_hash() or #TEH_get_key_state()
* or #TEH_keys_exchange_sign().
*
* @return NULL on error
*/
struct TEH_KeyStateHandle *
TEH_get_key_state (void);
/** /**
* Something changed in the database. Rebuild all key states. This function * Something changed in the database. Rebuild all key states. This function
* should be called if the exchange learns about a new signature from an * should be called if the exchange learns about a new signature from an
@ -109,12 +136,30 @@ TEH_keys_update_states (void);
* or NULL if @a h_denom_pub could not be found * or NULL if @a h_denom_pub could not be found
*/ */
struct TEH_DenominationKey * struct TEH_DenominationKey *
TEH_keys_denomination_by_hash ( TEH_keys_denomination_by_hash (const struct GNUNET_HashCode *h_denom_pub,
const struct GNUNET_HashCode *h_denom_pub,
enum TALER_ErrorCode *ec, enum TALER_ErrorCode *ec,
unsigned int *hc); unsigned int *hc);
/**
* Look up the issue for a denom public key using a given @a ksh. This allows
* requesting multiple denominations with the same @a ksh which thus will
* remain valid until the next call to #TEH_keys_denomination_by_hash() or
* #TEH_get_key_state() or #TEH_keys_exchange_sign().
*
* @param key_state state to look in
* @param h_denom_pub hash of denomination public key
* @param[out] ec set to the error code, in case the operation failed
* @param[out] hc set to the HTTP status code to use
* @return the denomination key issue,
* or NULL if @a h_denom_pub could not be found
*/
struct TEH_DenominationKey *
TEH_keys_denomination_by_hash2 (struct TEH_KeyStateHandle *ksh,
const struct GNUNET_HashCode *h_denom_pub,
enum TALER_ErrorCode *ec,
unsigned int *hc);
/** /**
* Request to sign @a msg using the public key corresponding to * Request to sign @a msg using the public key corresponding to
* @a h_denom_pub. * @a h_denom_pub.
@ -127,8 +172,7 @@ TEH_keys_denomination_by_hash (
* see @a ec for details about the failure * see @a ec for details about the failure
*/ */
struct TALER_DenominationSignature struct TALER_DenominationSignature
TEH_keys_denomination_sign ( TEH_keys_denomination_sign (const struct GNUNET_HashCode *h_denom_pub,
const struct GNUNET_HashCode *h_denom_pub,
const void *msg, const void *msg,
size_t msg_size, size_t msg_size,
enum TALER_ErrorCode *ec); enum TALER_ErrorCode *ec);
@ -146,8 +190,17 @@ TEH_keys_denomination_sign (
* @param h_denom_pub hash of the public key to revoke * @param h_denom_pub hash of the public key to revoke
*/ */
void void
TEH_keys_denomination_revoke ( TEH_keys_denomination_revoke (const struct GNUNET_HashCode *h_denom_pub);
const struct GNUNET_HashCode *h_denom_pub);
/**
* Resumse all suspended /keys requests, we may now have key material
* (or are shuting down).
*
* @param[in] connection to suspend
*/
void
TEH_resume_keys_requests (void);
/** /**

View File

@ -2054,7 +2054,7 @@ TEH_KS_denomination_key_lookup_by_hash (
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Not returning DKI for %s, as time to create coins has passed\n", "Not returning DKI for %s, as time to create coins has passed\n",
GNUNET_h2s (denom_pub_hash)); GNUNET_h2s (denom_pub_hash));
*ec = TALER_EC_EXCHANGE_WITHDRAW_VALIDITY_IN_PAST; *ec = TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED;
*hc = MHD_HTTP_GONE; *hc = MHD_HTTP_GONE;
return NULL; return NULL;
} }

View File

@ -103,7 +103,8 @@ add_auditor (void *cls,
"lookup auditor"); "lookup auditor");
return qs; return qs;
} }
if (last_date.abs_value_us > aac->validity_start.abs_value_us) if ( (0 < qs) &&
(last_date.abs_value_us > aac->validity_start.abs_value_us) )
{ {
*mhd_ret = TALER_MHD_reply_with_error ( *mhd_ret = TALER_MHD_reply_with_error (
connection, connection,

View File

@ -29,6 +29,7 @@
#include "taler-exchange-httpd_management.h" #include "taler-exchange-httpd_management.h"
#include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd_responses.h"
#include "taler-exchange-httpd_keystate.h" #include "taler-exchange-httpd_keystate.h"
#include "taler-exchange-httpd_keys.h"
MHD_RESULT MHD_RESULT
@ -81,7 +82,7 @@ TEH_handler_management_denominations_HDP_revoke (
TALER_EC_GENERIC_DB_STORE_FAILED, TALER_EC_GENERIC_DB_STORE_FAILED,
"denomination revocation"); "denomination revocation");
} }
// FIXME: also update our '/keys' replies! (signal all threads!?!?) TEH_keys_update_states ();
return TALER_MHD_reply_static ( return TALER_MHD_reply_static (
connection, connection,
MHD_HTTP_NO_CONTENT, MHD_HTTP_NO_CONTENT,

View File

@ -212,6 +212,9 @@ add_keys (void *cls,
"activate denomination key"); "activate denomination key");
return qs; return qs;
} }
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Added offline signature for denomination `%s'\n",
GNUNET_h2s (&akc->d_sigs[i].h_denom_pub));
GNUNET_assert (0 != qs); GNUNET_assert (0 != qs);
} }
@ -296,9 +299,11 @@ add_keys (void *cls,
"activate signing key"); "activate signing key");
return qs; return qs;
} }
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Added offline signature for signing key `%s'\n",
TALER_B2S (&akc->s_sigs[i].exchange_pub));
GNUNET_assert (0 != qs); GNUNET_assert (0 != qs);
} }
return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; /* only 'success', so >=0, matters here */ return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; /* only 'success', so >=0, matters here */
} }
@ -382,9 +387,9 @@ TEH_handler_management_post_keys (
return ret; return ret;
} }
akc.ns_sigs = json_array_size (signkey_sigs); akc.ns_sigs = json_array_size (signkey_sigs);
akc.s_sigs = GNUNET_new_array (akc.nd_sigs, akc.s_sigs = GNUNET_new_array (akc.ns_sigs,
struct SigningSig); struct SigningSig);
for (unsigned int i = 0; i<akc.nd_sigs; i++) for (unsigned int i = 0; i<akc.ns_sigs; i++)
{ {
struct SigningSig *s = &akc.s_sigs[i]; struct SigningSig *s = &akc.s_sigs[i];
struct GNUNET_JSON_Specification ispec[] = { struct GNUNET_JSON_Specification ispec[] = {
@ -419,6 +424,10 @@ TEH_handler_management_post_keys (
GNUNET_free (akc.s_sigs); GNUNET_free (akc.s_sigs);
return ret; return ret;
} }
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Received %u denomination and %u signing key signatures\n",
akc.nd_sigs,
akc.ns_sigs);
qs = TEH_DB_run_transaction (connection, qs = TEH_DB_run_transaction (connection,
"add keys", "add keys",
&ret, &ret,
@ -426,6 +435,7 @@ TEH_handler_management_post_keys (
&akc); &akc);
if (qs < 0) if (qs < 0)
return ret; return ret;
TEH_keys_update_states ();
return TALER_MHD_reply_static ( return TALER_MHD_reply_static (
connection, connection,
MHD_HTTP_NO_CONTENT, MHD_HTTP_NO_CONTENT,

View File

@ -29,6 +29,7 @@
#include "taler-exchange-httpd_management.h" #include "taler-exchange-httpd_management.h"
#include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd_responses.h"
#include "taler-exchange-httpd_keystate.h" #include "taler-exchange-httpd_keystate.h"
#include "taler-exchange-httpd_keys.h"
MHD_RESULT MHD_RESULT
@ -80,7 +81,7 @@ TEH_handler_management_signkeys_EP_revoke (
TALER_EC_GENERIC_DB_STORE_FAILED, TALER_EC_GENERIC_DB_STORE_FAILED,
"signkey revocation"); "signkey revocation");
} }
// FIXME: also update our '/keys' replies! (signal all threads!?!?) TEH_keys_update_states ();
return TALER_MHD_reply_static ( return TALER_MHD_reply_static (
connection, connection,
MHD_HTTP_NO_CONTENT, MHD_HTTP_NO_CONTENT,

View File

@ -101,7 +101,8 @@ add_wire (void *cls,
"lookup wire"); "lookup wire");
return qs; return qs;
} }
if (last_date.abs_value_us > awc->validity_start.abs_value_us) if ( (0 < qs) &&
(last_date.abs_value_us > awc->validity_start.abs_value_us) )
{ {
*mhd_ret = TALER_MHD_reply_with_error ( *mhd_ret = TALER_MHD_reply_with_error (
connection, connection,

View File

@ -30,6 +30,7 @@
#include "taler-exchange-httpd_melt.h" #include "taler-exchange-httpd_melt.h"
#include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd_responses.h"
#include "taler-exchange-httpd_keystate.h" #include "taler-exchange-httpd_keystate.h"
#include "taler-exchange-httpd_keys.h"
/** /**
@ -107,16 +108,16 @@ reply_melt_success (struct MHD_Connection *connection,
.rc = *rc, .rc = *rc,
.noreveal_index = htonl (noreveal_index) .noreveal_index = htonl (noreveal_index)
}; };
enum TALER_ErrorCode ec;
if (GNUNET_OK != if (TALER_EC_NONE !=
TEH_KS_sign (&body, (ec = TEH_keys_exchange_sign (&body,
&pub, &pub,
&sig)) &sig)))
{ {
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_ec (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR, ec,
TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION, NULL);
"no keys");
} }
return TALER_MHD_reply_json_pack ( return TALER_MHD_reply_json_pack (
connection, connection,
@ -477,28 +478,48 @@ check_for_denomination_key (struct MHD_Connection *connection,
{ {
/* Baseline: check if deposits/refreshs are generally /* Baseline: check if deposits/refreshs are generally
simply still allowed for this denomination */ simply still allowed for this denomination */
struct TALER_EXCHANGEDB_DenominationKey *dki; struct TEH_DenominationKey *dk;
unsigned int hc; unsigned int hc;
enum TALER_ErrorCode ec; enum TALER_ErrorCode ec;
struct GNUNET_TIME_Absolute now;
dki = TEH_KS_denomination_key_lookup_by_hash ( dk = TEH_keys_denomination_by_hash (
key_state,
&rmc->refresh_session.coin.denom_pub_hash, &rmc->refresh_session.coin.denom_pub_hash,
TEH_KS_DKU_DEPOSIT,
&ec, &ec,
&hc); &hc);
/* Consider case that denomination was revoked but if (NULL == dk)
this coin was already seen and thus refresh is OK. */
if (NULL == dki)
{ {
dki = TEH_KS_denomination_key_lookup_by_hash ( TEH_KS_release (key_state);
key_state, return TALER_MHD_reply_with_error (
&rmc->refresh_session.coin.denom_pub_hash, connection,
TEH_KS_DKU_RECOUP, MHD_HTTP_NOT_FOUND,
&ec, TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN,
&hc); NULL);
if (NULL != dki) }
now = GNUNET_TIME_absolute_get ();
if (now.abs_value_us >= dk->meta.expire_legal.abs_value_us)
{ {
/* Way too late now, even zombies have expired */
TEH_KS_release (key_state);
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_GONE,
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
NULL);
}
if (now.abs_value_us < dk->meta.start.abs_value_us)
{
/* This denomination is not yet valid */
TEH_KS_release (key_state);
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_PRECONDITION_FAILED,
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE,
NULL);
}
if (now.abs_value_us >= dk->meta.expire_deposit.abs_value_us)
{
/* We are past deposit expiration time, but maybe this is a zombie? */
struct GNUNET_HashCode denom_hash; struct GNUNET_HashCode denom_hash;
enum GNUNET_DB_QueryStatus qs; enum GNUNET_DB_QueryStatus qs;
@ -527,7 +548,12 @@ check_for_denomination_key (struct MHD_Connection *connection,
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
{ {
/* We never saw this coin before, so _this_ justification is not OK */ /* We never saw this coin before, so _this_ justification is not OK */
dki = NULL; TEH_KS_release (key_state);
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_GONE,
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
NULL);
} }
else else
{ {
@ -535,36 +561,11 @@ check_for_denomination_key (struct MHD_Connection *connection,
"ensure_coin_known" part of the transaction */ "ensure_coin_known" part of the transaction */
rmc->coin_is_dirty = true; rmc->coin_is_dirty = true;
} }
}
}
/* Consider the case that the denomination expired for deposits, but
recoup of a refreshed coin refilled the balance of the 'zombie' coin
and we should thus allow the refresh during the legal period. */
if (NULL == dki)
{
dki = TEH_KS_denomination_key_lookup_by_hash (key_state,
&rmc->refresh_session.coin.
denom_pub_hash,
TEH_KS_DKU_ZOMBIE,
&ec,
&hc);
if (NULL != dki)
rmc->zombie_required = true; /* check later that zombie is satisfied */ rmc->zombie_required = true; /* check later that zombie is satisfied */
} }
if (NULL == dki)
{
TEH_KS_release (key_state);
return TALER_MHD_reply_with_error (connection,
hc,
ec,
NULL);
}
TALER_amount_ntoh (&rmc->coin_refresh_fee, rmc->coin_refresh_fee = dk->meta.fee_refresh;
&dki->issue.properties.fee_refresh); rmc->coin_value = dk->meta.value;
TALER_amount_ntoh (&rmc->coin_value,
&dki->issue.properties.value);
/* check client used sane currency */ /* check client used sane currency */
if (GNUNET_YES != if (GNUNET_YES !=
TALER_amount_cmp_currency (&rmc->refresh_session.amount_with_fee, TALER_amount_cmp_currency (&rmc->refresh_session.amount_with_fee,
@ -581,7 +582,7 @@ check_for_denomination_key (struct MHD_Connection *connection,
/* check coin is actually properly signed */ /* check coin is actually properly signed */
if (GNUNET_OK != if (GNUNET_OK !=
TALER_test_coin_valid (&rmc->refresh_session.coin, TALER_test_coin_valid (&rmc->refresh_session.coin,
&dki->denom_pub)) &dk->denom_pub))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
TEH_KS_release (key_state); TEH_KS_release (key_state);

View File

@ -31,6 +31,7 @@
#include "taler-exchange-httpd_recoup.h" #include "taler-exchange-httpd_recoup.h"
#include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd_responses.h"
#include "taler-exchange-httpd_keystate.h" #include "taler-exchange-httpd_keystate.h"
#include "taler-exchange-httpd_keys.h"
/** /**
@ -359,7 +360,7 @@ verify_and_execute_recoup (struct MHD_Connection *connection,
int refreshed) int refreshed)
{ {
struct RecoupContext pc; struct RecoupContext pc;
const struct TALER_EXCHANGEDB_DenominationKey *dki; const struct TEH_DenominationKey *dk;
struct GNUNET_HashCode c_hash; struct GNUNET_HashCode c_hash;
void *coin_ev; void *coin_ev;
size_t coin_ev_size; size_t coin_ev_size;
@ -369,6 +370,7 @@ verify_and_execute_recoup (struct MHD_Connection *connection,
/* check denomination exists and is in recoup mode */ /* check denomination exists and is in recoup mode */
{ {
struct TEH_KS_StateHandle *key_state; struct TEH_KS_StateHandle *key_state;
struct GNUNET_TIME_Absolute now;
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)
@ -379,12 +381,10 @@ verify_and_execute_recoup (struct MHD_Connection *connection,
TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION, TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION,
"no keys"); "no keys");
} }
dki = TEH_KS_denomination_key_lookup_by_hash (key_state, dk = TEH_keys_denomination_by_hash (&coin->denom_pub_hash,
&coin->denom_pub_hash,
TEH_KS_DKU_RECOUP,
&ec, &ec,
&hc); &hc);
if (NULL == dki) if (NULL == dk)
{ {
TEH_KS_release (key_state); TEH_KS_release (key_state);
TALER_LOG_WARNING ( TALER_LOG_WARNING (
@ -394,13 +394,45 @@ verify_and_execute_recoup (struct MHD_Connection *connection,
ec, ec,
NULL); NULL);
} }
TALER_amount_ntoh (&pc.value,
&dki->issue.properties.value); now = GNUNET_TIME_absolute_get ();
if (now.abs_value_us >= dk->meta.expire_deposit.abs_value_us)
{
/* This denomination is past the expiration time for recoup */
TEH_KS_release (key_state);
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_GONE,
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
NULL);
}
if (now.abs_value_us < dk->meta.start.abs_value_us)
{
/* This denomination is not yet valid */
TEH_KS_release (key_state);
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_PRECONDITION_FAILED,
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE,
NULL);
}
if (! dk->recoup_possible)
{
/* This denomination is not eligible for recoup */
TEH_KS_release (key_state);
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_NOT_FOUND,
TALER_EC_EXCHANGE_RECOUP_NOT_ELIGIBLE,
NULL);
}
pc.value = dk->meta.value;
/* check denomination signature */ /* check denomination signature */
if (GNUNET_YES != if (GNUNET_YES !=
TALER_test_coin_valid (coin, TALER_test_coin_valid (coin,
&dki->denom_pub)) &dk->denom_pub))
{ {
TALER_LOG_WARNING ("Invalid coin passed for recoup\n"); TALER_LOG_WARNING ("Invalid coin passed for recoup\n");
TEH_KS_release (key_state); TEH_KS_release (key_state);
@ -416,7 +448,7 @@ verify_and_execute_recoup (struct MHD_Connection *connection,
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP), .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP),
.purpose.size = htonl (sizeof (struct TALER_RecoupRequestPS)), .purpose.size = htonl (sizeof (struct TALER_RecoupRequestPS)),
.coin_pub = coin->coin_pub, .coin_pub = coin->coin_pub,
.h_denom_pub = dki->issue.properties.denom_hash, .h_denom_pub = coin->denom_pub_hash,
.coin_blind = *coin_bks .coin_blind = *coin_bks
}; };
@ -440,7 +472,7 @@ verify_and_execute_recoup (struct MHD_Connection *connection,
if (GNUNET_YES != if (GNUNET_YES !=
TALER_rsa_blind (&c_hash, TALER_rsa_blind (&c_hash,
&coin_bks->bks, &coin_bks->bks,
dki->denom_pub.rsa_public_key, dk->denom_pub.rsa_public_key,
&coin_ev, &coin_ev,
&coin_ev_size)) &coin_ev_size))
{ {

View File

@ -29,6 +29,7 @@
#include "taler-exchange-httpd_refreshes_reveal.h" #include "taler-exchange-httpd_refreshes_reveal.h"
#include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd_responses.h"
#include "taler-exchange-httpd_keystate.h" #include "taler-exchange-httpd_keystate.h"
#include "taler-exchange-httpd_keys.h"
/** /**
@ -132,7 +133,7 @@ struct RevealContext
/** /**
* Denominations being requested. * Denominations being requested.
*/ */
const struct TALER_EXCHANGEDB_DenominationKey **dkis; const struct TEH_DenominationKey **dks;
/** /**
* Envelopes to be signed. * Envelopes to be signed.
@ -151,7 +152,7 @@ struct RevealContext
struct TALER_DenominationSignature *ev_sigs; struct TALER_DenominationSignature *ev_sigs;
/** /**
* Size of the @e dkis, @e rcds and @e ev_sigs arrays (if non-NULL). * Size of the @e dks, @e rcds and @e ev_sigs arrays (if non-NULL).
*/ */
unsigned int num_fresh_coins; unsigned int num_fresh_coins;
@ -367,7 +368,7 @@ refreshes_reveal_transaction (void *cls,
struct TALER_PlanchetDetail pd; struct TALER_PlanchetDetail pd;
struct GNUNET_HashCode c_hash; struct GNUNET_HashCode c_hash;
rcd->dk = &rctx->dkis[j]->denom_pub; rcd->dk = &rctx->dks[j]->denom_pub;
TALER_planchet_setup_refresh (&ts, TALER_planchet_setup_refresh (&ts,
j, j,
&ps); &ps);
@ -432,18 +433,12 @@ refreshes_reveal_transaction (void *cls,
refresh_cost = melt.melt_fee; refresh_cost = melt.melt_fee;
for (unsigned int i = 0; i<rctx->num_fresh_coins; i++) for (unsigned int i = 0; i<rctx->num_fresh_coins; i++)
{ {
struct TALER_Amount fee_withdraw;
struct TALER_Amount value;
struct TALER_Amount total; struct TALER_Amount total;
TALER_amount_ntoh (&fee_withdraw,
&rctx->dkis[i]->issue.properties.fee_withdraw);
TALER_amount_ntoh (&value,
&rctx->dkis[i]->issue.properties.value);
if ( (0 > if ( (0 >
TALER_amount_add (&total, TALER_amount_add (&total,
&fee_withdraw, &rctx->dks[i]->meta.fee_withdraw,
&value)) || &rctx->dks[i]->meta.value)) ||
(0 > (0 >
TALER_amount_add (&refresh_cost, TALER_amount_add (&refresh_cost,
&refresh_cost, &refresh_cost,
@ -499,7 +494,7 @@ refreshes_reveal_persist (void *cls,
{ {
struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrc = &rrcs[i]; struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrc = &rrcs[i];
rrc->denom_pub = rctx->dkis[i]->denom_pub; rrc->denom_pub = rctx->dks[i]->denom_pub;
rrc->orig_coin_link_sig = rctx->link_sigs[i]; rrc->orig_coin_link_sig = rctx->link_sigs[i];
rrc->coin_ev = rctx->rcds[i].coin_ev; rrc->coin_ev = rctx->rcds[i].coin_ev;
rrc->coin_ev_size = rctx->rcds[i].coin_ev_size; rrc->coin_ev_size = rctx->rcds[i].coin_ev_size;
@ -546,20 +541,31 @@ resolve_refreshes_reveal_denominations (struct TEH_KS_StateHandle *key_state,
{ {
unsigned int num_fresh_coins = json_array_size (new_denoms_h_json); unsigned int num_fresh_coins = json_array_size (new_denoms_h_json);
/* We know num_fresh_coins is bounded by #MAX_FRESH_COINS, so this is safe */ /* We know num_fresh_coins is bounded by #MAX_FRESH_COINS, so this is safe */
const struct TALER_EXCHANGEDB_DenominationKey *dkis[num_fresh_coins]; const struct TEH_DenominationKey *dks[num_fresh_coins];
struct GNUNET_HashCode dki_h[num_fresh_coins]; struct GNUNET_HashCode dk_h[num_fresh_coins];
struct TALER_RefreshCoinData rcds[num_fresh_coins]; struct TALER_RefreshCoinData rcds[num_fresh_coins];
struct TALER_CoinSpendSignatureP link_sigs[num_fresh_coins]; struct TALER_CoinSpendSignatureP link_sigs[num_fresh_coins];
struct TALER_EXCHANGEDB_Melt melt; struct TALER_EXCHANGEDB_Melt melt;
enum GNUNET_GenericReturnValue res; enum GNUNET_GenericReturnValue res;
MHD_RESULT ret; MHD_RESULT ret;
struct TEH_KeyStateHandle *ksh;
struct GNUNET_TIME_Absolute now;
ksh = TEH_get_key_state ();
if (NULL == ksh)
{
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
NULL);
}
/* Parse denomination key hashes */ /* Parse denomination key hashes */
now = GNUNET_TIME_absolute_get ();
for (unsigned int i = 0; i<num_fresh_coins; i++) for (unsigned int i = 0; i<num_fresh_coins; i++)
{ {
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto (NULL, GNUNET_JSON_spec_fixed_auto (NULL,
&dki_h[i]), &dk_h[i]),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
unsigned int hc; unsigned int hc;
@ -574,21 +580,45 @@ resolve_refreshes_reveal_denominations (struct TEH_KS_StateHandle *key_state,
{ {
return (GNUNET_NO == res) ? MHD_YES : MHD_NO; return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
} }
dkis[i] = TEH_KS_denomination_key_lookup_by_hash (key_state, dks[i] = TEH_keys_denomination_by_hash2 (ksh,
&dki_h[i], &dk_h[i],
TEH_KS_DKU_WITHDRAW,
&ec, &ec,
&hc); &hc);
if (NULL == dkis[i]) if (NULL == dks[i])
{ {
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_error (connection,
hc, hc,
ec, ec,
NULL); NULL);
} }
/* #TEH_KS_DKU_WITHDRAW should warrant that we only get denomination
keys where we did not yet forget the private key */ if (now.abs_value_us >= dks[i]->meta.expire_withdraw.abs_value_us)
GNUNET_assert (NULL != dkis[i]->denom_priv.rsa_private_key); {
/* This denomination is past the expiration time for withdraws */
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_GONE,
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
NULL);
}
if (now.abs_value_us < dks[i]->meta.start.abs_value_us)
{
/* This denomination is not yet valid */
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_PRECONDITION_FAILED,
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE,
NULL);
}
if (dks[i]->recoup_possible)
{
/* This denomination has been revoked */
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_GONE,
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED,
NULL);
}
} }
/* Parse coin envelopes */ /* Parse coin envelopes */
@ -613,7 +643,7 @@ resolve_refreshes_reveal_denominations (struct TEH_KS_StateHandle *key_state,
GNUNET_free (rcds[j].coin_ev); GNUNET_free (rcds[j].coin_ev);
return (GNUNET_NO == res) ? MHD_YES : MHD_NO; return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
} }
rcd->dk = &dkis[i]->denom_pub; rcd->dk = &dks[i]->denom_pub;
} }
/* lookup old_coin_pub in database */ /* lookup old_coin_pub in database */
@ -672,7 +702,7 @@ resolve_refreshes_reveal_denominations (struct TEH_KS_StateHandle *key_state,
struct TALER_LinkDataPS ldp = { struct TALER_LinkDataPS ldp = {
.purpose.size = htonl (sizeof (ldp)), .purpose.size = htonl (sizeof (ldp)),
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_LINK), .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_LINK),
.h_denom_pub = dki_h[i], .h_denom_pub = dk_h[i],
.old_coin_pub = melt.session.coin.coin_pub, .old_coin_pub = melt.session.coin.coin_pub,
.transfer_pub = rctx->gamma_tp .transfer_pub = rctx->gamma_tp
}; };
@ -699,7 +729,7 @@ resolve_refreshes_reveal_denominations (struct TEH_KS_StateHandle *key_state,
rctx->num_fresh_coins = num_fresh_coins; rctx->num_fresh_coins = num_fresh_coins;
rctx->rcds = rcds; rctx->rcds = rcds;
rctx->dkis = dkis; rctx->dks = dks;
rctx->link_sigs = link_sigs; rctx->link_sigs = link_sigs;
/* sign _early_ (optimistic!) to keep out of transaction scope! */ /* sign _early_ (optimistic!) to keep out of transaction scope! */
@ -707,17 +737,19 @@ resolve_refreshes_reveal_denominations (struct TEH_KS_StateHandle *key_state,
struct TALER_DenominationSignature); struct TALER_DenominationSignature);
for (unsigned int i = 0; i<rctx->num_fresh_coins; i++) for (unsigned int i = 0; i<rctx->num_fresh_coins; i++)
{ {
rctx->ev_sigs[i].rsa_signature enum TALER_ErrorCode ec;
= GNUNET_CRYPTO_rsa_sign_blinded (
rctx->dkis[i]->denom_priv.rsa_private_key, rctx->ev_sigs[i]
= TEH_keys_denomination_sign (
&dk_h[i],
rctx->rcds[i].coin_ev, rctx->rcds[i].coin_ev,
rctx->rcds[i].coin_ev_size); rctx->rcds[i].coin_ev_size,
&ec);
if (NULL == rctx->ev_sigs[i].rsa_signature) if (NULL == rctx->ev_sigs[i].rsa_signature)
{ {
GNUNET_break (0); GNUNET_break (0);
ret = TALER_MHD_reply_with_error (connection, ret = TALER_MHD_reply_with_ec (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR, ec,
TALER_EC_EXCHANGE_REFRESHES_REVEAL_SIGNING_ERROR,
NULL); NULL);
goto cleanup; goto cleanup;
} }

View File

@ -33,6 +33,7 @@
#include "taler-exchange-httpd_refund.h" #include "taler-exchange-httpd_refund.h"
#include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd_responses.h"
#include "taler-exchange-httpd_keystate.h" #include "taler-exchange-httpd_keystate.h"
#include "taler-exchange-httpd_keys.h"
/** /**
@ -58,18 +59,18 @@ reply_refund_success (struct MHD_Connection *connection,
.merchant = refund->merchant_pub, .merchant = refund->merchant_pub,
.rtransaction_id = GNUNET_htonll (refund->rtransaction_id) .rtransaction_id = GNUNET_htonll (refund->rtransaction_id)
}; };
enum TALER_ErrorCode ec;
TALER_amount_hton (&rc.refund_amount, TALER_amount_hton (&rc.refund_amount,
&refund->refund_amount); &refund->refund_amount);
if (GNUNET_OK != if (TALER_EC_NONE !=
TEH_KS_sign (&rc, (ec = TEH_keys_exchange_sign (&rc,
&pub, &pub,
&sig)) &sig)))
{ {
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_ec (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR, ec,
TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION, NULL);
"no online signing key");
} }
return TALER_MHD_reply_json_pack ( return TALER_MHD_reply_json_pack (
connection, connection,
@ -460,16 +461,14 @@ verify_and_execute_refund (struct MHD_Connection *connection,
} }
/* Obtain information about the coin's denomination! */ /* Obtain information about the coin's denomination! */
{ {
struct TALER_EXCHANGEDB_DenominationKey *dki; struct TEH_DenominationKey *dk;
unsigned int hc; unsigned int hc;
enum TALER_ErrorCode ec; enum TALER_ErrorCode ec;
dki = TEH_KS_denomination_key_lookup_by_hash (key_state, dk = TEH_keys_denomination_by_hash (&denom_hash,
&denom_hash,
TEH_KS_DKU_DEPOSIT,
&ec, &ec,
&hc); &hc);
if (NULL == dki) if (NULL == dk)
{ {
/* DKI not found, but we do have a coin with this DK in our database; /* DKI not found, but we do have a coin with this DK in our database;
not good... */ not good... */
@ -480,8 +479,19 @@ verify_and_execute_refund (struct MHD_Connection *connection,
ec, ec,
NULL); NULL);
} }
TALER_amount_ntoh (&refund->details.refund_fee,
&dki->issue.properties.fee_refund); if (GNUNET_TIME_absolute_get ().abs_value_us >=
dk->meta.expire_deposit.abs_value_us)
{
/* This denomination is past the expiration time for deposits, and thus refunds */
TEH_KS_release (key_state);
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_GONE,
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
NULL);
}
refund->details.refund_fee = dk->meta.fee_refund;
} }
TEH_KS_release (key_state); TEH_KS_release (key_state);
} }

View File

@ -29,6 +29,7 @@
#include "taler_json_lib.h" #include "taler_json_lib.h"
#include "taler_mhd_lib.h" #include "taler_mhd_lib.h"
#include "taler-exchange-httpd_keystate.h" #include "taler-exchange-httpd_keystate.h"
#include "taler-exchange-httpd_keys.h"
/** /**
@ -256,8 +257,8 @@ TEH_RESPONSE_compile_transaction_history (
TALER_amount_hton (&pc.recoup_amount, TALER_amount_hton (&pc.recoup_amount,
&pr->value); &pr->value);
if (GNUNET_OK != if (TALER_EC_NONE !=
TEH_KS_sign (&pc, TEH_keys_exchange_sign (&pc,
&epub, &epub,
&esig)) &esig))
{ {
@ -309,8 +310,8 @@ TEH_RESPONSE_compile_transaction_history (
TALER_amount_hton (&pc.recoup_amount, TALER_amount_hton (&pc.recoup_amount,
&recoup->value); &recoup->value);
if (GNUNET_OK != if (TALER_EC_NONE !=
TEH_KS_sign (&pc, TEH_keys_exchange_sign (&pc,
&epub, &epub,
&esig)) &esig))
{ {
@ -366,8 +367,8 @@ TEH_RESPONSE_compile_transaction_history (
TALER_amount_hton (&pc.recoup_amount, TALER_amount_hton (&pc.recoup_amount,
&pr->value); &pr->value);
if (GNUNET_OK != if (TALER_EC_NONE !=
TEH_KS_sign (&pc, TEH_keys_exchange_sign (&pc,
&epub, &epub,
&esig)) &esig))
{ {
@ -610,8 +611,8 @@ TEH_RESPONSE_compile_reserve_history (
TALER_amount_hton (&pc.recoup_amount, TALER_amount_hton (&pc.recoup_amount,
&recoup->value); &recoup->value);
if (GNUNET_OK != if (TALER_EC_NONE !=
TEH_KS_sign (&pc, TEH_keys_exchange_sign (&pc,
&pub, &pub,
&sig)) &sig))
{ {
@ -686,8 +687,8 @@ TEH_RESPONSE_compile_reserve_history (
GNUNET_CRYPTO_hash (closing->receiver_account_details, GNUNET_CRYPTO_hash (closing->receiver_account_details,
strlen (closing->receiver_account_details) + 1, strlen (closing->receiver_account_details) + 1,
&rcc.h_wire); &rcc.h_wire);
if (GNUNET_OK != if (TALER_EC_NONE !=
TEH_KS_sign (&rcc, TEH_keys_exchange_sign (&rcc,
&pub, &pub,
&sig)) &sig))
{ {

View File

@ -24,6 +24,7 @@
#include <microhttpd.h> #include <microhttpd.h>
#include <pthread.h> #include <pthread.h>
#include "taler_signatures.h" #include "taler_signatures.h"
#include "taler-exchange-httpd_keys.h"
#include "taler-exchange-httpd_keystate.h" #include "taler-exchange-httpd_keystate.h"
#include "taler-exchange-httpd_transfers_get.h" #include "taler-exchange-httpd_transfers_get.h"
#include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd_responses.h"
@ -99,6 +100,7 @@ reply_transfer_details (struct MHD_Connection *connection,
struct TALER_ExchangePublicKeyP pub; struct TALER_ExchangePublicKeyP pub;
struct TALER_ExchangeSignatureP sig; struct TALER_ExchangeSignatureP sig;
GNUNET_TIME_round_abs (&exec_time); GNUNET_TIME_round_abs (&exec_time);
deposits = json_array (); deposits = json_array ();
if (NULL == deposits) if (NULL == deposits)
@ -158,16 +160,19 @@ reply_transfer_details (struct MHD_Connection *connection,
wdp.h_wire = *h_wire; wdp.h_wire = *h_wire;
GNUNET_CRYPTO_hash_context_finish (hash_context, GNUNET_CRYPTO_hash_context_finish (hash_context,
&wdp.h_details); &wdp.h_details);
if (GNUNET_OK != {
TEH_KS_sign (&wdp, enum TALER_ErrorCode ec;
if (TALER_EC_NONE !=
(ec = TEH_keys_exchange_sign (&wdp,
&pub, &pub,
&sig)) &sig)))
{ {
json_decref (deposits); json_decref (deposits);
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_ec (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR, ec,
TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION, NULL);
"no keys"); }
} }
return TALER_MHD_reply_json_pack (connection, return TALER_MHD_reply_json_pack (connection,

View File

@ -31,6 +31,7 @@
#include "taler-exchange-httpd_withdraw.h" #include "taler-exchange-httpd_withdraw.h"
#include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd_responses.h"
#include "taler-exchange-httpd_keystate.h" #include "taler-exchange-httpd_keystate.h"
#include "taler-exchange-httpd_keys.h"
/** /**
@ -133,11 +134,6 @@ struct WithdrawContext
*/ */
size_t blinded_msg_len; size_t blinded_msg_len;
/**
* Details about denomination we are about to withdraw.
*/
struct TALER_EXCHANGEDB_DenominationKey *dki;
/** /**
* Set to the resulting signed coin data to be returned to the client. * Set to the resulting signed coin data to be returned to the client.
*/ */
@ -291,16 +287,18 @@ withdraw_transaction (void *cls,
#if ! OPTIMISTIC_SIGN #if ! OPTIMISTIC_SIGN
if (NULL == wc->collectable.sig.rsa_signature) if (NULL == wc->collectable.sig.rsa_signature)
{ {
wc->collectable.sig.rsa_signature enum TALER_ErrorCode ec;
= GNUNET_CRYPTO_rsa_sign_blinded (wc->dki->denom_priv.rsa_private_key,
wc->collectable.sig
= TEH_keys_denomination_sign (&wc->denom_pub_hash,
wc->blinded_msg, wc->blinded_msg,
wc->blinded_msg_len); wc->blinded_msg_len,
&ec);
if (NULL == wc->collectable.sig.rsa_signature) if (NULL == wc->collectable.sig.rsa_signature)
{ {
GNUNET_break (0); GNUNET_break (0);
*mhd_ret = TALER_MHD_reply_with_error (connection, *mhd_ret = TALER_MHD_reply_with_ec (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR, ec,
TALER_EC_EXCHANGE_WITHDRAW_SIGNATURE_FAILED,
NULL); NULL);
return GNUNET_DB_STATUS_HARD_ERROR; return GNUNET_DB_STATUS_HARD_ERROR;
} }
@ -360,6 +358,8 @@ TEH_handler_withdraw (const struct TEH_RequestHandler *rh,
&wc.denom_pub_hash), &wc.denom_pub_hash),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
enum TALER_ErrorCode ec;
struct TEH_DenominationKey *dk;
(void) rh; (void) rh;
if (GNUNET_OK != if (GNUNET_OK !=
@ -397,13 +397,12 @@ TEH_handler_withdraw (const struct TEH_RequestHandler *rh,
{ {
unsigned int hc; unsigned int hc;
enum TALER_ErrorCode ec; enum TALER_ErrorCode ec;
struct GNUNET_TIME_Absolute now;
wc.dki = TEH_KS_denomination_key_lookup_by_hash (wc.key_state, dk = TEH_keys_denomination_by_hash (&wc.denom_pub_hash,
&wc.denom_pub_hash,
TEH_KS_DKU_WITHDRAW,
&ec, &ec,
&hc); &hc);
if (NULL == wc.dki) if (NULL == dk)
{ {
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
TEH_KS_release (wc.key_state); TEH_KS_release (wc.key_state);
@ -412,20 +411,47 @@ TEH_handler_withdraw (const struct TEH_RequestHandler *rh,
ec, ec,
NULL); NULL);
} }
} now = GNUNET_TIME_absolute_get ();
GNUNET_assert (NULL != wc.dki->denom_priv.rsa_private_key); if (now.abs_value_us >= dk->meta.expire_withdraw.abs_value_us)
{ {
struct TALER_Amount amount; /* This denomination is past the expiration time for withdraws */
struct TALER_Amount fee_withdraw; TEH_KS_release (wc.key_state);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_GONE,
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
NULL);
}
if (now.abs_value_us < dk->meta.start.abs_value_us)
{
/* This denomination is not yet valid */
TEH_KS_release (wc.key_state);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_PRECONDITION_FAILED,
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE,
NULL);
}
if (dk->recoup_possible)
{
/* This denomination has been revoked */
TEH_KS_release (wc.key_state);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_GONE,
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED,
NULL);
}
}
TALER_amount_ntoh (&amount, {
&wc.dki->issue.properties.value);
TALER_amount_ntoh (&fee_withdraw,
&wc.dki->issue.properties.fee_withdraw);
if (0 > if (0 >
TALER_amount_add (&wc.amount_required, TALER_amount_add (&wc.amount_required,
&amount, &dk->meta.value,
&fee_withdraw)) &dk->meta.fee_withdraw))
{ {
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
TEH_KS_release (wc.key_state); TEH_KS_release (wc.key_state);
@ -466,18 +492,18 @@ TEH_handler_withdraw (const struct TEH_RequestHandler *rh,
#if OPTIMISTIC_SIGN #if OPTIMISTIC_SIGN
/* Sign before transaction! */ /* Sign before transaction! */
wc.collectable.sig.rsa_signature wc.collectable.sig
= GNUNET_CRYPTO_rsa_sign_blinded (wc.dki->denom_priv.rsa_private_key, = TEH_keys_denomination_sign (&wc.denom_pub_hash,
wc.blinded_msg, wc.blinded_msg,
wc.blinded_msg_len); wc.blinded_msg_len,
&ec);
if (NULL == wc.collectable.sig.rsa_signature) if (NULL == wc.collectable.sig.rsa_signature)
{ {
GNUNET_break (0); GNUNET_break (0);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
TEH_KS_release (wc.key_state); TEH_KS_release (wc.key_state);
return TALER_MHD_reply_with_error (connection, return TALER_MHD_reply_with_ec (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR, ec,
TALER_EC_EXCHANGE_WITHDRAW_SIGNATURE_FAILED,
NULL); NULL);
} }
#endif #endif

View File

@ -18,6 +18,7 @@ TERMS_DIR = ../../contrib/tos
# Etag / filename for the terms of service. # Etag / filename for the terms of service.
TERMS_ETAG = 0 TERMS_ETAG = 0
SIGNKEY_LEGAL_DURATION = 2 years
# Directory with our privacy policy. # Directory with our privacy policy.
PRIVACY_DIR = ../../contrib/pp PRIVACY_DIR = ../../contrib/pp

View File

@ -20,7 +20,7 @@
# #
/ /
/agpl /agpl
/keys /seed
/robots.txt /robots.txt
/terms /terms
/privacy /privacy

View File

@ -31,10 +31,6 @@ PREFIX=
# Setup database # Setup database
taler-exchange-dbinit -c test_taler_exchange_httpd.conf &> /dev/null taler-exchange-dbinit -c test_taler_exchange_httpd.conf &> /dev/null
# Setup keys.
taler-exchange-keyup -c test_taler_exchange_httpd.conf || exit 1
# Setup wire accounts.
taler-exchange-wire -c test_taler_exchange_httpd.conf > /dev/null || exit 1
# Run Exchange HTTPD (in background) # Run Exchange HTTPD (in background)
$PREFIX taler-exchange-httpd -c test_taler_exchange_httpd.conf 2> test-exchange.log & $PREFIX taler-exchange-httpd -c test_taler_exchange_httpd.conf 2> test-exchange.log &
@ -45,7 +41,7 @@ do
echo -n "." echo -n "."
sleep 0.1 sleep 0.1
OK=1 OK=1
wget http://localhost:8081/ -o /dev/null -O /dev/null >/dev/null && break wget http://localhost:8081/seed -o /dev/null -O /dev/null >/dev/null && break
OK=0 OK=0
done done
if [ 1 != $OK ] if [ 1 != $OK ]

View File

@ -53,10 +53,6 @@ PREFIX=
# Setup database # Setup database
taler-exchange-dbinit -c test_taler_exchange_unix.conf &> /dev/null taler-exchange-dbinit -c test_taler_exchange_unix.conf &> /dev/null
# Setup keys.
taler-exchange-keyup -c test_taler_exchange_unix.conf || exit 1
# Setup wire accounts.
taler-exchange-wire -c test_taler_exchange_unix.conf > /dev/null || exit 1
# Run Exchange HTTPD (in background) # Run Exchange HTTPD (in background)
$PREFIX taler-exchange-httpd -c test_taler_exchange_unix.conf 2> test-exchange.log & $PREFIX taler-exchange-httpd -c test_taler_exchange_unix.conf 2> test-exchange.log &
@ -79,13 +75,6 @@ then
fi fi
echo " DONE" echo " DONE"
# Finally run test...
echo -n "Reloading keys ..."
kill -SIGUSR1 $!
sleep 1
curl --unix-socket "${UNIXPATH}" "http://ignored/" >/dev/null 2> /dev/null || exit_fail "SIGUSR1 killed HTTP service"
echo " DONE"
# Finally run test... # Finally run test...
echo -n "Restarting program ..." echo -n "Restarting program ..."
kill -SIGHUP $! kill -SIGHUP $!

View File

@ -15,6 +15,7 @@ TERMS_DIR = ../../contrib/tos
# Etag / filename for the terms of service. # Etag / filename for the terms of service.
TERMS_ETAG = 0 TERMS_ETAG = 0
SIGNKEY_LEGAL_DURATION = 2 years
# Directory with our privacy policy. # Directory with our privacy policy.
PRIVACY_DIR = ../../contrib/pp PRIVACY_DIR = ../../contrib/pp

View File

@ -143,6 +143,21 @@ TALER_MHD_reply_with_error (struct MHD_Connection *connection,
const char *detail); const char *detail);
/**
* Send a response indicating an error. The HTTP status code is
* to be derived from the @a ec.
*
* @param connection the MHD connection to use
* @param ec error code uniquely identifying the error
* @param detail additional optional detail about the error
* @return a MHD result code
*/
MHD_RESULT
TALER_MHD_reply_with_ec (struct MHD_Connection *connection,
enum TALER_ErrorCode ec,
const char *detail);
/** /**
* Make JSON response object. * Make JSON response object.
* *

View File

@ -442,6 +442,37 @@ TALER_MHD_reply_with_error (struct MHD_Connection *connection,
} }
/**
* Send a response indicating an error. The HTTP status code is
* to be derived from the @a ec.
*
* @param connection the MHD connection to use
* @param ec error code uniquely identifying the error
* @param detail additional optional detail about the error
* @return a MHD result code
*/
MHD_RESULT
TALER_MHD_reply_with_ec (struct MHD_Connection *connection,
enum TALER_ErrorCode ec,
const char *detail)
{
unsigned int hc = TALER_ErrorCode_get_http_status (ec);
if ( (0 == hc) ||
(UINT_MAX == hc) )
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Invalid Taler error code %d provided for response!\n",
(int) ec);
hc = MHD_HTTP_INTERNAL_SERVER_ERROR;
}
return TALER_MHD_reply_with_error (connection,
hc,
ec,
detail);
}
/** /**
* Send a response indicating that the request was too big. * Send a response indicating that the request was too big.
* *

View File

@ -131,7 +131,6 @@ check_PROGRAMS = \
test_bank_api_with_pybank \ test_bank_api_with_pybank \
test_bank_api_with_nexus \ test_bank_api_with_nexus \
test_exchange_api \ test_exchange_api \
test_exchange_api_keys_cherry_picking \
test_exchange_api_revocation \ test_exchange_api_revocation \
test_exchange_api_overlapping_keys_bug \ test_exchange_api_overlapping_keys_bug \
test_exchange_management_api \ test_exchange_management_api \
@ -144,6 +143,10 @@ if HAVE_TWISTER
test_bank_api_with_pybank_twisted test_bank_api_with_pybank_twisted
endif endif
# test_exchange_api_keys_cherry_picking disabled for now:
# needs to be rewritten as we no longer support /keys timetravel!
TESTS = \ TESTS = \
$(check_PROGRAMS) $(check_PROGRAMS)

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2014-2018 Taler Systems SA Copyright (C) 2014-2020 Taler Systems SA
TALER is free software; you can redistribute it and/or modify TALER is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as it under the terms of the GNU General Public License as
@ -630,8 +630,8 @@ run (void *cls,
TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys", TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys",
CONFIG_FILE), CONFIG_FILE),
TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys", TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
1, 2,
5 /* FIXME: wrong number... */), 270 /* FIXME: wrong number... */),
CMD_RUN_AUDITOR ("virgin-auditor"), CMD_RUN_AUDITOR ("virgin-auditor"),
TALER_TESTING_cmd_exchanges_with_url ("check-exchange", TALER_TESTING_cmd_exchanges_with_url ("check-exchange",
MHD_HTTP_OK, MHD_HTTP_OK,

View File

@ -880,11 +880,11 @@ run (void *cls,
"{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}", "{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO, GNUNET_TIME_UNIT_ZERO,
"EUR:1", "EUR:1",
MHD_HTTP_NOT_FOUND), MHD_HTTP_GONE),
/* Test deposit fails after recoup, with proof in recoup */ /* Test deposit fails after recoup, with proof in recoup */
/* Note that, the exchange will never return the coin's transaction /* Note that, the exchange will never return the coin's transaction
* history with recoup data, as we get a 404 on the DK! */ * history with recoup data, as we get a 410 on the DK! */
TALER_TESTING_cmd_deposit ("recoup-deposit-partial-after-recoup", TALER_TESTING_cmd_deposit ("recoup-deposit-partial-after-recoup",
"recoup-withdraw-coin-2a", "recoup-withdraw-coin-2a",
0, 0,
@ -892,7 +892,7 @@ run (void *cls,
"{\"items\":[{\"name\":\"extra ice cream\",\"value\":1}]}", "{\"items\":[{\"name\":\"extra ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO, GNUNET_TIME_UNIT_ZERO,
"EUR:0.5", "EUR:0.5",
MHD_HTTP_NOT_FOUND), MHD_HTTP_GONE),
/* Test that revoked coins cannot be withdrawn */ /* Test that revoked coins cannot be withdrawn */
CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-3", CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-3",
"EUR:1.01"), "EUR:1.01"),
@ -906,7 +906,7 @@ run (void *cls,
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-3-revoked", TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-3-revoked",
"recoup-create-reserve-3", "recoup-create-reserve-3",
"EUR:1", "EUR:1",
MHD_HTTP_NOT_FOUND), MHD_HTTP_GONE),
/* check that we are empty before the rejection test */ /* check that we are empty before the rejection test */
TALER_TESTING_cmd_check_bank_empty ("check-empty-again"), TALER_TESTING_cmd_check_bank_empty ("check-empty-again"),
@ -958,7 +958,7 @@ run (void *cls,
CONFIG_FILE), CONFIG_FILE),
TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys", TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
1, 1,
5 /* FIXME: wrong number... */), 270 /* FIXME: wrong number... */),
TALER_TESTING_cmd_batch ("wire", TALER_TESTING_cmd_batch ("wire",
wire), wire),
TALER_TESTING_cmd_batch ("withdraw", TALER_TESTING_cmd_batch ("withdraw",

View File

@ -129,8 +129,8 @@ run (void *cls,
* Make sure we have the same keys situation as * Make sure we have the same keys situation as
* it was before the serialization. * it was before the serialization.
*/ */
TALER_TESTING_cmd_check_keys_with_now TALER_TESTING_cmd_check_keys_with_now (
("check-keys-after-deserialization", "check-keys-after-deserialization",
4, 4,
NDKS_RIGHT_BEFORE_SERIALIZATION, NDKS_RIGHT_BEFORE_SERIALIZATION,
/** /**
@ -198,8 +198,8 @@ run (void *cls,
* ---- * ----
* 40 * 40
*/// *///
TALER_TESTING_cmd_check_keys_with_now TALER_TESTING_cmd_check_keys_with_now (
("check-keys-3", "check-keys-3",
3 /* generation */, 3 /* generation */,
NDKS_RIGHT_BEFORE_SERIALIZATION, NDKS_RIGHT_BEFORE_SERIALIZATION,
TTH_parse_time (JAN2030)), TTH_parse_time (JAN2030)),

View File

@ -73,7 +73,7 @@ run (void *cls,
CONFIG_FILE), CONFIG_FILE),
TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys", TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
1, 1,
5 /* FIXME: wrong number... */), 270 /* FIXME: wrong number... */),
/** /**
* Fill reserve with EUR:10.02, as withdraw fee is 1 ct per * Fill reserve with EUR:10.02, as withdraw fee is 1 ct per
* config. * config.

View File

@ -222,7 +222,7 @@ run (void *cls,
TALER_TESTING_cmd_check_keys_pull_all_keys ( TALER_TESTING_cmd_check_keys_pull_all_keys (
"check-keys-expiration-0", "check-keys-expiration-0",
2, 2,
5), 270),
/** /**
* Run some normal commands after this to make sure everything is fine. * Run some normal commands after this to make sure everything is fine.
*/ */
@ -237,6 +237,15 @@ run (void *cls,
}; };
struct TALER_TESTING_Command commands[] = { struct TALER_TESTING_Command commands[] = {
TALER_TESTING_cmd_wire_add ("add-wire-account",
"payto://x-taler-bank/localhost/2",
MHD_HTTP_NO_CONTENT,
false),
TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys",
CONFIG_FILE),
TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
1,
270 /* FIXME: wrong number... */),
TALER_TESTING_cmd_batch ("refresh-reveal-409-conflict", TALER_TESTING_cmd_batch ("refresh-reveal-409-conflict",
refresh_409_conflict), refresh_409_conflict),
TALER_TESTING_cmd_batch ("refund", TALER_TESTING_cmd_batch ("refund",

View File

@ -144,7 +144,7 @@ run (void *cls,
CONFIG_FILE), CONFIG_FILE),
TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys", TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
1, 1,
5 /* FIXME: wrong number... */), 270 /* FIXME: wrong number... */),
TALER_TESTING_cmd_end () TALER_TESTING_cmd_end ()
}; };

View File

@ -93,7 +93,7 @@ run (void *cls,
config_filename), config_filename),
TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys", TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
1, 1,
5 /* FIXME: wrong number... */), 58 /* FIXME: wrong number... */),
TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-on-start"), TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-on-start"),
CMD_EXEC_AGGREGATOR ("run-aggregator-on-empty"), CMD_EXEC_AGGREGATOR ("run-aggregator-on-empty"),
TALER_TESTING_cmd_exec_wirewatch ("run-wirewatch-on-empty", TALER_TESTING_cmd_exec_wirewatch ("run-wirewatch-on-empty",

View File

@ -70,6 +70,7 @@ offlinesign_run (void *cls,
"taler-exchange-offline", "taler-exchange-offline",
"taler-exchange-offline", "taler-exchange-offline",
"-c", ks->config_filename, "-c", ks->config_filename,
"-L", "INFO",
"download", "download",
"sign", "sign",
"upload", "upload",
@ -80,8 +81,6 @@ offlinesign_run (void *cls,
TALER_TESTING_interpreter_fail (is); TALER_TESTING_interpreter_fail (is);
return; return;
} }
/* This function does not tell whether the command
* succeeded or not! */
TALER_TESTING_wait_for_sigchld (is); TALER_TESTING_wait_for_sigchld (is);
} }

View File

@ -79,8 +79,9 @@ revoke_cleanup (void *cls,
if (NULL != rs->revoke_proc) if (NULL != rs->revoke_proc)
{ {
GNUNET_break (0 == GNUNET_OS_process_kill GNUNET_break (0 ==
(rs->revoke_proc, SIGKILL)); GNUNET_OS_process_kill (rs->revoke_proc,
SIGKILL));
GNUNET_OS_process_wait (rs->revoke_proc); GNUNET_OS_process_wait (rs->revoke_proc);
GNUNET_OS_process_destroy (rs->revoke_proc); GNUNET_OS_process_destroy (rs->revoke_proc);
rs->revoke_proc = NULL; rs->revoke_proc = NULL;
@ -163,13 +164,13 @@ revoke_run (void *cls,
rs->dhks = GNUNET_STRINGS_data_to_string_alloc ( rs->dhks = GNUNET_STRINGS_data_to_string_alloc (
&denom_pub->h_key, &denom_pub->h_key,
sizeof (struct GNUNET_HashCode)); sizeof (struct GNUNET_HashCode));
rs->revoke_proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL, rs->revoke_proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
NULL, NULL, NULL, NULL, NULL, NULL,
"taler-exchange-keyup", "taler-exchange-offline",
"taler-exchange-keyup", "taler-exchange-offline",
"-c", rs->config_filename, "-c", rs->config_filename,
"-r", rs->dhks, "revoke-denomination", rs->dhks,
"upload",
NULL); NULL);
if (NULL == rs->revoke_proc) if (NULL == rs->revoke_proc)

View File

@ -617,7 +617,7 @@ TALER_TESTING_wait_exchange_ready (const char *base_url)
unsigned int iter; unsigned int iter;
GNUNET_asprintf (&wget_cmd, GNUNET_asprintf (&wget_cmd,
"wget -q -t 1 -T 1 %skeys -o /dev/null -O /dev/null", "wget -q -t 1 -T 1 %sseed -o /dev/null -O /dev/null",
base_url); // make sure ends with '/' base_url); // make sure ends with '/'
/* give child time to start and bind against the socket */ /* give child time to start and bind against the socket */
fprintf (stderr, fprintf (stderr,

View File

@ -388,24 +388,25 @@ maint_child_death (void *cls)
struct TALER_TESTING_Interpreter *is = cls; struct TALER_TESTING_Interpreter *is = cls;
struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
const struct GNUNET_DISK_FileHandle *pr; const struct GNUNET_DISK_FileHandle *pr;
struct GNUNET_OS_Process **processp; struct GNUNET_OS_Process **processp;
char c[16]; char c[16];
enum GNUNET_OS_ProcessStatusType type;
unsigned long code;
if (TALER_TESTING_cmd_is_batch (cmd)) if (TALER_TESTING_cmd_is_batch (cmd))
{ {
struct TALER_TESTING_Command *batch_cmd; struct TALER_TESTING_Command *batch_cmd;
GNUNET_assert GNUNET_assert (GNUNET_OK ==
(GNUNET_OK == TALER_TESTING_get_trait_cmd TALER_TESTING_get_trait_cmd (cmd,
(cmd, 0, &batch_cmd)); /* bad? */ 0,
&batch_cmd));
cmd = batch_cmd; cmd = batch_cmd;
} }
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Got SIGCHLD for `%s'.\n", "Got SIGCHLD for `%s'.\n",
cmd->label); cmd->label);
is->child_death_task = NULL; is->child_death_task = NULL;
pr = GNUNET_DISK_pipe_handle (sigpipe, pr = GNUNET_DISK_pipe_handle (sigpipe,
GNUNET_DISK_PIPE_END_READ); GNUNET_DISK_PIPE_END_READ);
@ -424,16 +425,45 @@ maint_child_death (void *cls)
} }
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Got the dead child process handle" "Got the dead child process handle, waiting for termination ...\n");
", waiting for termination ...\n"); GNUNET_OS_process_wait_status (*processp,
&type,
GNUNET_OS_process_wait (*processp); &code);
GNUNET_OS_process_destroy (*processp); GNUNET_OS_process_destroy (*processp);
*processp = NULL; *processp = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"... definitively terminated\n"); "... definitively terminated\n");
switch (type)
{
case GNUNET_OS_PROCESS_UNKNOWN:
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
case GNUNET_OS_PROCESS_RUNNING:
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
case GNUNET_OS_PROCESS_STOPPED:
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
case GNUNET_OS_PROCESS_EXITED:
if (0 != code)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Process exited with unexpected status %u\n",
(unsigned int) code);
TALER_TESTING_interpreter_fail (is);
return;
}
break;
case GNUNET_OS_PROCESS_SIGNALED:
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
// FIXME: remove reload_keys, obsolete!
if (GNUNET_OK == is->reload_keys) if (GNUNET_OK == is->reload_keys)
{ {
if (NULL == is->exchanged) if (NULL == is->exchanged)
@ -444,8 +474,9 @@ maint_child_death (void *cls)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Triggering key state reload at exchange\n"); "Triggering key state reload at exchange\n");
GNUNET_break (0 == GNUNET_OS_process_kill GNUNET_break (0 ==
(is->exchanged, SIGUSR1)); GNUNET_OS_process_kill (is->exchanged,
SIGUSR1));
sleep (5); /* make sure signal was received and processed */ sleep (5); /* make sure signal was received and processed */
} }
} }
@ -643,19 +674,8 @@ TALER_TESTING_cert_cb (void *cls,
* the interpreter is already running. */ * the interpreter is already running. */
if (GNUNET_YES == is->working) if (GNUNET_YES == is->working)
return; return;
is->working = GNUNET_YES; is->working = GNUNET_YES;
/* Trigger the next command. */
/* Very first start of tests, call "run()" */
if (1 == is->key_generation)
{
main_ctx->main_cb (main_ctx->main_cb_cls,
is);
return;
}
/* Tests already started, just trigger the
* next command. */
TALER_LOG_DEBUG ("Cert_cb, scheduling CMD (ip: %d)\n", TALER_LOG_DEBUG ("Cert_cb, scheduling CMD (ip: %d)\n",
is->ip); is->ip);
GNUNET_SCHEDULER_add_now (&interpreter_run, GNUNET_SCHEDULER_add_now (&interpreter_run,
@ -740,6 +760,7 @@ main_wrapper_exchange_connect (void *cls)
main_ctx->exchange_url = exchange_url; main_ctx->exchange_url = exchange_url;
is->timeout_task = GNUNET_SCHEDULER_add_shutdown (&do_abort, is->timeout_task = GNUNET_SCHEDULER_add_shutdown (&do_abort,
main_ctx); main_ctx);
is->working = GNUNET_YES;
GNUNET_break GNUNET_break
(NULL != (is->exchange = (NULL != (is->exchange =
TALER_EXCHANGE_connect (is->ctx, TALER_EXCHANGE_connect (is->ctx,
@ -747,6 +768,10 @@ main_wrapper_exchange_connect (void *cls)
&TALER_TESTING_cert_cb, &TALER_TESTING_cert_cb,
main_ctx, main_ctx,
TALER_EXCHANGE_OPTION_END))); TALER_EXCHANGE_OPTION_END)));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Starting main test loop\n");
main_ctx->main_cb (main_ctx->main_cb_cls,
is);
} }
@ -842,7 +867,7 @@ static int
load_urls (struct TALER_TESTING_Interpreter *is) load_urls (struct TALER_TESTING_Interpreter *is)
{ {
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_filename (is->cfg, GNUNET_CONFIGURATION_get_value_string (is->cfg,
"auditor", "auditor",
"BASE_URL", "BASE_URL",
&is->auditor_url)) &is->auditor_url))

View File

@ -1112,17 +1112,16 @@ read_job (void *cls)
* Create a new denomination key (we do not have enough). * Create a new denomination key (we do not have enough).
* *
* @param denom denomination key to create * @param denom denomination key to create
* @param now current time to use (to get many keys to use the exact same time)
* @return #GNUNET_OK on success * @return #GNUNET_OK on success
*/ */
static int static int
create_key (struct Denomination *denom) create_key (struct Denomination *denom,
struct GNUNET_TIME_Absolute now)
{ {
struct DenominationKey *dk; struct DenominationKey *dk;
struct GNUNET_TIME_Absolute anchor; struct GNUNET_TIME_Absolute anchor;
struct GNUNET_TIME_Absolute now;
now = GNUNET_TIME_absolute_get ();
(void) GNUNET_TIME_round_abs (&now);
if (NULL == denom->keys_tail) if (NULL == denom->keys_tail)
{ {
anchor = now; anchor = now;
@ -1237,9 +1236,11 @@ purge_key (struct DenominationKey *dk)
* correct location sorted by next maintenance activity. * correct location sorted by next maintenance activity.
* *
* @param[in,out] denom denomination to update material for * @param[in,out] denom denomination to update material for
* @param now current time to use (to get many keys to use the exact same time)
*/ */
static void static void
update_keys (struct Denomination *denom) update_keys (struct Denomination *denom,
struct GNUNET_TIME_Absolute now)
{ {
/* create new denomination keys */ /* create new denomination keys */
while ( (NULL == denom->keys_tail) || while ( (NULL == denom->keys_tail) ||
@ -1252,7 +1253,8 @@ update_keys (struct Denomination *denom)
lookahead_sign), lookahead_sign),
overlap_duration)).rel_value_us) ) overlap_duration)).rel_value_us) )
if (GNUNET_OK != if (GNUNET_OK !=
create_key (denom)) create_key (denom,
now))
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to create keys for `%s'\n", "Failed to create keys for `%s'\n",
@ -1273,18 +1275,19 @@ update_keys (struct Denomination *denom)
struct GNUNET_TIME_Absolute at; struct GNUNET_TIME_Absolute at;
at = denomination_action_time (denom); at = denomination_action_time (denom);
before = NULL;
GNUNET_CONTAINER_DLL_remove (denom_head, GNUNET_CONTAINER_DLL_remove (denom_head,
denom_tail, denom_tail,
denom); denom);
before = NULL;
for (struct Denomination *pos = denom_head; for (struct Denomination *pos = denom_head;
NULL != pos; NULL != pos;
pos = pos->next) pos = pos->next)
{ {
if (denomination_action_time (pos).abs_value_us > at.abs_value_us) if (denomination_action_time (pos).abs_value_us >= at.abs_value_us)
break; break;
before = pos; before = pos;
} }
GNUNET_CONTAINER_DLL_insert_after (denom_head, GNUNET_CONTAINER_DLL_insert_after (denom_head,
denom_tail, denom_tail,
before, before,
@ -1302,12 +1305,16 @@ static void
update_denominations (void *cls) update_denominations (void *cls)
{ {
struct Denomination *denom; struct Denomination *denom;
struct GNUNET_TIME_Absolute now;
(void) cls; (void) cls;
now = GNUNET_TIME_absolute_get ();
(void) GNUNET_TIME_round_abs (&now);
keygen_task = NULL; keygen_task = NULL;
do { do {
denom = denom_head; denom = denom_head;
update_keys (denom); update_keys (denom,
now);
} while (denom != denom_head); } while (denom != denom_head);
keygen_task = GNUNET_SCHEDULER_add_at (denomination_action_time (denom), keygen_task = GNUNET_SCHEDULER_add_at (denomination_action_time (denom),
&update_denominations, &update_denominations,
@ -1609,18 +1616,35 @@ parse_denomination_cfg (const char *ct,
} }
/**
* Closure for #load_denominations.
*/
struct LoadContext
{
/**
* Current time to use.
*/
struct GNUNET_TIME_Absolute now;
/**
* Status, to be set to #GNUNET_SYSERR on failure
*/
int ret;
};
/** /**
* Generate new denomination signing keys for the denomination type of the given @a * Generate new denomination signing keys for the denomination type of the given @a
* denomination_alias. * denomination_alias.
* *
* @param cls a `int *`, to be set to #GNUNET_SYSERR on failure * @param cls a `struct LoadContext`, with 'ret' to be set to #GNUNET_SYSERR on failure
* @param denomination_alias name of the denomination's section in the configuration * @param denomination_alias name of the denomination's section in the configuration
*/ */
static void static void
load_denominations (void *cls, load_denominations (void *cls,
const char *denomination_alias) const char *denomination_alias)
{ {
int *ret = cls; struct LoadContext *ctx = cls;
struct Denomination *denom; struct Denomination *denom;
if (0 != strncasecmp (denomination_alias, if (0 != strncasecmp (denomination_alias,
@ -1632,7 +1656,7 @@ load_denominations (void *cls,
parse_denomination_cfg (denomination_alias, parse_denomination_cfg (denomination_alias,
denom)) denom))
{ {
*ret = GNUNET_SYSERR; ctx->ret = GNUNET_SYSERR;
GNUNET_free (denom); GNUNET_free (denom);
return; return;
} }
@ -1656,7 +1680,8 @@ load_denominations (void *cls,
GNUNET_CONTAINER_DLL_insert (denom_head, GNUNET_CONTAINER_DLL_insert (denom_head,
denom_tail, denom_tail,
denom); denom);
update_keys (denom); update_keys (denom,
ctx->now);
} }
@ -1905,13 +1930,16 @@ run (void *cls,
keys = GNUNET_CONTAINER_multihashmap_create (65536, keys = GNUNET_CONTAINER_multihashmap_create (65536,
GNUNET_YES); GNUNET_YES);
{ {
int ok; struct LoadContext lc = {
.ret = GNUNET_OK,
.now = GNUNET_TIME_absolute_get ()
};
ok = GNUNET_OK; (void) GNUNET_TIME_round_abs (&lc.now);
GNUNET_CONFIGURATION_iterate_sections (kcfg, GNUNET_CONFIGURATION_iterate_sections (kcfg,
&load_denominations, &load_denominations,
&ok); &lc);
if (GNUNET_OK != ok) if (GNUNET_OK != lc.ret)
{ {
global_ret = 4; global_ret = 4;
GNUNET_SCHEDULER_shutdown (); GNUNET_SCHEDULER_shutdown ();