aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2020-12-15 21:09:36 +0100
committerChristian Grothoff <christian@grothoff.org>2020-12-15 21:09:36 +0100
commit18c12f62347c2c3767a36577f352fc39df532801 (patch)
tree5c69a1a15dbf8a5b6141f44aee1f8d24901648f5 /src
parent97cbf8bd532a07a9263954f1c9685f4a608caf8d (diff)
misc new /keys management related bugfixes
Diffstat (limited to 'src')
-rw-r--r--src/exchange-tools/taler-exchange-offline.c8
-rw-r--r--src/exchange/taler-exchange-httpd.c12
-rw-r--r--src/exchange/taler-exchange-httpd_keys.c272
-rw-r--r--src/exchange/taler-exchange-httpd_keys.h63
-rw-r--r--src/exchange/taler-exchange-httpd_management_post_keys.c14
-rw-r--r--src/lib/exchange_api_management_post_keys.c4
6 files changed, 249 insertions, 124 deletions
diff --git a/src/exchange-tools/taler-exchange-offline.c b/src/exchange-tools/taler-exchange-offline.c
index 0fbcd6726..28bbbe023 100644
--- a/src/exchange-tools/taler-exchange-offline.c
+++ b/src/exchange-tools/taler-exchange-offline.c
@@ -635,8 +635,8 @@ denom_revocation_cb (
"Upload failed for command %u with status %u: %s (%s)\n",
(unsigned int) drr->idx,
hr->http_status,
- TALER_ErrorCode_get_hint (hr->ec),
- hr->hint);
+ hr->hint,
+ TALER_JSON_get_error_hint (hr->reply));
global_ret = 10;
}
GNUNET_CONTAINER_DLL_remove (drr_head,
@@ -724,8 +724,8 @@ signkey_revocation_cb (
"Upload failed for command %u with status %u: %s (%s)\n",
(unsigned int) srr->idx,
hr->http_status,
- TALER_ErrorCode_get_hint (hr->ec),
- hr->hint);
+ hr->hint,
+ TALER_JSON_get_error_hint (hr->reply));
global_ret = 10;
}
GNUNET_CONTAINER_DLL_remove (srr_head,
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
index 6009672f1..eb9d7c46b 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -696,7 +696,7 @@ handle_post_auditors (const struct TEH_RequestHandler *rh,
if ( (NULL == args[0]) ||
(NULL == args[1]) ||
- (NULL != args[0]) )
+ (NULL != args[2]) )
{
GNUNET_break_op (0);
return r404 (connection, "/auditors/$AUDITOR_PUB/$H_DENOM_PUB");
@@ -1476,12 +1476,7 @@ run_main_loop (int fh,
}
atexit (&write_stats);
- ret = TEH_keys_init ();
- if (GNUNET_OK == ret)
- {
- ret = TEH_loop_run ();
- TEH_loop_done ();
- }
+ ret = TEH_loop_run ();
switch (ret)
{
case GNUNET_OK:
@@ -1696,6 +1691,9 @@ main (int argc,
if (GNUNET_OK !=
TEH_WIRE_init ())
return 42;
+ if (GNUNET_OK !=
+ TEH_keys_init ())
+ return 43;
ret = TEH_loop_init ();
if (GNUNET_OK == ret)
{
diff --git a/src/exchange/taler-exchange-httpd_keys.c b/src/exchange/taler-exchange-httpd_keys.c
index fe7a024cf..e955cd953 100644
--- a/src/exchange/taler-exchange-httpd_keys.c
+++ b/src/exchange/taler-exchange-httpd_keys.c
@@ -293,6 +293,12 @@ struct TEH_KeyStateHandle
*/
struct GNUNET_TIME_Absolute next_reload;
+ /**
+ * True if #finish_keys_response() was not yet run and this key state
+ * is only suitable for the /management/keys API.
+ */
+ bool management_only;
+
};
@@ -888,7 +894,10 @@ TEH_keys_init ()
if (0 !=
pthread_key_create (&key_state,
&destroy_key_state_cb))
+ {
+ GNUNET_break (0);
return GNUNET_SYSERR;
+ }
key_state_available = true;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
@@ -1125,87 +1134,6 @@ auditor_denom_cb (
/**
- * Create a key state.
- *
- * @param[in] hs helper state to (re)use, NULL if not available
- * @return NULL on error (i.e. failed to access database)
- */
-static struct TEH_KeyStateHandle *
-build_key_state (struct HelperState *hs)
-{
- struct TEH_KeyStateHandle *ksh;
- enum GNUNET_DB_QueryStatus qs;
-
- 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! */
- ksh->key_generation = key_generation;
- if (NULL == hs)
- {
- if (GNUNET_OK !=
- setup_key_helpers (&ksh->helpers))
- {
- GNUNET_free (ksh);
- return NULL;
- }
- }
- else
- {
- ksh->helpers = *hs;
- }
- ksh->denomkey_map = GNUNET_CONTAINER_multihashmap_create (1024,
- GNUNET_YES);
- ksh->signkey_map = GNUNET_CONTAINER_multipeermap_create (32,
- GNUNET_NO /* MUST be NO! */);
- ksh->auditors = json_array ();
- /* NOTE: fetches master-signed signkeys, but ALSO those that were revoked! */
- qs = TEH_plugin->iterate_denominations (TEH_plugin->cls,
- &denomination_info_cb,
- ksh);
- if (qs < 0)
- {
- GNUNET_break (0);
- destroy_key_state (ksh,
- true);
- return NULL;
- }
- /* NOTE: ONLY fetches non-revoked AND master-signed signkeys! */
- qs = TEH_plugin->iterate_active_signkeys (TEH_plugin->cls,
- &signkey_info_cb,
- ksh);
- if (qs < 0)
- {
- GNUNET_break (0);
- destroy_key_state (ksh,
- true);
- return NULL;
- }
- qs = TEH_plugin->iterate_active_auditors (TEH_plugin->cls,
- &auditor_info_cb,
- ksh);
- if (qs < 0)
- {
- GNUNET_break (0);
- destroy_key_state (ksh,
- true);
- return NULL;
- }
- qs = TEH_plugin->iterate_auditor_denominations (TEH_plugin->cls,
- &auditor_denom_cb,
- ksh);
- if (qs < 0)
- {
- GNUNET_break (0);
- destroy_key_state (ksh,
- true);
- return NULL;
- }
- return ksh;
-}
-
-
-/**
* Closure for #add_sign_key_cb.
*/
struct SignKeyCtx
@@ -1462,9 +1390,10 @@ create_krd (struct TEH_KeyStateHandle *ksh,
enum TALER_ErrorCode ec;
if (TALER_EC_NONE !=
- (ec = TEH_keys_exchange_sign (&ks,
- &exchange_pub,
- &exchange_sig)))
+ (ec = TEH_keys_exchange_sign2 (ksh,
+ &ks,
+ &exchange_pub,
+ &exchange_sig)))
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Could not create key response data: cannot sign (%s)\n",
@@ -1544,7 +1473,7 @@ create_krd (struct TEH_KeyStateHandle *ksh,
/**
- * Update the "/keys" responses in @a ksh up to @a now into the future.
+ * Update the "/keys" responses in @a ksh, computing the detailed replies.
*
* This function is to recompute all (including cherry-picked) responses we
* might want to return, based on the state already in @a ksh.
@@ -1553,7 +1482,7 @@ create_krd (struct TEH_KeyStateHandle *ksh,
* @return #GNUNET_OK on success
*/
static int
-update_keys_response (struct TEH_KeyStateHandle *ksh)
+finish_keys_response (struct TEH_KeyStateHandle *ksh)
{
json_t *recoup;
struct SignKeyCtx sctx;
@@ -1686,10 +1615,109 @@ update_keys_response (struct TEH_KeyStateHandle *ksh)
json_decref (sctx.signkeys);
json_decref (recoup);
json_decref (denoms);
+ ksh->management_only = false;
return GNUNET_OK;
}
+/**
+ * Create a key state.
+ *
+ * @param[in] hs helper state to (re)use, NULL if not available
+ * @param management_only if we should NOT run 'finish_keys_response()'
+ * because we only need the state for the /management/keys API
+ * @return NULL on error (i.e. failed to access database)
+ */
+static struct TEH_KeyStateHandle *
+build_key_state (struct HelperState *hs,
+ bool management_only)
+{
+ struct TEH_KeyStateHandle *ksh;
+ enum GNUNET_DB_QueryStatus qs;
+
+ 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! */
+ ksh->key_generation = key_generation;
+ if (NULL == hs)
+ {
+ if (GNUNET_OK !=
+ setup_key_helpers (&ksh->helpers))
+ {
+ GNUNET_free (ksh);
+ return NULL;
+ }
+ }
+ else
+ {
+ ksh->helpers = *hs;
+ }
+ ksh->denomkey_map = GNUNET_CONTAINER_multihashmap_create (1024,
+ GNUNET_YES);
+ ksh->signkey_map = GNUNET_CONTAINER_multipeermap_create (32,
+ GNUNET_NO /* MUST be NO! */);
+ ksh->auditors = json_array ();
+ /* NOTE: fetches master-signed signkeys, but ALSO those that were revoked! */
+ qs = TEH_plugin->iterate_denominations (TEH_plugin->cls,
+ &denomination_info_cb,
+ ksh);
+ if (qs < 0)
+ {
+ GNUNET_break (0);
+ destroy_key_state (ksh,
+ true);
+ return NULL;
+ }
+ /* NOTE: ONLY fetches non-revoked AND master-signed signkeys! */
+ qs = TEH_plugin->iterate_active_signkeys (TEH_plugin->cls,
+ &signkey_info_cb,
+ ksh);
+ if (qs < 0)
+ {
+ GNUNET_break (0);
+ destroy_key_state (ksh,
+ true);
+ return NULL;
+ }
+ qs = TEH_plugin->iterate_active_auditors (TEH_plugin->cls,
+ &auditor_info_cb,
+ ksh);
+ if (qs < 0)
+ {
+ GNUNET_break (0);
+ destroy_key_state (ksh,
+ true);
+ return NULL;
+ }
+ qs = TEH_plugin->iterate_auditor_denominations (TEH_plugin->cls,
+ &auditor_denom_cb,
+ ksh);
+ if (qs < 0)
+ {
+ GNUNET_break (0);
+ destroy_key_state (ksh,
+ true);
+ return NULL;
+ }
+ if (management_only)
+ {
+ ksh->management_only = true;
+ return ksh;
+ }
+ if (GNUNET_OK !=
+ finish_keys_response (ksh))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Could not finish /keys response (likely no signing keys available yet)\n");
+ destroy_key_state (ksh,
+ true);
+ return NULL;
+ }
+ return ksh;
+}
+
+
void
TEH_keys_update_states ()
{
@@ -1699,8 +1727,16 @@ TEH_keys_update_states ()
}
-struct TEH_KeyStateHandle *
-TEH_get_key_state (void)
+/**
+ * Obtain the key state for the current thread. Should ONLY be used
+ * directly if @a management_only is true. Otherwise use #TEH_get_key_state().
+ *
+ * @param management_only if we should NOT run 'finish_keys_response()'
+ * because we only need the state for the /management/keys API
+ * @return NULL on error
+ */
+static struct TEH_KeyStateHandle *
+get_key_state (bool management_only)
{
struct TEH_KeyStateHandle *old_ksh;
struct TEH_KeyStateHandle *ksh;
@@ -1709,7 +1745,8 @@ TEH_get_key_state (void)
old_ksh = pthread_getspecific (key_state);
if (NULL == old_ksh)
{
- ksh = build_key_state (NULL);
+ ksh = build_key_state (NULL,
+ management_only);
if (NULL == ksh)
return NULL;
if (0 != pthread_setspecific (key_state,
@@ -1728,7 +1765,8 @@ TEH_get_key_state (void)
"Rebuilding /keys, generation upgrade from %llu to %llu\n",
(unsigned long long) old_ksh->key_generation,
(unsigned long long) key_generation);
- ksh = build_key_state (&old_ksh->helpers);
+ ksh = build_key_state (&old_ksh->helpers,
+ management_only);
if (0 != pthread_setspecific (key_state,
ksh))
{
@@ -1748,6 +1786,24 @@ TEH_get_key_state (void)
}
+struct TEH_KeyStateHandle *
+TEH_get_key_state (void)
+{
+ struct TEH_KeyStateHandle *ksh;
+
+ ksh = get_key_state (false);
+ if (NULL == ksh)
+ return NULL;
+ if (ksh->management_only)
+ {
+ if (GNUNET_OK !=
+ finish_keys_response (ksh))
+ return NULL;
+ }
+ return ksh;
+}
+
+
struct TEH_DenominationKey *
TEH_keys_denomination_by_hash (const struct GNUNET_HashCode *h_denom_pub,
enum TALER_ErrorCode *ec,
@@ -1830,13 +1886,12 @@ TEH_keys_denomination_revoke (const struct GNUNET_HashCode *h_denom_pub)
enum TALER_ErrorCode
-TEH_keys_exchange_sign_ (const struct
- GNUNET_CRYPTO_EccSignaturePurpose *purpose,
- struct TALER_ExchangePublicKeyP *pub,
- struct TALER_ExchangeSignatureP *sig)
+TEH_keys_exchange_sign_ (
+ const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+ struct TALER_ExchangePublicKeyP *pub,
+ struct TALER_ExchangeSignatureP *sig)
{
struct TEH_KeyStateHandle *ksh;
- enum TALER_ErrorCode ec;
ksh = TEH_get_key_state ();
if (NULL == ksh)
@@ -1847,6 +1902,22 @@ TEH_keys_exchange_sign_ (const struct
"Cannot sign request, no valid signing keys available.\n");
return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
}
+ return TEH_keys_exchange_sign2_ (ksh,
+ purpose,
+ pub,
+ sig);
+}
+
+
+enum TALER_ErrorCode
+TEH_keys_exchange_sign2_ (
+ struct TEH_KeyStateHandle *ksh,
+ const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+ struct TALER_ExchangePublicKeyP *pub,
+ struct TALER_ExchangeSignatureP *sig)
+{
+ enum TALER_ErrorCode ec;
+
ec = TALER_CRYPTO_helper_esign_sign_ (ksh->helpers.esh,
purpose,
pub,
@@ -1971,11 +2042,6 @@ TEH_keys_get_handler (const struct TEH_RequestHandler *rh,
{
return suspend_request (connection);
}
- if (GNUNET_OK !=
- update_keys_response (ksh))
- {
- return suspend_request (connection);
- }
krd = bsearch (&last_issue_date,
ksh->krd_array,
ksh->krd_array_length,
@@ -2152,7 +2218,7 @@ TEH_keys_load_fees (const struct GNUNET_HashCode *h_denom_pub,
struct HelperDenomination *hd;
int ok;
- ksh = TEH_get_key_state ();
+ ksh = get_key_state (true);
if (NULL == ksh)
{
GNUNET_break (0);
@@ -2184,7 +2250,7 @@ TEH_keys_get_timing (const struct TALER_ExchangePublicKeyP *exchange_pub,
struct HelperSignkey *hsk;
struct GNUNET_PeerIdentity pid;
- ksh = TEH_get_key_state ();
+ ksh = get_key_state (true);
if (NULL == ksh)
{
GNUNET_break (0);
@@ -2354,7 +2420,7 @@ TEH_keys_management_get_handler (const struct TEH_RequestHandler *rh,
struct TEH_KeyStateHandle *ksh;
json_t *reply;
- ksh = TEH_get_key_state ();
+ ksh = get_key_state (true);
if (NULL == ksh)
{
GNUNET_break (0);
diff --git a/src/exchange/taler-exchange-httpd_keys.h b/src/exchange/taler-exchange-httpd_keys.h
index 1bdabd0fd..54dc8c73e 100644
--- a/src/exchange/taler-exchange-httpd_keys.h
+++ b/src/exchange/taler-exchange-httpd_keys.h
@@ -217,10 +217,31 @@ TEH_resume_keys_requests (bool do_shutdown);
* @return #TALER_EC_NONE on success
*/
enum TALER_ErrorCode
-TEH_keys_exchange_sign_ (const struct
- GNUNET_CRYPTO_EccSignaturePurpose *purpose,
- struct TALER_ExchangePublicKeyP *pub,
- struct TALER_ExchangeSignatureP *sig);
+TEH_keys_exchange_sign_ (
+ const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+ struct TALER_ExchangePublicKeyP *pub,
+ struct TALER_ExchangeSignatureP *sig);
+
+
+/**
+ * Sign the message in @a purpose with the exchange's signing key.
+ *
+ * The @a purpose data is the beginning of the data of which the signature is
+ * to be created. The `size` field in @a purpose must correctly indicate the
+ * number of bytes of the data structure, including its header. Use
+ * #TEH_keys_exchange_sign() instead of calling this function directly!
+ *
+ * @param purpose the message to sign
+ * @param[out] pub set to the current public signing key of the exchange
+ * @param[out] sig signature over purpose using current signing key
+ * @return #TALER_EC_NONE on success
+ */
+enum TALER_ErrorCode
+TEH_keys_exchange_sign2_ (
+ struct TEH_KeyStateHandle *ksh,
+ const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+ struct TALER_ExchangePublicKeyP *pub,
+ struct TALER_ExchangeSignatureP *sig);
/**
@@ -251,6 +272,40 @@ TEH_keys_exchange_sign_ (const struct
/**
+ * @ingroup crypto
+ * @brief EdDSA sign a given block.
+ *
+ * The @a ps data must be a fixed-size struct for which the signature is to be
+ * created. The `size` field in @a ps->purpose must correctly indicate the
+ * number of bytes of the data structure, including its header.
+ *
+ * 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 ksh key state to use
+ * @param ps packed struct with what to sign, MUST begin with a purpose
+ * @param[out] pub where to store the public key to use for the signing
+ * @param[out] sig where to write the signature
+ * @return #TALER_EC_NONE on success
+ */
+#define TEH_keys_exchange_sign2(ksh,ps,pub,sig) \
+ ({ \
+ /* check size is set correctly */ \
+ GNUNET_assert (htonl ((ps)->purpose.size) == \
+ sizeof (*ps)); \
+ /* check 'ps' begins with the purpose */ \
+ GNUNET_static_assert (((void*) (ps)) == \
+ ((void*) &(ps)->purpose)); \
+ TEH_keys_exchange_sign2_ (ksh, \
+ &(ps)->purpose, \
+ pub, \
+ sig); \
+ })
+
+
+/**
* Revoke the given exchange's signing key.
* This function should be called AFTER the database was
* updated, as it also triggers #TEH_keys_update_states().
diff --git a/src/exchange/taler-exchange-httpd_management_post_keys.c b/src/exchange/taler-exchange-httpd_management_post_keys.c
index 84ec1f531..df044b6d7 100644
--- a/src/exchange/taler-exchange-httpd_management_post_keys.c
+++ b/src/exchange/taler-exchange-httpd_management_post_keys.c
@@ -157,7 +157,7 @@ add_keys (void *cls,
MHD_HTTP_NOT_FOUND,
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN,
GNUNET_h2s (&akc->d_sigs[i].h_denom_pub));
- return qs;
+ return GNUNET_DB_STATUS_HARD_ERROR;
}
}
else
@@ -183,11 +183,12 @@ add_keys (void *cls,
&akc->d_sigs[i].master_sig))
{
GNUNET_break_op (0);
- return TALER_MHD_reply_with_error (
+ *mhd_ret = TALER_MHD_reply_with_error (
connection,
MHD_HTTP_FORBIDDEN,
- TALER_EC_EXCHANGE_MANAGEMENT_KEYS_SIGNKEY_ADD_SIGNATURE_INVALID,
+ TALER_EC_EXCHANGE_MANAGEMENT_KEYS_DENOMKEY_ADD_SIGNATURE_INVALID,
GNUNET_h2s (&akc->d_sigs[i].h_denom_pub));
+ return GNUNET_DB_STATUS_HARD_ERROR;
}
}
if (is_active)
@@ -253,7 +254,7 @@ add_keys (void *cls,
MHD_HTTP_NOT_FOUND,
TALER_EC_EXCHANGE_MANAGEMENT_KEYS_SIGNKEY_UNKNOWN,
TALER_B2S (&akc->s_sigs[i].exchange_pub));
- return qs;
+ return GNUNET_DB_STATUS_HARD_ERROR;
}
}
else
@@ -273,11 +274,12 @@ add_keys (void *cls,
&akc->s_sigs[i].master_sig))
{
GNUNET_break_op (0);
- return TALER_MHD_reply_with_error (
+ *mhd_ret = TALER_MHD_reply_with_error (
connection,
MHD_HTTP_FORBIDDEN,
- TALER_EC_EXCHANGE_MANAGEMENT_KEYS_DENOMKEY_ADD_SIGNATURE_INVALID,
+ TALER_EC_EXCHANGE_MANAGEMENT_KEYS_SIGNKEY_ADD_SIGNATURE_INVALID,
GNUNET_h2s (&akc->d_sigs[i].h_denom_pub));
+ return GNUNET_DB_STATUS_HARD_ERROR;
}
}
if (is_active)
diff --git a/src/lib/exchange_api_management_post_keys.c b/src/lib/exchange_api_management_post_keys.c
index b885df7f2..7b37bb0ca 100644
--- a/src/lib/exchange_api_management_post_keys.c
+++ b/src/lib/exchange_api_management_post_keys.c
@@ -95,6 +95,10 @@ handle_post_keys_finished (void *cls,
hr.ec = TALER_JSON_get_error_code (json);
hr.hint = TALER_JSON_get_error_hint (json);
break;
+ case MHD_HTTP_NOT_FOUND:
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ break;
default:
/* unexpected response code */
GNUNET_break_op (0);