summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2020-12-14 15:42:32 +0100
committerChristian Grothoff <christian@grothoff.org>2020-12-14 15:42:32 +0100
commitb5d88fc2d1832fd27bdd7df0860c07ae3c61312c (patch)
treebc279533511c65d9f5dabdb1d03d7ee0bf156888
parent468fc9d1a1bcf3eb771519a746c5e3218ee121e3 (diff)
downloadexchange-b5d88fc2d1832fd27bdd7df0860c07ae3c61312c.tar.gz
exchange-b5d88fc2d1832fd27bdd7df0860c07ae3c61312c.tar.bz2
exchange-b5d88fc2d1832fd27bdd7df0860c07ae3c61312c.zip
activating implementation of #6175
m---------contrib/gana0
-rwxr-xr-xcontrib/gana-update.sh6
-rwxr-xr-xsrc/auditor/generate-auditor-basedb.sh5
-rwxr-xr-xsrc/auditor/generate-revoke-basedb.sh5
-rw-r--r--src/exchange/taler-exchange-httpd.c26
-rw-r--r--src/exchange/taler-exchange-httpd.h5
-rw-r--r--src/exchange/taler-exchange-httpd_deposit.c73
-rw-r--r--src/exchange/taler-exchange-httpd_deposits_get.c17
-rw-r--r--src/exchange/taler-exchange-httpd_keys.c459
-rw-r--r--src/exchange/taler-exchange-httpd_keys.h75
-rw-r--r--src/exchange/taler-exchange-httpd_keystate.c2
-rw-r--r--src/exchange/taler-exchange-httpd_management_auditors.c3
-rw-r--r--src/exchange/taler-exchange-httpd_management_denominations_HDP_revoke.c3
-rw-r--r--src/exchange/taler-exchange-httpd_management_post_keys.c16
-rw-r--r--src/exchange/taler-exchange-httpd_management_signkey_EP_revoke.c3
-rw-r--r--src/exchange/taler-exchange-httpd_management_wire.c3
-rw-r--r--src/exchange/taler-exchange-httpd_melt.c167
-rw-r--r--src/exchange/taler-exchange-httpd_recoup.c56
-rw-r--r--src/exchange/taler-exchange-httpd_refreshes_reveal.c102
-rw-r--r--src/exchange/taler-exchange-httpd_refund.c44
-rw-r--r--src/exchange/taler-exchange-httpd_responses.c41
-rw-r--r--src/exchange/taler-exchange-httpd_transfers_get.c23
-rw-r--r--src/exchange/taler-exchange-httpd_withdraw.c100
-rw-r--r--src/exchange/test_taler_exchange_httpd.conf1
-rw-r--r--src/exchange/test_taler_exchange_httpd.get2
-rwxr-xr-xsrc/exchange/test_taler_exchange_httpd.sh6
-rwxr-xr-xsrc/exchange/test_taler_exchange_httpd_restart.sh11
-rw-r--r--src/exchange/test_taler_exchange_unix.conf1
-rw-r--r--src/include/taler_mhd_lib.h15
-rw-r--r--src/mhd/mhd_responses.c31
-rw-r--r--src/testing/Makefile.am5
-rw-r--r--src/testing/test_auditor_api.c6
-rw-r--r--src/testing/test_exchange_api.c10
-rw-r--r--src/testing/test_exchange_api_keys_cherry_picking.c8
-rw-r--r--src/testing/test_exchange_api_revocation.c2
-rw-r--r--src/testing/test_exchange_api_twisted.c11
-rw-r--r--src/testing/test_exchange_management_api.c2
-rw-r--r--src/testing/test_taler_exchange_wirewatch.c2
-rw-r--r--src/testing/testing_api_cmd_offline_sign_keys.c3
-rw-r--r--src/testing/testing_api_cmd_revoke.c13
-rw-r--r--src/testing/testing_api_helpers_exchange.c2
-rw-r--r--src/testing/testing_api_loop.c81
-rw-r--r--src/util/taler-helper-crypto-rsa.c62
43 files changed, 1037 insertions, 471 deletions
diff --git a/contrib/gana b/contrib/gana
-Subproject 3501eb7b857d573258c1ab1c42d7e827c36cec9
+Subproject 912dc84dc52a1291b635e19da32c7c824719f8d
diff --git a/contrib/gana-update.sh b/contrib/gana-update.sh
index a5da6f1b1..196d4b530 100755
--- a/contrib/gana-update.sh
+++ b/contrib/gana-update.sh
@@ -10,9 +10,9 @@ make
cd ../../..
if ! diff contrib/gana/gnu-taler-error-codes/taler_error_codes.h src/include/taler_error_codes.h > /dev/null
then
- echo "Deploying latest new GANA database..."
cp contrib/gana/gnu-taler-error-codes/taler_error_codes.h src/include/taler_error_codes.h
+fi
+if ! diff contrib/gana/gnu-taler-error-codes/taler_error_codes.c src/util/taler_error_codes.c > /dev/null
+then
cp contrib/gana/gnu-taler-error-codes/taler_error_codes.c src/util/taler_error_codes.c
-else
- echo "GANA database already up-to-date"
fi
diff --git a/src/auditor/generate-auditor-basedb.sh b/src/auditor/generate-auditor-basedb.sh
index 86e8fe2ec..c41d4a982 100755
--- a/src/auditor/generate-auditor-basedb.sh
+++ b/src/auditor/generate-auditor-basedb.sh
@@ -116,6 +116,11 @@ mv a2e.dat $ABD
# Launch services
echo "Launching services"
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-merchant-httpd -c $CONF -L INFO 2> taler-merchant-httpd.log &
taler-exchange-wirewatch -c $CONF 2> taler-exchange-wirewatch.log &
diff --git a/src/auditor/generate-revoke-basedb.sh b/src/auditor/generate-revoke-basedb.sh
index ef77e4d7d..3874e349b 100755
--- a/src/auditor/generate-revoke-basedb.sh
+++ b/src/auditor/generate-revoke-basedb.sh
@@ -104,6 +104,11 @@ mv a2e.dat $ABD
# Launch services
echo "Launching services"
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 &
EXCHANGE_PID=$!
taler-merchant-httpd -c $CONF -L INFO 2> taler-merchant-httpd.log &
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
index d9c565406..8ee82ce19 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -562,8 +562,8 @@ handle_post_management (const struct TEH_RequestHandler *rh,
return r404 (connection,
"/management/denominations/$HDP/revoke");
if (GNUNET_OK !=
- GNUNET_STRINGS_string_to_data (args[2],
- strlen (args[2]),
+ GNUNET_STRINGS_string_to_data (args[1],
+ strlen (args[1]),
&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,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
- args[2]);
+ args[1]);
}
return TEH_handler_management_denominations_HDP_revoke (connection,
&h_denom_pub,
@@ -591,8 +591,8 @@ handle_post_management (const struct TEH_RequestHandler *rh,
return r404 (connection,
"/management/signkeys/$HDP/revoke");
if (GNUNET_OK !=
- GNUNET_STRINGS_string_to_data (args[2],
- strlen (args[2]),
+ GNUNET_STRINGS_string_to_data (args[1],
+ strlen (args[1]),
&exchange_pub,
sizeof (exchange_pub)))
{
@@ -600,7 +600,7 @@ handle_post_management (const struct TEH_RequestHandler *rh,
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
- args[2]);
+ args[1]);
}
return TEH_handler_management_signkeys_EP_revoke (connection,
&exchange_pub,
@@ -805,7 +805,7 @@ handle_mhd_request (void *cls,
{
.url = "keys",
.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 */
{
@@ -1427,6 +1427,7 @@ run_single_request (void)
}
MHD_run (mhd);
}
+ TEH_resume_keys_requests ();
MHD_stop_daemon (mhd);
mhd = NULL;
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_USE_DEBUG | MHD_USE_DUAL_STACK
| MHD_USE_INTERNAL_POLLING_THREAD
+ | MHD_ALLOW_SUSPEND_RESUME
| MHD_USE_TCP_FASTOPEN,
(-1 == fh) ? serve_port : 0,
NULL, NULL,
@@ -1484,11 +1486,17 @@ run_main_loop (int fh,
}
atexit (&write_stats);
- ret = TEH_KS_loop ();
+ ret = TEH_keys_init ();
+ if (GNUNET_OK == ret)
+ {
+ ret = TEH_KS_loop ();
+ TEH_keys_done ();
+ }
switch (ret)
{
case GNUNET_OK:
case GNUNET_SYSERR:
+ TEH_resume_keys_requests ();
MHD_stop_daemon (mhd);
break;
case GNUNET_NO:
@@ -1544,11 +1552,13 @@ run_main_loop (int fh,
num_connections)
sleep (1);
/* Now we're really done, practice clean shutdown */
+ TEH_resume_keys_requests ();
MHD_stop_daemon (mhd);
}
break;
default:
GNUNET_break (0);
+ TEH_resume_keys_requests ();
MHD_stop_daemon (mhd);
break;
}
diff --git a/src/exchange/taler-exchange-httpd.h b/src/exchange/taler-exchange-httpd.h
index 316e565b6..497ff16a7 100644
--- a/src/exchange/taler-exchange-httpd.h
+++ b/src/exchange/taler-exchange-httpd.h
@@ -79,6 +79,11 @@ extern struct TALER_EXCHANGEDB_Plugin *TEH_plugin;
extern char *TEH_currency;
/**
+ * Are we shutting down?
+ */
+extern volatile bool MHD_terminating;
+
+/**
* @brief Struct describing an URL and the handler for it.
*/
struct TEH_RequestHandler
diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c
index bd38c6256..e8ca04f8c 100644
--- a/src/exchange/taler-exchange-httpd_deposit.c
+++ b/src/exchange/taler-exchange-httpd_deposit.c
@@ -33,6 +33,7 @@
#include "taler-exchange-httpd_deposit.h"
#include "taler-exchange-httpd_responses.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,
.merchant = *merchant
};
+ enum TALER_ErrorCode ec;
TALER_amount_hton (&dc.amount_without_fee,
amount_without_fee);
- if (GNUNET_OK !=
- TEH_KS_sign (&dc,
- &pub,
- &sig))
+ if (TALER_EC_NONE !=
+ (ec = TEH_keys_exchange_sign (&dc,
+ &pub,
+ &sig)))
{
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION,
- "no keys");
+ return TALER_MHD_reply_with_ec (connection,
+ ec,
+ NULL);
}
return TALER_MHD_reply_json_pack (
connection,
@@ -430,9 +431,10 @@ TEH_handler_deposit (struct MHD_Connection *connection,
/* check denomination exists and is valid */
{
struct TEH_KS_StateHandle *key_state;
- struct TALER_EXCHANGEDB_DenominationKey *dki;
+ struct TEH_DenominationKey *dk;
enum TALER_ErrorCode ec;
unsigned int hc;
+ struct GNUNET_TIME_Absolute now;
key_state = TEH_KS_acquire (dc.exchange_timestamp);
if (NULL == key_state)
@@ -444,12 +446,10 @@ TEH_handler_deposit (struct MHD_Connection *connection,
TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION,
"no keys");
}
- dki = TEH_KS_denomination_key_lookup_by_hash (key_state,
- &deposit.coin.denom_pub_hash,
- TEH_KS_DKU_DEPOSIT,
- &ec,
- &hc);
- if (NULL == dki)
+ dk = TEH_keys_denomination_by_hash (&deposit.coin.denom_pub_hash,
+ &ec,
+ &hc);
+ if (NULL == dk)
{
TALER_LOG_DEBUG ("Unknown denomination key in /deposit request\n");
TEH_KS_release (key_state);
@@ -459,8 +459,42 @@ TEH_handler_deposit (struct MHD_Connection *connection,
ec,
NULL);
}
- TALER_amount_ntoh (&deposit.deposit_fee,
- &dki->issue.properties.fee_deposit);
+ 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 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 !=
TALER_amount_cmp_currency (&deposit.amount_with_fee,
&deposit.deposit_fee) )
@@ -476,7 +510,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
/* check coin signature */
if (GNUNET_YES !=
TALER_test_coin_valid (&deposit.coin,
- &dki->denom_pub))
+ &dk->denom_pub))
{
TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
TEH_KS_release (key_state);
@@ -486,8 +520,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
TALER_EC_EXCHANGE_DENOMINATION_SIGNATURE_INVALID,
NULL);
}
- TALER_amount_ntoh (&dc.value,
- &dki->issue.properties.value);
+ dc.value = dk->meta.value;
TEH_KS_release (key_state);
}
if (0 < TALER_amount_cmp (&deposit.deposit_fee,
diff --git a/src/exchange/taler-exchange-httpd_deposits_get.c b/src/exchange/taler-exchange-httpd_deposits_get.c
index 5b75bdcfd..a4932a1ed 100644
--- a/src/exchange/taler-exchange-httpd_deposits_get.c
+++ b/src/exchange/taler-exchange-httpd_deposits_get.c
@@ -27,6 +27,7 @@
#include "taler_mhd_lib.h"
#include "taler_signatures.h"
#include "taler-exchange-httpd_keystate.h"
+#include "taler-exchange-httpd_keys.h"
#include "taler-exchange-httpd_deposits_get.h"
#include "taler-exchange-httpd_responses.h"
@@ -65,18 +66,18 @@ reply_deposit_details (struct MHD_Connection *connection,
.coin_pub = *coin_pub,
.execution_time = GNUNET_TIME_absolute_hton (exec_time)
};
+ enum TALER_ErrorCode ec;
TALER_amount_hton (&cw.coin_contribution,
coin_contribution);
- if (GNUNET_OK !=
- TEH_KS_sign (&cw,
- &pub,
- &sig))
+ if (TALER_EC_NONE !=
+ (ec = TEH_keys_exchange_sign (&cw,
+ &pub,
+ &sig)))
{
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION,
- "no keys");
+ return TALER_MHD_reply_with_ec (connection,
+ ec,
+ NULL);
}
return TALER_MHD_reply_json_pack (connection,
MHD_HTTP_OK,
diff --git a/src/exchange/taler-exchange-httpd_keys.c b/src/exchange/taler-exchange-httpd_keys.c
index 6e778677a..adc950792 100644
--- a/src/exchange/taler-exchange-httpd_keys.c
+++ b/src/exchange/taler-exchange-httpd_keys.c
@@ -232,17 +232,7 @@ struct SigningKey
};
-/**
- * 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
+struct TEH_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.
*/
static pthread_key_t key_state;
@@ -322,6 +335,16 @@ static pthread_key_t key_state;
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?
* Configuration value.
*/
@@ -343,6 +366,73 @@ static struct TALER_SecurityModulePublicKeyP esign_sm_pub;
*/
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.
@@ -350,7 +440,7 @@ static pthread_mutex_t sm_pub_mutex = PTHREAD_MUTEX_INITIALIZER;
* @param[in,out] ksh key state to update
*/
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++)
{
@@ -530,6 +620,12 @@ helper_denom_cb (
struct HelperDenomination *hd;
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,
h_denom_pub);
if (NULL != hd)
@@ -594,6 +690,11 @@ helper_esign_cb (
struct GNUNET_PeerIdentity pid;
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;
hsk = GNUNET_CONTAINER_multipeermap_get (hs->esign_keys,
&pid);
@@ -675,7 +776,7 @@ sync_key_helpers (struct HelperState *hs)
/**
* 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 value a `struct TEH_DenominationKey` to free
* @return #GNUNET_OK (continue to iterate)
@@ -706,7 +807,7 @@ clear_denomination_cb (void *cls,
/**
* 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 value a `struct SigningKey` to free
* @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
*/
static void
-destroy_key_state (struct KeyStateHandle *ksh,
+destroy_key_state (struct TEH_KeyStateHandle *ksh,
bool free_helper)
{
clear_response_cache (ksh);
@@ -762,12 +863,12 @@ destroy_key_state (struct KeyStateHandle *ksh,
* Free all resources associated with @a cls. Called when
* the respective pthread is destroyed.
*
- * @param[in] cls a `struct KeyStateHandle`.
+ * @param[in] cls a `struct TEH_KeyStateHandle`.
*/
static void
destroy_key_state_cb (void *cls)
{
- struct KeyStateHandle *ksh = cls;
+ struct TEH_KeyStateHandle *ksh = cls;
destroy_key_state (ksh,
true);
@@ -786,6 +887,7 @@ TEH_keys_init ()
pthread_key_create (&key_state,
&destroy_key_state_cb))
return GNUNET_SYSERR;
+ key_state_available = true;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
"exchange",
@@ -801,21 +903,33 @@ TEH_keys_init ()
}
-/**
- * Close down keys submodule.
- */
void
TEH_keys_done ()
{
- GNUNET_assert (0 ==
- pthread_key_delete (key_state));
+ 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 ==
+ pthread_key_delete (key_state));
+ }
}
/**
* 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 h_denom_pub hash of @a denom_pub
* @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,
bool recoup_possible)
{
- struct KeyStateHandle *ksh = cls;
+ struct TEH_KeyStateHandle *ksh = cls;
struct TEH_DenominationKey *dk;
dk = GNUNET_new (struct TEH_DenominationKey);
@@ -854,7 +968,7 @@ denomination_info_cb (
/**
* 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 meta meta data information about the denomination type (expirations)
* @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_MasterSignatureP *master_sig)
{
- struct KeyStateHandle *ksh = cls;
+ struct TEH_KeyStateHandle *ksh = cls;
struct SigningKey *sk;
struct GNUNET_PeerIdentity pid;
@@ -885,9 +999,65 @@ 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.
*
- * @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_url URL of the REST API 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_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 ==
json_array_append_new (
ksh->auditors,
- json_pack ("{s:s, s:o, s:s}",
- "name",
+ json_pack ("{s:s, s:o, s:s, s:o}",
+ "auditor_name",
auditor_name,
"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
* 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 h_denom_pub hash of a denomination key audited by this auditor
* @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 TALER_AuditorSignatureP *auditor_sig)
{
- struct KeyStateHandle *ksh = cls;
+ struct TEH_KeyStateHandle *ksh = cls;
struct TEH_DenominationKey *dk;
struct TEH_AuditorSignature *as;
@@ -959,13 +1137,13 @@ auditor_denom_cb (
* @param[in] hs helper state to (re)use, NULL if not available
* @return NULL on error (i.e. failed to access database)
*/
-static struct KeyStateHandle *
+static struct TEH_KeyStateHandle *
build_key_state (struct HelperState *hs)
{
- struct KeyStateHandle *ksh;
+ struct TEH_KeyStateHandle *ksh;
enum GNUNET_DB_QueryStatus qs;
- ksh = GNUNET_new (struct KeyStateHandle);
+ ksh = GNUNET_new (struct TEH_KeyStateHandle);
ksh->reload_time = GNUNET_TIME_absolute_get ();
GNUNET_TIME_round_abs (&ksh->reload_time);
/* 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
*/
static int
-setup_general_response_headers (const struct KeyStateHandle *ksh,
+setup_general_response_headers (const struct TEH_KeyStateHandle *ksh,
struct MHD_Response *response)
{
char dat[128];
@@ -1262,9 +1440,10 @@ setup_general_response_headers (const struct KeyStateHandle *ksh,
* @param signkeys list of sign keys to return
* @param recoup list of revoked keys to return
* @param denoms list of denominations to return
+ * @return #GNUNET_OK on success
*/
-static void
-create_krd (struct KeyStateHandle *ksh,
+static int
+create_krd (struct TEH_KeyStateHandle *ksh,
const struct GNUNET_HashCode *denom_keys_hash,
struct GNUNET_TIME_Absolute last_cpd,
json_t *signkeys,
@@ -1284,15 +1463,23 @@ create_krd (struct KeyStateHandle *ksh,
.list_issue_date = GNUNET_TIME_absolute_hton (last_cpd),
.hc = *denom_keys_hash
};
+ enum TALER_ErrorCode ec;
- TEH_keys_exchange_sign (&ks,
- &exchange_pub,
- &exchange_sig);
+ if (TALER_EC_NONE !=
+ (ec = TEH_keys_exchange_sign (&ks,
+ &exchange_pub,
+ &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 (
"{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 */
"version", EXCHANGE_PROTOCOL_VERSION,
"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,
krd.response_compressed));
}
+ krd.cherry_pick_date = last_cpd;
GNUNET_array_append (ksh->krd_array,
ksh->krd_array_length,
krd);
+ return GNUNET_OK;
}
@@ -1364,11 +1553,11 @@ create_krd (struct KeyStateHandle *ksh,
* This function is to recompute all (including cherry-picked) responses we
* might want to return, based on the state already in @a ksh.
*
- *
* @param[in,out] ksh state handle to update
+ * @return #GNUNET_OK on success
*/
-static void
-update_keys_response (struct KeyStateHandle *ksh)
+static int
+update_keys_response (struct TEH_KeyStateHandle *ksh)
{
json_t *recoup;
struct SignKeyCtx sctx;
@@ -1417,12 +1606,24 @@ update_keys_response (struct KeyStateHandle *ksh)
GNUNET_CRYPTO_hash_context_finish (
GNUNET_CRYPTO_hash_context_copy (hash_context),
&hc);
- create_krd (ksh,
- &hc,
- last_cpd,
- sctx.signkeys,
- recoup,
- denoms);
+ if (GNUNET_OK !=
+ create_krd (ksh,
+ &hc,
+ last_cpd,
+ sctx.signkeys,
+ recoup,
+ 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;
}
GNUNET_CRYPTO_hash_context_read (hash_context,
@@ -1468,16 +1669,28 @@ update_keys_response (struct KeyStateHandle *ksh)
GNUNET_CRYPTO_hash_context_finish (hash_context,
&hc);
- create_krd (ksh,
- &hc,
- last_cpd,
- sctx.signkeys,
- recoup,
- denoms);
+ if (GNUNET_OK !=
+ create_krd (ksh,
+ &hc,
+ last_cpd,
+ sctx.signkeys,
+ recoup,
+ 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 (recoup);
json_decref (denoms);
+ return GNUNET_OK;
}
@@ -1486,21 +1699,17 @@ TEH_keys_update_states ()
{
__sync_fetch_and_add (&key_generation,
1);
+ TEH_resume_keys_requests ();
}
-/**
- * Return the current key state for this thread. Possibly re-builds the key
- * state if we have reason to believe that something changed.
- *
- * @return NULL on error
- */
-static struct KeyStateHandle *
-get_key_state (void)
+struct TEH_KeyStateHandle *
+TEH_get_key_state (void)
{
- struct KeyStateHandle *old_ksh;
- struct KeyStateHandle *ksh;
+ struct TEH_KeyStateHandle *old_ksh;
+ struct TEH_KeyStateHandle *ksh;
+ GNUNET_assert (key_state_available);
old_ksh = pthread_getspecific (key_state);
if (NULL == old_ksh)
{
@@ -1540,21 +1749,34 @@ get_key_state (void)
struct TEH_DenominationKey *
-TEH_keys_denomination_by_hash (
- const struct GNUNET_HashCode *h_denom_pub,
- enum TALER_ErrorCode *ec,
- unsigned int *hc)
+TEH_keys_denomination_by_hash (const struct GNUNET_HashCode *h_denom_pub,
+ enum TALER_ErrorCode *ec,
+ unsigned int *hc)
{
- struct KeyStateHandle *ksh;
- struct TEH_DenominationKey *dk;
+ struct TEH_KeyStateHandle *ksh;
- ksh = get_key_state ();
+ ksh = TEH_get_key_state ();
if (NULL == ksh)
{
*hc = MHD_HTTP_INTERNAL_SERVER_ERROR;
*ec = TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
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,
h_denom_pub);
if (NULL == dk)
@@ -1568,16 +1790,15 @@ TEH_keys_denomination_by_hash (
struct TALER_DenominationSignature
-TEH_keys_denomination_sign (
- const struct GNUNET_HashCode *h_denom_pub,
- const void *msg,
- size_t msg_size,
- enum TALER_ErrorCode *ec)
+TEH_keys_denomination_sign (const struct GNUNET_HashCode *h_denom_pub,
+ const void *msg,
+ size_t msg_size,
+ enum TALER_ErrorCode *ec)
{
- struct KeyStateHandle *ksh;
+ struct TEH_KeyStateHandle *ksh;
struct TALER_DenominationSignature none = { NULL };
- ksh = get_key_state ();
+ ksh = TEH_get_key_state ();
if (NULL == ksh)
{
*ec = TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
@@ -1592,12 +1813,11 @@ TEH_keys_denomination_sign (
void
-TEH_keys_denomination_revoke (
- const struct GNUNET_HashCode *h_denom_pub)
+TEH_keys_denomination_revoke (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)
{
GNUNET_break (0);
@@ -1615,10 +1835,10 @@ TEH_keys_exchange_sign_ (const struct
struct TALER_ExchangePublicKeyP *pub,
struct TALER_ExchangeSignatureP *sig)
{
- struct KeyStateHandle *ksh;
+ struct TEH_KeyStateHandle *ksh;
enum TALER_ErrorCode ec;
- ksh = get_key_state ();
+ ksh = TEH_get_key_state ();
if (NULL == ksh)
{
/* This *can* happen if the exchange's crypto helper is not running
@@ -1646,9 +1866,10 @@ TEH_keys_exchange_sign_ (const struct
&pid);
if (NULL == sk)
{
- GNUNET_break (0);
/* 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,
0,
sizeof (*sig));
@@ -1662,9 +1883,9 @@ TEH_keys_exchange_sign_ (const struct
void
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)
{
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;
- ksh = get_key_state ();
+ ksh = TEH_get_key_state ();
if (NULL == ksh)
{
- GNUNET_break (0);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
- "no key state");
+ return suspend_request (connection);
+ }
+ if (GNUNET_OK !=
+ update_keys_response (ksh))
+ {
+ return suspend_request (connection);
}
- update_keys_response (ksh);
krd = bsearch (&last_issue_date,
ksh->krd_array,
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_EXCHANGEDB_DenominationKeyMetaData *meta)
{
- struct KeyStateHandle *ksh;
+ struct TEH_KeyStateHandle *ksh;
struct HelperDenomination *hd;
int ok;
- ksh = get_key_state ();
+ ksh = TEH_get_key_state ();
if (NULL == ksh)
{
GNUNET_break (0);
@@ -1959,11 +2180,11 @@ int
TEH_keys_get_timing (const struct TALER_ExchangePublicKeyP *exchange_pub,
struct TALER_EXCHANGEDB_SignkeyMetaData *meta)
{
- struct KeyStateHandle *ksh;
+ struct TEH_KeyStateHandle *ksh;
struct HelperSignkey *hsk;
struct GNUNET_PeerIdentity pid;
- ksh = get_key_state ();
+ ksh = TEH_get_key_state ();
if (NULL == ksh)
{
GNUNET_break (0);
@@ -1990,7 +2211,7 @@ struct FutureBuilderContext
/**
* Our key state.
*/
- struct KeyStateHandle *ksh;
+ struct TEH_KeyStateHandle *ksh;
/**
* Array of denomination keys.
@@ -2044,7 +2265,10 @@ add_future_denomkey_cb (void *cls,
0 ==
json_array_append_new (
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",
TALER_JSON_from_amount (&meta.value),
"stamp_start",
@@ -2055,8 +2279,9 @@ add_future_denomkey_cb (void *cls,
GNUNET_JSON_from_time_abs (meta.expire_deposit),
"stamp_expire_legal",
GNUNET_JSON_from_time_abs (meta.expire_legal),
+ /* 6-10 */
"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",
TALER_JSON_from_amount (&meta.fee_withdraw),
"fee_deposit",
@@ -2065,8 +2290,11 @@ add_future_denomkey_cb (void *cls,
TALER_JSON_from_amount (&meta.fee_refresh),
"fee_refund",
TALER_JSON_from_amount (&meta.fee_refund),
+ /* 11- */
"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;
}
@@ -2123,10 +2351,10 @@ MHD_RESULT
TEH_keys_management_get_handler (const struct TEH_RequestHandler *rh,
struct MHD_Connection *connection)
{
- struct KeyStateHandle *ksh;
+ struct TEH_KeyStateHandle *ksh;
json_t *reply;
- ksh = get_key_state ();
+ ksh = TEH_get_key_state ();
if (NULL == ksh)
{
GNUNET_break (0);
@@ -2143,6 +2371,8 @@ TEH_keys_management_get_handler (const struct TEH_RequestHandler *rh,
.signkeys = json_array ()
};
+ GNUNET_assert (NULL != fbc.denoms);
+ GNUNET_assert (NULL != fbc.signkeys);
GNUNET_CONTAINER_multihashmap_iterate (ksh->helpers.denom_keys,
&add_future_denomkey_cb,
&fbc);
@@ -2161,6 +2391,11 @@ TEH_keys_management_get_handler (const struct TEH_RequestHandler *rh,
GNUNET_JSON_from_data_auto (&denom_sm_pub),
"signkey_secmod_public_key",
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)
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
diff --git a/src/exchange/taler-exchange-httpd_keys.h b/src/exchange/taler-exchange-httpd_keys.h
index 5a1314f12..6966290f3 100644
--- a/src/exchange/taler-exchange-httpd_keys.h
+++ b/src/exchange/taler-exchange-httpd_keys.h
@@ -84,6 +84,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
* should be called if the exchange learns about a new signature from an
* auditor or our master key.
@@ -109,13 +136,31 @@ TEH_keys_update_states (void);
* or NULL if @a h_denom_pub could not be found
*/
struct TEH_DenominationKey *
-TEH_keys_denomination_by_hash (
- const struct GNUNET_HashCode *h_denom_pub,
- enum TALER_ErrorCode *ec,
- unsigned int *hc);
+TEH_keys_denomination_by_hash (const struct GNUNET_HashCode *h_denom_pub,
+ enum TALER_ErrorCode *ec,
+ 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
* @a h_denom_pub.
*
@@ -127,11 +172,10 @@ TEH_keys_denomination_by_hash (
* see @a ec for details about the failure
*/
struct TALER_DenominationSignature
-TEH_keys_denomination_sign (
- const struct GNUNET_HashCode *h_denom_pub,
- const void *msg,
- size_t msg_size,
- enum TALER_ErrorCode *ec);
+TEH_keys_denomination_sign (const struct GNUNET_HashCode *h_denom_pub,
+ const void *msg,
+ size_t msg_size,
+ enum TALER_ErrorCode *ec);
/**
@@ -146,8 +190,17 @@ TEH_keys_denomination_sign (
* @param h_denom_pub hash of the public key to revoke
*/
void
-TEH_keys_denomination_revoke (
- const struct GNUNET_HashCode *h_denom_pub);
+TEH_keys_denomination_revoke (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);
/**
diff --git a/src/exchange/taler-exchange-httpd_keystate.c b/src/exchange/taler-exchange-httpd_keystate.c
index 9491234e9..8d5a18510 100644
--- a/src/exchange/taler-exchange-httpd_keystate.c
+++ b/src/exchange/taler-exchange-httpd_keystate.c
@@ -2054,7 +2054,7 @@ TEH_KS_denomination_key_lookup_by_hash (
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Not returning DKI for %s, as time to create coins has passed\n",
GNUNET_h2s (denom_pub_hash));
- *ec = TALER_EC_EXCHANGE_WITHDRAW_VALIDITY_IN_PAST;
+ *ec = TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED;
*hc = MHD_HTTP_GONE;
return NULL;
}
diff --git a/src/exchange/taler-exchange-httpd_management_auditors.c b/src/exchange/taler-exchange-httpd_management_auditors.c
index 33f1c6df3..1a2494dae 100644
--- a/src/exchange/taler-exchange-httpd_management_auditors.c
+++ b/src/exchange/taler-exchange-httpd_management_auditors.c
@@ -103,7 +103,8 @@ add_auditor (void *cls,
"lookup auditor");
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 (
connection,
diff --git a/src/exchange/taler-exchange-httpd_management_denominations_HDP_revoke.c b/src/exchange/taler-exchange-httpd_management_denominations_HDP_revoke.c
index 75ce3d76b..8fb5b0839 100644
--- a/src/exchange/taler-exchange-httpd_management_denominations_HDP_revoke.c
+++ b/src/exchange/taler-exchange-httpd_management_denominations_HDP_revoke.c
@@ -29,6 +29,7 @@
#include "taler-exchange-httpd_management.h"
#include "taler-exchange-httpd_responses.h"
#include "taler-exchange-httpd_keystate.h"
+#include "taler-exchange-httpd_keys.h"
MHD_RESULT
@@ -81,7 +82,7 @@ TEH_handler_management_denominations_HDP_revoke (
TALER_EC_GENERIC_DB_STORE_FAILED,
"denomination revocation");
}
- // FIXME: also update our '/keys' replies! (signal all threads!?!?)
+ TEH_keys_update_states ();
return TALER_MHD_reply_static (
connection,
MHD_HTTP_NO_CONTENT,
diff --git a/src/exchange/taler-exchange-httpd_management_post_keys.c b/src/exchange/taler-exchange-httpd_management_post_keys.c
index 06750716e..84ec1f531 100644
--- a/src/exchange/taler-exchange-httpd_management_post_keys.c
+++ b/src/exchange/taler-exchange-httpd_management_post_keys.c
@@ -212,6 +212,9 @@ add_keys (void *cls,
"activate denomination key");
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);
}
@@ -296,9 +299,11 @@ add_keys (void *cls,
"activate signing key");
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);
}
-
return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; /* only 'success', so >=0, matters here */
}
@@ -382,9 +387,9 @@ TEH_handler_management_post_keys (
return ret;
}
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);
- 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 GNUNET_JSON_Specification ispec[] = {
@@ -419,6 +424,10 @@ TEH_handler_management_post_keys (
GNUNET_free (akc.s_sigs);
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,
"add keys",
&ret,
@@ -426,6 +435,7 @@ TEH_handler_management_post_keys (
&akc);
if (qs < 0)
return ret;
+ TEH_keys_update_states ();
return TALER_MHD_reply_static (
connection,
MHD_HTTP_NO_CONTENT,
diff --git a/src/exchange/taler-exchange-httpd_management_signkey_EP_revoke.c b/src/exchange/taler-exchange-httpd_management_signkey_EP_revoke.c
index 8a462f967..3a84296cd 100644
--- a/src/exchange/taler-exchange-httpd_management_signkey_EP_revoke.c
+++ b/src/exchange/taler-exchange-httpd_management_signkey_EP_revoke.c
@@ -29,6 +29,7 @@
#include "taler-exchange-httpd_management.h"
#include "taler-exchange-httpd_responses.h"
#include "taler-exchange-httpd_keystate.h"
+#include "taler-exchange-httpd_keys.h"
MHD_RESULT
@@ -80,7 +81,7 @@ TEH_handler_management_signkeys_EP_revoke (
TALER_EC_GENERIC_DB_STORE_FAILED,
"signkey revocation");
}
- // FIXME: also update our '/keys' replies! (signal all threads!?!?)
+ TEH_keys_update_states ();
return TALER_MHD_reply_static (
connection,
MHD_HTTP_NO_CONTENT,
diff --git a/src/exchange/taler-exchange-httpd_management_wire.c b/src/exchange/taler-exchange-httpd_management_wire.c
index 15e5b3610..c462bfc31 100644
--- a/src/exchange/taler-exchange-httpd_management_wire.c
+++ b/src/exchange/taler-exchange-httpd_management_wire.c
@@ -101,7 +101,8 @@ add_wire (void *cls,
"lookup wire");
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 (
connection,
diff --git a/src/exchange/taler-exchange-httpd_melt.c b/src/exchange/taler-exchange-httpd_melt.c
index 8b5914e2d..76cf52ebe 100644
--- a/src/exchange/taler-exchange-httpd_melt.c
+++ b/src/exchange/taler-exchange-httpd_melt.c
@@ -30,6 +30,7 @@
#include "taler-exchange-httpd_melt.h"
#include "taler-exchange-httpd_responses.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,
.noreveal_index = htonl (noreveal_index)
};
+ enum TALER_ErrorCode ec;
- if (GNUNET_OK !=
- TEH_KS_sign (&body,
- &pub,
- &sig))
+ if (TALER_EC_NONE !=
+ (ec = TEH_keys_exchange_sign (&body,
+ &pub,
+ &sig)))
{
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION,
- "no keys");
+ return TALER_MHD_reply_with_ec (connection,
+ ec,
+ NULL);
}
return TALER_MHD_reply_json_pack (
connection,
@@ -477,94 +478,94 @@ check_for_denomination_key (struct MHD_Connection *connection,
{
/* Baseline: check if deposits/refreshs are generally
simply still allowed for this denomination */
- struct TALER_EXCHANGEDB_DenominationKey *dki;
+ struct TEH_DenominationKey *dk;
unsigned int hc;
enum TALER_ErrorCode ec;
+ struct GNUNET_TIME_Absolute now;
- dki = TEH_KS_denomination_key_lookup_by_hash (
- key_state,
+ dk = TEH_keys_denomination_by_hash (
&rmc->refresh_session.coin.denom_pub_hash,
- TEH_KS_DKU_DEPOSIT,
&ec,
&hc);
- /* Consider case that denomination was revoked but
- this coin was already seen and thus refresh is OK. */
- if (NULL == dki)
+ if (NULL == dk)
{
- dki = TEH_KS_denomination_key_lookup_by_hash (
- key_state,
- &rmc->refresh_session.coin.denom_pub_hash,
- TEH_KS_DKU_RECOUP,
- &ec,
- &hc);
- if (NULL != dki)
- {
- struct GNUNET_HashCode denom_hash;
- enum GNUNET_DB_QueryStatus qs;
-
- /* Check that the coin is dirty (we have seen it before), as we will
- not just allow melting of a *fresh* coin where the denomination was
- revoked (those must be recouped) */
- qs = TEH_plugin->get_coin_denomination (
- TEH_plugin->cls,
- NULL,
- &rmc->refresh_session.coin.coin_pub,
- &denom_hash);
- if (0 > qs)
- {
- TEH_KS_release (key_state);
- /* There is no good reason for a serialization failure here: */
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_FETCH_FAILED,
- "coin denomination");
- }
- /* sanity check */
- GNUNET_break (0 ==
- GNUNET_memcmp (&denom_hash,
- &rmc->refresh_session.coin.denom_pub_hash));
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
- {
- /* We never saw this coin before, so _this_ justification is not OK */
- dki = NULL;
- }
- else
- {
- /* Minor optimization: no need to run the
- "ensure_coin_known" part of the transaction */
- rmc->coin_is_dirty = true;
- }
- }
+ TEH_KS_release (key_state);
+ return TALER_MHD_reply_with_error (
+ connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN,
+ NULL);
}
-
- /* 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)
+ now = GNUNET_TIME_absolute_get ();
+ if (now.abs_value_us >= dk->meta.expire_legal.abs_value_us)
{
- 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 */
+ /* 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 (NULL == dki)
+ 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,
- hc,
- ec,
- NULL);
+ 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;
+ enum GNUNET_DB_QueryStatus qs;
+
+ /* Check that the coin is dirty (we have seen it before), as we will
+ not just allow melting of a *fresh* coin where the denomination was
+ revoked (those must be recouped) */
+ qs = TEH_plugin->get_coin_denomination (
+ TEH_plugin->cls,
+ NULL,
+ &rmc->refresh_session.coin.coin_pub,
+ &denom_hash);
+ if (0 > qs)
+ {
+ TEH_KS_release (key_state);
+ /* There is no good reason for a serialization failure here: */
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "coin denomination");
+ }
+ /* sanity check */
+ GNUNET_break (0 ==
+ GNUNET_memcmp (&denom_hash,
+ &rmc->refresh_session.coin.denom_pub_hash));
+ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
+ {
+ /* We never saw this coin before, so _this_ justification is not OK */
+ TEH_KS_release (key_state);
+ return TALER_MHD_reply_with_error (
+ connection,
+ MHD_HTTP_GONE,
+ TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
+ NULL);
+ }
+ else
+ {
+ /* Minor optimization: no need to run the
+ "ensure_coin_known" part of the transaction */
+ rmc->coin_is_dirty = true;
+ }
+ rmc->zombie_required = true; /* check later that zombie is satisfied */
}
- TALER_amount_ntoh (&rmc->coin_refresh_fee,
- &dki->issue.properties.fee_refresh);
- TALER_amount_ntoh (&rmc->coin_value,
- &dki->issue.properties.value);
+ rmc->coin_refresh_fee = dk->meta.fee_refresh;
+ rmc->coin_value = dk->meta.value;
/* check client used sane currency */
if (GNUNET_YES !=
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 */
if (GNUNET_OK !=
TALER_test_coin_valid (&rmc->refresh_session.coin,
- &dki->denom_pub))
+ &dk->denom_pub))
{
GNUNET_break_op (0);
TEH_KS_release (key_state);
diff --git a/src/exchange/taler-exchange-httpd_recoup.c b/src/exchange/taler-exchange-httpd_recoup.c
index fe8b8d603..aa521d66b 100644
--- a/src/exchange/taler-exchange-httpd_recoup.c
+++ b/src/exchange/taler-exchange-httpd_recoup.c
@@ -31,6 +31,7 @@
#include "taler-exchange-httpd_recoup.h"
#include "taler-exchange-httpd_responses.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)
{
struct RecoupContext pc;
- const struct TALER_EXCHANGEDB_DenominationKey *dki;
+ const struct TEH_DenominationKey *dk;
struct GNUNET_HashCode c_hash;
void *coin_ev;
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 */
{
struct TEH_KS_StateHandle *key_state;
+ struct GNUNET_TIME_Absolute now;
key_state = TEH_KS_acquire (GNUNET_TIME_absolute_get ());
if (NULL == key_state)
@@ -379,12 +381,10 @@ verify_and_execute_recoup (struct MHD_Connection *connection,
TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION,
"no keys");
}
- dki = TEH_KS_denomination_key_lookup_by_hash (key_state,
- &coin->denom_pub_hash,
- TEH_KS_DKU_RECOUP,
- &ec,
- &hc);
- if (NULL == dki)
+ dk = TEH_keys_denomination_by_hash (&coin->denom_pub_hash,
+ &ec,
+ &hc);
+ if (NULL == dk)
{
TEH_KS_release (key_state);
TALER_LOG_WARNING (
@@ -394,13 +394,45 @@ verify_and_execute_recoup (struct MHD_Connection *connection,
ec,
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 */
if (GNUNET_YES !=
TALER_test_coin_valid (coin,
- &dki->denom_pub))
+ &dk->denom_pub))
{
TALER_LOG_WARNING ("Invalid coin passed for recoup\n");
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.size = htonl (sizeof (struct TALER_RecoupRequestPS)),
.coin_pub = coin->coin_pub,
- .h_denom_pub = dki->issue.properties.denom_hash,
+ .h_denom_pub = coin->denom_pub_hash,
.coin_blind = *coin_bks
};
@@ -440,7 +472,7 @@ verify_and_execute_recoup (struct MHD_Connection *connection,
if (GNUNET_YES !=
TALER_rsa_blind (&c_hash,
&coin_bks->bks,
- dki->denom_pub.rsa_public_key,
+ dk->denom_pub.rsa_public_key,
&coin_ev,
&coin_ev_size))
{
diff --git a/src/exchange/taler-exchange-httpd_refreshes_reveal.c b/src/exchange/taler-exchange-httpd_refreshes_reveal.c
index 6440f6dd0..9b3a42f97 100644
--- a/src/exchange/taler-exchange-httpd_refreshes_reveal.c
+++ b/src/exchange/taler-exchange-httpd_refreshes_reveal.c
@@ -29,6 +29,7 @@
#include "taler-exchange-httpd_refreshes_reveal.h"
#include "taler-exchange-httpd_responses.h"
#include "taler-exchange-httpd_keystate.h"
+#include "taler-exchange-httpd_keys.h"
/**
@@ -132,7 +133,7 @@ struct RevealContext
/**
* Denominations being requested.
*/
- const struct TALER_EXCHANGEDB_DenominationKey **dkis;
+ const struct TEH_DenominationKey **dks;
/**
* Envelopes to be signed.
@@ -151,7 +152,7 @@ struct RevealContext
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;
@@ -367,7 +368,7 @@ refreshes_reveal_transaction (void *cls,
struct TALER_PlanchetDetail pd;
struct GNUNET_HashCode c_hash;
- rcd->dk = &rctx->dkis[j]->denom_pub;
+ rcd->dk = &rctx->dks[j]->denom_pub;
TALER_planchet_setup_refresh (&ts,
j,
&ps);
@@ -432,18 +433,12 @@ refreshes_reveal_transaction (void *cls,
refresh_cost = melt.melt_fee;
for (unsigned int i = 0; i<rctx->num_fresh_coins; i++)
{
- struct TALER_Amount fee_withdraw;
- struct TALER_Amount value;
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 >
TALER_amount_add (&total,
- &fee_withdraw,
- &value)) ||
+ &rctx->dks[i]->meta.fee_withdraw,
+ &rctx->dks[i]->meta.value)) ||
(0 >
TALER_amount_add (&refresh_cost,
&refresh_cost,
@@ -499,7 +494,7 @@ refreshes_reveal_persist (void *cls,
{
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->coin_ev = rctx->rcds[i].coin_ev;
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);
/* We know num_fresh_coins is bounded by #MAX_FRESH_COINS, so this is safe */
- const struct TALER_EXCHANGEDB_DenominationKey *dkis[num_fresh_coins];
- struct GNUNET_HashCode dki_h[num_fresh_coins];
+ const struct TEH_DenominationKey *dks[num_fresh_coins];
+ struct GNUNET_HashCode dk_h[num_fresh_coins];
struct TALER_RefreshCoinData rcds[num_fresh_coins];
struct TALER_CoinSpendSignatureP link_sigs[num_fresh_coins];
struct TALER_EXCHANGEDB_Melt melt;
enum GNUNET_GenericReturnValue res;
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 */
+ now = GNUNET_TIME_absolute_get ();
for (unsigned int i = 0; i<num_fresh_coins; i++)
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto (NULL,
- &dki_h[i]),
+ &dk_h[i]),
GNUNET_JSON_spec_end ()
};
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;
}
- dkis[i] = TEH_KS_denomination_key_lookup_by_hash (key_state,
- &dki_h[i],
- TEH_KS_DKU_WITHDRAW,
- &ec,
- &hc);
- if (NULL == dkis[i])
+ dks[i] = TEH_keys_denomination_by_hash2 (ksh,
+ &dk_h[i],
+ &ec,
+ &hc);
+ if (NULL == dks[i])
{
return TALER_MHD_reply_with_error (connection,
hc,
ec,
NULL);
}
- /* #TEH_KS_DKU_WITHDRAW should warrant that we only get denomination
- keys where we did not yet forget the private key */
- GNUNET_assert (NULL != dkis[i]->denom_priv.rsa_private_key);
+
+ if (now.abs_value_us >= dks[i]->meta.expire_withdraw.abs_value_us)
+ {
+ /* 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 */
@@ -613,7 +643,7 @@ resolve_refreshes_reveal_denominations (struct TEH_KS_StateHandle *key_state,
GNUNET_free (rcds[j].coin_ev);
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 */
@@ -672,7 +702,7 @@ resolve_refreshes_reveal_denominations (struct TEH_KS_StateHandle *key_state,
struct TALER_LinkDataPS ldp = {
.purpose.size = htonl (sizeof (ldp)),
.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,
.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->rcds = rcds;
- rctx->dkis = dkis;
+ rctx->dks = dks;
rctx->link_sigs = link_sigs;
/* sign _early_ (optimistic!) to keep out of transaction scope! */
@@ -707,18 +737,20 @@ resolve_refreshes_reveal_denominations (struct TEH_KS_StateHandle *key_state,
struct TALER_DenominationSignature);
for (unsigned int i = 0; i<rctx->num_fresh_coins; i++)
{
- rctx->ev_sigs[i].rsa_signature
- = GNUNET_CRYPTO_rsa_sign_blinded (
- rctx->dkis[i]->denom_priv.rsa_private_key,
+ enum TALER_ErrorCode ec;
+
+ rctx->ev_sigs[i]
+ = TEH_keys_denomination_sign (
+ &dk_h[i],
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)
{
GNUNET_break (0);
- ret = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_EXCHANGE_REFRESHES_REVEAL_SIGNING_ERROR,
- NULL);
+ ret = TALER_MHD_reply_with_ec (connection,
+ ec,
+ NULL);
goto cleanup;
}
}
diff --git a/src/exchange/taler-exchange-httpd_refund.c b/src/exchange/taler-exchange-httpd_refund.c
index 1dfd8931b..6bb943483 100644
--- a/src/exchange/taler-exchange-httpd_refund.c
+++ b/src/exchange/taler-exchange-httpd_refund.c
@@ -33,6 +33,7 @@
#include "taler-exchange-httpd_refund.h"
#include "taler-exchange-httpd_responses.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,
.rtransaction_id = GNUNET_htonll (refund->rtransaction_id)
};
+ enum TALER_ErrorCode ec;
TALER_amount_hton (&rc.refund_amount,
&refund->refund_amount);
- if (GNUNET_OK !=
- TEH_KS_sign (&rc,
- &pub,
- &sig))
+ if (TALER_EC_NONE !=
+ (ec = TEH_keys_exchange_sign (&rc,
+ &pub,
+ &sig)))
{
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION,
- "no online signing key");
+ return TALER_MHD_reply_with_ec (connection,
+ ec,
+ NULL);
}
return TALER_MHD_reply_json_pack (
connection,
@@ -460,16 +461,14 @@ verify_and_execute_refund (struct MHD_Connection *connection,
}
/* Obtain information about the coin's denomination! */
{
- struct TALER_EXCHANGEDB_DenominationKey *dki;
+ struct TEH_DenominationKey *dk;
unsigned int hc;
enum TALER_ErrorCode ec;
- dki = TEH_KS_denomination_key_lookup_by_hash (key_state,
- &denom_hash,
- TEH_KS_DKU_DEPOSIT,
- &ec,
- &hc);
- if (NULL == dki)
+ dk = TEH_keys_denomination_by_hash (&denom_hash,
+ &ec,
+ &hc);
+ if (NULL == dk)
{
/* DKI not found, but we do have a coin with this DK in our database;
not good... */
@@ -480,8 +479,19 @@ verify_and_execute_refund (struct MHD_Connection *connection,
ec,
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);
}
diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c
index 32b44ffca..c0ec6d95d 100644
--- a/src/exchange/taler-exchange-httpd_responses.c
+++ b/src/exchange/taler-exchange-httpd_responses.c
@@ -29,6 +29,7 @@
#include "taler_json_lib.h"
#include "taler_mhd_lib.h"
#include "taler-exchange-httpd_keystate.h"
+#include "taler-exchange-httpd_keys.h"
/**
@@ -256,10 +257,10 @@ TEH_RESPONSE_compile_transaction_history (
TALER_amount_hton (&pc.recoup_amount,
&pr->value);
- if (GNUNET_OK !=
- TEH_KS_sign (&pc,
- &epub,
- &esig))
+ if (TALER_EC_NONE !=
+ TEH_keys_exchange_sign (&pc,
+ &epub,
+ &esig))
{
GNUNET_break (0);
json_decref (history);
@@ -309,10 +310,10 @@ TEH_RESPONSE_compile_transaction_history (
TALER_amount_hton (&pc.recoup_amount,
&recoup->value);
- if (GNUNET_OK !=
- TEH_KS_sign (&pc,
- &epub,
- &esig))
+ if (TALER_EC_NONE !=
+ TEH_keys_exchange_sign (&pc,
+ &epub,
+ &esig))
{
GNUNET_break (0);
json_decref (history);
@@ -366,10 +367,10 @@ TEH_RESPONSE_compile_transaction_history (
TALER_amount_hton (&pc.recoup_amount,
&pr->value);
- if (GNUNET_OK !=
- TEH_KS_sign (&pc,
- &epub,
- &esig))
+ if (TALER_EC_NONE !=
+ TEH_keys_exchange_sign (&pc,
+ &epub,
+ &esig))
{
GNUNET_break (0);
json_decref (history);
@@ -610,10 +611,10 @@ TEH_RESPONSE_compile_reserve_history (
TALER_amount_hton (&pc.recoup_amount,
&recoup->value);
- if (GNUNET_OK !=
- TEH_KS_sign (&pc,
- &pub,
- &sig))
+ if (TALER_EC_NONE !=
+ TEH_keys_exchange_sign (&pc,
+ &pub,
+ &sig))
{
GNUNET_break (0);
json_decref (json_history);
@@ -686,10 +687,10 @@ TEH_RESPONSE_compile_reserve_history (
GNUNET_CRYPTO_hash (closing->receiver_account_details,
strlen (closing->receiver_account_details) + 1,
&rcc.h_wire);
- if (GNUNET_OK !=
- TEH_KS_sign (&rcc,
- &pub,
- &sig))
+ if (TALER_EC_NONE !=
+ TEH_keys_exchange_sign (&rcc,
+ &pub,
+ &sig))
{
GNUNET_break (0);
json_decref (json_history);
diff --git a/src/exchange/taler-exchange-httpd_transfers_get.c b/src/exchange/taler-exchange-httpd_transfers_get.c
index b5237df25..b7f24f23f 100644
--- a/src/exchange/taler-exchange-httpd_transfers_get.c
+++ b/src/exchange/taler-exchange-httpd_transfers_get.c
@@ -24,6 +24,7 @@
#include <microhttpd.h>
#include <pthread.h>
#include "taler_signatures.h"
+#include "taler-exchange-httpd_keys.h"
#include "taler-exchange-httpd_keystate.h"
#include "taler-exchange-httpd_transfers_get.h"
#include "taler-exchange-httpd_responses.h"
@@ -99,6 +100,7 @@ reply_transfer_details (struct MHD_Connection *connection,
struct TALER_ExchangePublicKeyP pub;
struct TALER_ExchangeSignatureP sig;
+
GNUNET_TIME_round_abs (&exec_time);
deposits = json_array ();
if (NULL == deposits)
@@ -158,16 +160,19 @@ reply_transfer_details (struct MHD_Connection *connection,
wdp.h_wire = *h_wire;
GNUNET_CRYPTO_hash_context_finish (hash_context,
&wdp.h_details);
- if (GNUNET_OK !=
- TEH_KS_sign (&wdp,
- &pub,
- &sig))
{
- json_decref (deposits);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_EXCHANGE_GENERIC_BAD_CONFIGURATION,
- "no keys");
+ enum TALER_ErrorCode ec;
+
+ if (TALER_EC_NONE !=
+ (ec = TEH_keys_exchange_sign (&wdp,
+ &pub,
+ &sig)))
+ {
+ json_decref (deposits);
+ return TALER_MHD_reply_with_ec (connection,
+ ec,
+ NULL);
+ }
}
return TALER_MHD_reply_json_pack (connection,
diff --git a/src/exchange/taler-exchange-httpd_withdraw.c b/src/exchange/taler-exchange-httpd_withdraw.c
index 0b5eb7370..035273bc6 100644
--- a/src/exchange/taler-exchange-httpd_withdraw.c
+++ b/src/exchange/taler-exchange-httpd_withdraw.c
@@ -31,6 +31,7 @@
#include "taler-exchange-httpd_withdraw.h"
#include "taler-exchange-httpd_responses.h"
#include "taler-exchange-httpd_keystate.h"
+#include "taler-exchange-httpd_keys.h"
/**
@@ -134,11 +135,6 @@ struct WithdrawContext
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.
*/
struct TALER_EXCHANGEDB_CollectableBlindcoin collectable;
@@ -291,17 +287,19 @@ withdraw_transaction (void *cls,
#if ! OPTIMISTIC_SIGN
if (NULL == wc->collectable.sig.rsa_signature)
{
- wc->collectable.sig.rsa_signature
- = GNUNET_CRYPTO_rsa_sign_blinded (wc->dki->denom_priv.rsa_private_key,
- wc->blinded_msg,
- wc->blinded_msg_len);
+ enum TALER_ErrorCode ec;
+
+ wc->collectable.sig
+ = TEH_keys_denomination_sign (&wc->denom_pub_hash,
+ wc->blinded_msg,
+ wc->blinded_msg_len,
+ &ec);
if (NULL == wc->collectable.sig.rsa_signature)
{
GNUNET_break (0);
- *mhd_ret = TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_EXCHANGE_WITHDRAW_SIGNATURE_FAILED,
- NULL);
+ *mhd_ret = TALER_MHD_reply_with_ec (connection,
+ ec,
+ NULL);
return GNUNET_DB_STATUS_HARD_ERROR;
}
}
@@ -360,6 +358,8 @@ TEH_handler_withdraw (const struct TEH_RequestHandler *rh,
&wc.denom_pub_hash),
GNUNET_JSON_spec_end ()
};
+ enum TALER_ErrorCode ec;
+ struct TEH_DenominationKey *dk;
(void) rh;
if (GNUNET_OK !=
@@ -397,13 +397,12 @@ TEH_handler_withdraw (const struct TEH_RequestHandler *rh,
{
unsigned int hc;
enum TALER_ErrorCode ec;
+ struct GNUNET_TIME_Absolute now;
- wc.dki = TEH_KS_denomination_key_lookup_by_hash (wc.key_state,
- &wc.denom_pub_hash,
- TEH_KS_DKU_WITHDRAW,
- &ec,
- &hc);
- if (NULL == wc.dki)
+ dk = TEH_keys_denomination_by_hash (&wc.denom_pub_hash,
+ &ec,
+ &hc);
+ if (NULL == dk)
{
GNUNET_JSON_parse_free (spec);
TEH_KS_release (wc.key_state);
@@ -412,20 +411,47 @@ TEH_handler_withdraw (const struct TEH_RequestHandler *rh,
ec,
NULL);
}
+ now = GNUNET_TIME_absolute_get ();
+ if (now.abs_value_us >= dk->meta.expire_withdraw.abs_value_us)
+ {
+ /* This denomination is past the expiration time for withdraws */
+ 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);
+ }
}
- GNUNET_assert (NULL != wc.dki->denom_priv.rsa_private_key);
- {
- struct TALER_Amount amount;
- struct TALER_Amount fee_withdraw;
- TALER_amount_ntoh (&amount,
- &wc.dki->issue.properties.value);
- TALER_amount_ntoh (&fee_withdraw,
- &wc.dki->issue.properties.fee_withdraw);
+ {
if (0 >
TALER_amount_add (&wc.amount_required,
- &amount,
- &fee_withdraw))
+ &dk->meta.value,
+ &dk->meta.fee_withdraw))
{
GNUNET_JSON_parse_free (spec);
TEH_KS_release (wc.key_state);
@@ -466,19 +492,19 @@ TEH_handler_withdraw (const struct TEH_RequestHandler *rh,
#if OPTIMISTIC_SIGN
/* Sign before transaction! */
- wc.collectable.sig.rsa_signature
- = GNUNET_CRYPTO_rsa_sign_blinded (wc.dki->denom_priv.rsa_private_key,
- wc.blinded_msg,
- wc.blinded_msg_len);
+ wc.collectable.sig
+ = TEH_keys_denomination_sign (&wc.denom_pub_hash,
+ wc.blinded_msg,
+ wc.blinded_msg_len,
+ &ec);
if (NULL == wc.collectable.sig.rsa_signature)
{
GNUNET_break (0);
GNUNET_JSON_parse_free (spec);
TEH_KS_release (wc.key_state);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_EXCHANGE_WITHDRAW_SIGNATURE_FAILED,
- NULL);
+ return TALER_MHD_reply_with_ec (connection,
+ ec,
+ NULL);
}
#endif
diff --git a/src/exchange/test_taler_exchange_httpd.conf b/src/exchange/test_taler_exchange_httpd.conf
index 23307cd2e..b0e3801fb 100644
--- a/src/exchange/test_taler_exchange_httpd.conf
+++ b/src/exchange/test_taler_exchange_httpd.conf
@@ -18,6 +18,7 @@ TERMS_DIR = ../../contrib/tos
# Etag / filename for the terms of service.
TERMS_ETAG = 0
+SIGNKEY_LEGAL_DURATION = 2 years
# Directory with our privacy policy.
PRIVACY_DIR = ../../contrib/pp
diff --git a/src/exchange/test_taler_exchange_httpd.get b/src/exchange/test_taler_exchange_httpd.get
index 28a9e9bc9..c9058c870 100644
--- a/src/exchange/test_taler_exchange_httpd.get
+++ b/src/exchange/test_taler_exchange_httpd.get
@@ -20,7 +20,7 @@
#
/
/agpl
-/keys
+/seed
/robots.txt
/terms
/privacy
diff --git a/src/exchange/test_taler_exchange_httpd.sh b/src/exchange/test_taler_exchange_httpd.sh
index dabe79cb7..943488911 100755
--- a/src/exchange/test_taler_exchange_httpd.sh
+++ b/src/exchange/test_taler_exchange_httpd.sh
@@ -31,10 +31,6 @@ PREFIX=
# Setup database
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)
$PREFIX taler-exchange-httpd -c test_taler_exchange_httpd.conf 2> test-exchange.log &
@@ -45,7 +41,7 @@ do
echo -n "."
sleep 0.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
done
if [ 1 != $OK ]
diff --git a/src/exchange/test_taler_exchange_httpd_restart.sh b/src/exchange/test_taler_exchange_httpd_restart.sh
index a8976fb0c..2897127fb 100755
--- a/src/exchange/test_taler_exchange_httpd_restart.sh
+++ b/src/exchange/test_taler_exchange_httpd_restart.sh
@@ -53,10 +53,6 @@ PREFIX=
# Setup database
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)
$PREFIX taler-exchange-httpd -c test_taler_exchange_unix.conf 2> test-exchange.log &
@@ -80,13 +76,6 @@ fi
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...
echo -n "Restarting program ..."
kill -SIGHUP $!
sleep 1
diff --git a/src/exchange/test_taler_exchange_unix.conf b/src/exchange/test_taler_exchange_unix.conf
index bc870d4bb..1a65d801c 100644
--- a/src/exchange/test_taler_exchange_unix.conf
+++ b/src/exchange/test_taler_exchange_unix.conf
@@ -15,6 +15,7 @@ TERMS_DIR = ../../contrib/tos
# Etag / filename for the terms of service.
TERMS_ETAG = 0
+SIGNKEY_LEGAL_DURATION = 2 years
# Directory with our privacy policy.
PRIVACY_DIR = ../../contrib/pp
diff --git a/src/include/taler_mhd_lib.h b/src/include/taler_mhd_lib.h
index 09e22f9e1..c1b65126c 100644
--- a/src/include/taler_mhd_lib.h
+++ b/src/include/taler_mhd_lib.h
@@ -144,6 +144,21 @@ 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);
+
+
+/**
* Make JSON response object.
*
* @param json the json object
diff --git a/src/mhd/mhd_responses.c b/src/mhd/mhd_responses.c
index 5ed82cd2a..9e6986a37 100644
--- a/src/mhd/mhd_responses.c
+++ b/src/mhd/mhd_responses.c
@@ -443,6 +443,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.
*
* @param connection the MHD connection to use
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am
index 0d50d95c6..ceba62201 100644
--- a/src/testing/Makefile.am
+++ b/src/testing/Makefile.am
@@ -131,7 +131,6 @@ check_PROGRAMS = \
test_bank_api_with_pybank \
test_bank_api_with_nexus \
test_exchange_api \
- test_exchange_api_keys_cherry_picking \
test_exchange_api_revocation \
test_exchange_api_overlapping_keys_bug \
test_exchange_management_api \
@@ -144,6 +143,10 @@ if HAVE_TWISTER
test_bank_api_with_pybank_twisted
endif
+# test_exchange_api_keys_cherry_picking disabled for now:
+# needs to be rewritten as we no longer support /keys timetravel!
+
+
TESTS = \
$(check_PROGRAMS)
diff --git a/src/testing/test_auditor_api.c b/src/testing/test_auditor_api.c
index f0184143a..48f03119e 100644
--- a/src/testing/test_auditor_api.c
+++ b/src/testing/test_auditor_api.c
@@ -1,6 +1,6 @@
/*
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
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",
CONFIG_FILE),
TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
- 1,
- 5 /* FIXME: wrong number... */),
+ 2,
+ 270 /* FIXME: wrong number... */),
CMD_RUN_AUDITOR ("virgin-auditor"),
TALER_TESTING_cmd_exchanges_with_url ("check-exchange",
MHD_HTTP_OK,
diff --git a/src/testing/test_exchange_api.c b/src/testing/test_exchange_api.c
index d2e18c41b..f24a3ff73 100644
--- a/src/testing/test_exchange_api.c
+++ b/src/testing/test_exchange_api.c
@@ -880,11 +880,11 @@ run (void *cls,
"{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
- MHD_HTTP_NOT_FOUND),
+ MHD_HTTP_GONE),
/* Test deposit fails after recoup, with proof in recoup */
/* 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",
"recoup-withdraw-coin-2a",
0,
@@ -892,7 +892,7 @@ run (void *cls,
"{\"items\":[{\"name\":\"extra ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:0.5",
- MHD_HTTP_NOT_FOUND),
+ MHD_HTTP_GONE),
/* Test that revoked coins cannot be withdrawn */
CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-3",
"EUR:1.01"),
@@ -906,7 +906,7 @@ run (void *cls,
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-3-revoked",
"recoup-create-reserve-3",
"EUR:1",
- MHD_HTTP_NOT_FOUND),
+ MHD_HTTP_GONE),
/* check that we are empty before the rejection test */
TALER_TESTING_cmd_check_bank_empty ("check-empty-again"),
@@ -958,7 +958,7 @@ run (void *cls,
CONFIG_FILE),
TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
1,
- 5 /* FIXME: wrong number... */),
+ 270 /* FIXME: wrong number... */),
TALER_TESTING_cmd_batch ("wire",
wire),
TALER_TESTING_cmd_batch ("withdraw",
diff --git a/src/testing/test_exchange_api_keys_cherry_picking.c b/src/testing/test_exchange_api_keys_cherry_picking.c
index aab94d68a..588ef7520 100644
--- a/src/testing/test_exchange_api_keys_cherry_picking.c
+++ b/src/testing/test_exchange_api_keys_cherry_picking.c
@@ -129,8 +129,8 @@ run (void *cls,
* Make sure we have the same keys situation as
* it was before the serialization.
*/
- TALER_TESTING_cmd_check_keys_with_now
- ("check-keys-after-deserialization",
+ TALER_TESTING_cmd_check_keys_with_now (
+ "check-keys-after-deserialization",
4,
NDKS_RIGHT_BEFORE_SERIALIZATION,
/**
@@ -198,8 +198,8 @@ run (void *cls,
* ----
* 40
*///
- TALER_TESTING_cmd_check_keys_with_now
- ("check-keys-3",
+ TALER_TESTING_cmd_check_keys_with_now (
+ "check-keys-3",
3 /* generation */,
NDKS_RIGHT_BEFORE_SERIALIZATION,
TTH_parse_time (JAN2030)),
diff --git a/src/testing/test_exchange_api_revocation.c b/src/testing/test_exchange_api_revocation.c
index a952d360c..555891497 100644
--- a/src/testing/test_exchange_api_revocation.c
+++ b/src/testing/test_exchange_api_revocation.c
@@ -73,7 +73,7 @@ run (void *cls,
CONFIG_FILE),
TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
1,
- 5 /* FIXME: wrong number... */),
+ 270 /* FIXME: wrong number... */),
/**
* Fill reserve with EUR:10.02, as withdraw fee is 1 ct per
* config.
diff --git a/src/testing/test_exchange_api_twisted.c b/src/testing/test_exchange_api_twisted.c
index 446bdccc4..05867f89b 100644
--- a/src/testing/test_exchange_api_twisted.c
+++ b/src/testing/test_exchange_api_twisted.c
@@ -222,7 +222,7 @@ run (void *cls,
TALER_TESTING_cmd_check_keys_pull_all_keys (
"check-keys-expiration-0",
2,
- 5),
+ 270),
/**
* Run some normal commands after this to make sure everything is fine.
*/
@@ -237,6 +237,15 @@ run (void *cls,
};
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",
refresh_409_conflict),
TALER_TESTING_cmd_batch ("refund",
diff --git a/src/testing/test_exchange_management_api.c b/src/testing/test_exchange_management_api.c
index 26c6cae8a..18f6dedf6 100644
--- a/src/testing/test_exchange_management_api.c
+++ b/src/testing/test_exchange_management_api.c
@@ -144,7 +144,7 @@ run (void *cls,
CONFIG_FILE),
TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
1,
- 5 /* FIXME: wrong number... */),
+ 270 /* FIXME: wrong number... */),
TALER_TESTING_cmd_end ()
};
diff --git a/src/testing/test_taler_exchange_wirewatch.c b/src/testing/test_taler_exchange_wirewatch.c
index b16a9e769..169c959be 100644
--- a/src/testing/test_taler_exchange_wirewatch.c
+++ b/src/testing/test_taler_exchange_wirewatch.c
@@ -93,7 +93,7 @@ run (void *cls,
config_filename),
TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
1,
- 5 /* FIXME: wrong number... */),
+ 58 /* FIXME: wrong number... */),
TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-on-start"),
CMD_EXEC_AGGREGATOR ("run-aggregator-on-empty"),
TALER_TESTING_cmd_exec_wirewatch ("run-wirewatch-on-empty",
diff --git a/src/testing/testing_api_cmd_offline_sign_keys.c b/src/testing/testing_api_cmd_offline_sign_keys.c
index 70654ea10..dd6170d90 100644
--- a/src/testing/testing_api_cmd_offline_sign_keys.c
+++ b/src/testing/testing_api_cmd_offline_sign_keys.c
@@ -70,6 +70,7 @@ offlinesign_run (void *cls,
"taler-exchange-offline",
"taler-exchange-offline",
"-c", ks->config_filename,
+ "-L", "INFO",
"download",
"sign",
"upload",
@@ -80,8 +81,6 @@ offlinesign_run (void *cls,
TALER_TESTING_interpreter_fail (is);
return;
}
- /* This function does not tell whether the command
- * succeeded or not! */
TALER_TESTING_wait_for_sigchld (is);
}
diff --git a/src/testing/testing_api_cmd_revoke.c b/src/testing/testing_api_cmd_revoke.c
index c43f53727..8863110bd 100644
--- a/src/testing/testing_api_cmd_revoke.c
+++ b/src/testing/testing_api_cmd_revoke.c
@@ -79,8 +79,9 @@ revoke_cleanup (void *cls,
if (NULL != rs->revoke_proc)
{
- GNUNET_break (0 == GNUNET_OS_process_kill
- (rs->revoke_proc, SIGKILL));
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (rs->revoke_proc,
+ SIGKILL));
GNUNET_OS_process_wait (rs->revoke_proc);
GNUNET_OS_process_destroy (rs->revoke_proc);
rs->revoke_proc = NULL;
@@ -163,13 +164,13 @@ revoke_run (void *cls,
rs->dhks = GNUNET_STRINGS_data_to_string_alloc (
&denom_pub->h_key,
sizeof (struct GNUNET_HashCode));
-
rs->revoke_proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
NULL, NULL, NULL,
- "taler-exchange-keyup",
- "taler-exchange-keyup",
+ "taler-exchange-offline",
+ "taler-exchange-offline",
"-c", rs->config_filename,
- "-r", rs->dhks,
+ "revoke-denomination", rs->dhks,
+ "upload",
NULL);
if (NULL == rs->revoke_proc)
diff --git a/src/testing/testing_api_helpers_exchange.c b/src/testing/testing_api_helpers_exchange.c
index 95ba71b7d..a12998e29 100644
--- a/src/testing/testing_api_helpers_exchange.c
+++ b/src/testing/testing_api_helpers_exchange.c
@@ -617,7 +617,7 @@ TALER_TESTING_wait_exchange_ready (const char *base_url)
unsigned int iter;
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 '/'
/* give child time to start and bind against the socket */
fprintf (stderr,
diff --git a/src/testing/testing_api_loop.c b/src/testing/testing_api_loop.c
index 88af481ea..f269274ec 100644
--- a/src/testing/testing_api_loop.c
+++ b/src/testing/testing_api_loop.c
@@ -388,24 +388,25 @@ maint_child_death (void *cls)
struct TALER_TESTING_Interpreter *is = cls;
struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
const struct GNUNET_DISK_FileHandle *pr;
-
struct GNUNET_OS_Process **processp;
char c[16];
+ enum GNUNET_OS_ProcessStatusType type;
+ unsigned long code;
if (TALER_TESTING_cmd_is_batch (cmd))
{
struct TALER_TESTING_Command *batch_cmd;
- GNUNET_assert
- (GNUNET_OK == TALER_TESTING_get_trait_cmd
- (cmd, 0, &batch_cmd)); /* bad? */
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_cmd (cmd,
+ 0,
+ &batch_cmd));
cmd = batch_cmd;
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Got SIGCHLD for `%s'.\n",
cmd->label);
-
is->child_death_task = NULL;
pr = GNUNET_DISK_pipe_handle (sigpipe,
GNUNET_DISK_PIPE_END_READ);
@@ -424,16 +425,45 @@ maint_child_death (void *cls)
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Got the dead child process handle"
- ", waiting for termination ...\n");
-
- GNUNET_OS_process_wait (*processp);
+ "Got the dead child process handle, waiting for termination ...\n");
+ GNUNET_OS_process_wait_status (*processp,
+ &type,
+ &code);
GNUNET_OS_process_destroy (*processp);
*processp = NULL;
-
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"... 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 (NULL == is->exchanged)
@@ -444,8 +474,9 @@ maint_child_death (void *cls)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Triggering key state reload at exchange\n");
- GNUNET_break (0 == GNUNET_OS_process_kill
- (is->exchanged, SIGUSR1));
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (is->exchanged,
+ SIGUSR1));
sleep (5); /* make sure signal was received and processed */
}
}
@@ -643,19 +674,8 @@ TALER_TESTING_cert_cb (void *cls,
* the interpreter is already running. */
if (GNUNET_YES == is->working)
return;
-
is->working = GNUNET_YES;
-
- /* 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. */
+ /* Trigger the next command. */
TALER_LOG_DEBUG ("Cert_cb, scheduling CMD (ip: %d)\n",
is->ip);
GNUNET_SCHEDULER_add_now (&interpreter_run,
@@ -740,6 +760,7 @@ main_wrapper_exchange_connect (void *cls)
main_ctx->exchange_url = exchange_url;
is->timeout_task = GNUNET_SCHEDULER_add_shutdown (&do_abort,
main_ctx);
+ is->working = GNUNET_YES;
GNUNET_break
(NULL != (is->exchange =
TALER_EXCHANGE_connect (is->ctx,
@@ -747,6 +768,10 @@ main_wrapper_exchange_connect (void *cls)
&TALER_TESTING_cert_cb,
main_ctx,
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,10 +867,10 @@ static int
load_urls (struct TALER_TESTING_Interpreter *is)
{
if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (is->cfg,
- "auditor",
- "BASE_URL",
- &is->auditor_url))
+ GNUNET_CONFIGURATION_get_value_string (is->cfg,
+ "auditor",
+ "BASE_URL",
+ &is->auditor_url))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"auditor",
diff --git a/src/util/taler-helper-crypto-rsa.c b/src/util/taler-helper-crypto-rsa.c
index ec1158ee7..32f0b44dd 100644
--- a/src/util/taler-helper-crypto-rsa.c
+++ b/src/util/taler-helper-crypto-rsa.c
@@ -1112,17 +1112,16 @@ read_job (void *cls)
* Create a new denomination key (we do not have enough).
*
* @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
*/
static int
-create_key (struct Denomination *denom)
+create_key (struct Denomination *denom,
+ struct GNUNET_TIME_Absolute now)
{
struct DenominationKey *dk;
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)
{
anchor = now;
@@ -1237,9 +1236,11 @@ purge_key (struct DenominationKey *dk)
* correct location sorted by next maintenance activity.
*
* @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
-update_keys (struct Denomination *denom)
+update_keys (struct Denomination *denom,
+ struct GNUNET_TIME_Absolute now)
{
/* create new denomination keys */
while ( (NULL == denom->keys_tail) ||
@@ -1252,7 +1253,8 @@ update_keys (struct Denomination *denom)
lookahead_sign),
overlap_duration)).rel_value_us) )
if (GNUNET_OK !=
- create_key (denom))
+ create_key (denom,
+ now))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to create keys for `%s'\n",
@@ -1273,18 +1275,19 @@ update_keys (struct Denomination *denom)
struct GNUNET_TIME_Absolute at;
at = denomination_action_time (denom);
- before = NULL;
GNUNET_CONTAINER_DLL_remove (denom_head,
denom_tail,
denom);
+ before = NULL;
for (struct Denomination *pos = denom_head;
NULL != pos;
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;
before = pos;
}
+
GNUNET_CONTAINER_DLL_insert_after (denom_head,
denom_tail,
before,
@@ -1302,12 +1305,16 @@ static void
update_denominations (void *cls)
{
struct Denomination *denom;
+ struct GNUNET_TIME_Absolute now;
(void) cls;
+ now = GNUNET_TIME_absolute_get ();
+ (void) GNUNET_TIME_round_abs (&now);
keygen_task = NULL;
do {
denom = denom_head;
- update_keys (denom);
+ update_keys (denom,
+ now);
} while (denom != denom_head);
keygen_task = GNUNET_SCHEDULER_add_at (denomination_action_time (denom),
&update_denominations,
@@ -1610,17 +1617,34 @@ 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
* 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
*/
static void
load_denominations (void *cls,
const char *denomination_alias)
{
- int *ret = cls;
+ struct LoadContext *ctx = cls;
struct Denomination *denom;
if (0 != strncasecmp (denomination_alias,
@@ -1632,7 +1656,7 @@ load_denominations (void *cls,
parse_denomination_cfg (denomination_alias,
denom))
{
- *ret = GNUNET_SYSERR;
+ ctx->ret = GNUNET_SYSERR;
GNUNET_free (denom);
return;
}
@@ -1656,7 +1680,8 @@ load_denominations (void *cls,
GNUNET_CONTAINER_DLL_insert (denom_head,
denom_tail,
denom);
- update_keys (denom);
+ update_keys (denom,
+ ctx->now);
}
@@ -1905,13 +1930,16 @@ run (void *cls,
keys = GNUNET_CONTAINER_multihashmap_create (65536,
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,
&load_denominations,
- &ok);
- if (GNUNET_OK != ok)
+ &lc);
+ if (GNUNET_OK != lc.ret)
{
global_ret = 4;
GNUNET_SCHEDULER_shutdown ();