summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--src/include/taler_exchange_service.h12
-rw-r--r--src/lib/exchange_api_deposit.c103
-rw-r--r--src/lib/exchange_api_handle.c216
-rw-r--r--src/lib/exchange_api_handle.h55
5 files changed, 301 insertions, 87 deletions
diff --git a/.gitignore b/.gitignore
index 8e3596100..8a99e4be8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -107,3 +107,5 @@ contrib/auditor-report.pdf
src/bank-lib/taler-bank-transfer
src/bank-lib/test_bank_api_twisted
src/lib/test_exchange_api_new
+src/lib/test_auditor_api
+src/lib/test_exchange_api_overlapping_keys_bug
diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h
index 0118d72d7..fa93dca80 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -48,7 +48,7 @@ enum TALER_EXCHANGE_Option
* /keys data (or at least only download the deltas).
*/
TALER_EXCHANGE_OPTION_DATA
-
+
};
@@ -66,7 +66,7 @@ struct TALER_EXCHANGE_SigningPublicKey
* Signature over this signing key by the exchange's master signature.
*/
struct TALER_MasterSignatureP master_sig;
-
+
/**
* Validity start time
*/
@@ -103,7 +103,7 @@ struct TALER_EXCHANGE_DenomPublicKey
* Exchange's master signature over this denomination record.
*/
struct TALER_MasterSignatureP master_sig;
-
+
/**
* Timestamp indicating when the denomination key becomes valid
*/
@@ -167,7 +167,7 @@ struct TALER_EXCHANGE_AuditorDenominationInfo
* denomination.
*/
struct TALER_AuditorSignatureP auditor_sig;
-
+
/**
* Offsets into the key's main `denom_keys` array identifying the
* denomination being audited by this auditor.
@@ -201,7 +201,7 @@ struct TALER_EXCHANGE_AuditorInformation
/**
* Array of length @a num_denom_keys with the denomination
- * keys audited by this auditor.
+ * keys audited by this auditor.
*/
struct TALER_EXCHANGE_AuditorDenominationInfo *denom_keys;
@@ -393,7 +393,7 @@ TALER_EXCHANGE_connect (struct GNUNET_CURL_Context *ctx,
/**
* Serialize the latest key data from @a exchange to be persisted
- * on disk (to be used with #TALER_EXCHANGE_OPTION_DATA to more
+ * on disk (to be used with #TALER_EXCHANGE_OPTION_DATA to more
* efficiently recover the state).
*
* @param exchange which exchange's key and wire data should be serialized
diff --git a/src/lib/exchange_api_deposit.c b/src/lib/exchange_api_deposit.c
index 55b3ca6b3..9ff9d97d3 100644
--- a/src/lib/exchange_api_deposit.c
+++ b/src/lib/exchange_api_deposit.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015, 2018 GNUnet e.V.
+ Copyright (C) 2014, 2015, 2018, 2019 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -76,6 +76,16 @@ struct TALER_EXCHANGE_DepositHandle
struct TALER_DepositConfirmationPS depconf;
/**
+ * Exchange signature, set for #auditor_cb.
+ */
+ struct TALER_ExchangeSignatureP exchange_sig;
+
+ /**
+ * Exchange signing public key, set for #auditor_cb.
+ */
+ struct TALER_ExchangePublicKeyP exchange_pub;
+
+ /**
* Value of the /deposit transaction, including fee.
*/
struct TALER_Amount amount_with_fee;
@@ -89,21 +99,52 @@ struct TALER_EXCHANGE_DepositHandle
/**
- * Signature of functions called with the result from our call to the
- * auditor's /deposit-confirmation handler.
+ * Function called for each auditor to give us a chance to possibly
+ * launch a deposit confirmation interaction.
*
* @param cls closure
- * @param http_status HTTP status code, 200 on success
- * @param ec taler protocol error status code, 0 on success
- * @param json raw json response
+ * @param ah handle to the auditor
+ * @param auditor_pub public key of the auditor
+ * @return NULL if no deposit confirmation interaction was launched
*/
-static void
-acc_confirmation_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- const json_t *json)
+static struct TEAH_AuditorInteractionEntry *
+auditor_cb (void *cls,
+ struct TALER_AUDITOR_Handle *ah,
+ const struct TALER_AuditorPublicKeyP *auditor_pub)
{
- /* FIXME: clean up state, some logging on errors! */
+ struct TALER_EXCHANGE_DepositHandle *dh = cls;
+ const struct TALER_EXCHANGE_Keys *key_state;
+ const struct TALER_EXCHANGE_SigningPublicKey *spk;
+ struct TALER_Amount amount_without_fee;
+ struct TEAH_AuditorInteractionEntry *aie;
+
+ if (1 /* #5447: replace with "for all auditors, if auditor selected for DC notification... */)
+ return NULL;
+ key_state = TALER_EXCHANGE_get_keys (dh->exchange);
+ spk = TALER_EXCHANGE_get_signing_key_details (key_state,
+ &dh->exchange_pub);
+ GNUNET_assert (NULL != spk);
+ TALER_amount_ntoh (&amount_without_fee,
+ &dh->depconf.amount_without_fee);
+ aie = GNUNET_new (struct TEAH_AuditorInteractionEntry);
+ aie->dch = TALER_AUDITOR_deposit_confirmation (ah,
+ &dh->depconf.h_wire,
+ &dh->depconf.h_contract_terms,
+ GNUNET_TIME_absolute_ntoh (dh->depconf.timestamp),
+ GNUNET_TIME_absolute_ntoh (dh->depconf.refund_deadline),
+ &amount_without_fee,
+ &dh->depconf.coin_pub,
+ &dh->depconf.merchant,
+ &dh->exchange_pub,
+ &dh->exchange_sig,
+ &key_state->master_pub,
+ spk->valid_from,
+ spk->valid_until,
+ spk->valid_legal,
+ &spk->master_sig,
+ &TEAH_acc_confirmation_cb,
+ aie);
+ return aie;
}
@@ -118,7 +159,7 @@ acc_confirmation_cb (void *cls,
* @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
*/
static int
-verify_deposit_signature_ok (const struct TALER_EXCHANGE_DepositHandle *dh,
+verify_deposit_signature_ok (struct TALER_EXCHANGE_DepositHandle *dh,
const json_t *json,
struct TALER_ExchangeSignatureP *exchange_sig,
struct TALER_ExchangePublicKeyP *exchange_pub)
@@ -155,37 +196,11 @@ verify_deposit_signature_ok (const struct TALER_EXCHANGE_DepositHandle *dh,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- if (0 /* #5447: replace with "for all auditors, if auditor selected for DC notification... */)
- {
- struct TALER_AUDITOR_DepositConfirmationHandle *dch;
- const struct TALER_EXCHANGE_SigningPublicKey *spk;
- struct TALER_Amount amount_without_fee;
-
- spk = TALER_EXCHANGE_get_signing_key_details (key_state,
- exchange_pub);
- GNUNET_assert (NULL != spk);
- TALER_amount_ntoh (&amount_without_fee,
- &dh->depconf.amount_without_fee);
- dch = TALER_AUDITOR_deposit_confirmation (NULL /* FIXME: auditor */,
- &dh->depconf.h_wire,
- &dh->depconf.h_contract_terms,
- GNUNET_TIME_absolute_ntoh (dh->depconf.timestamp),
- GNUNET_TIME_absolute_ntoh (dh->depconf.refund_deadline),
- &amount_without_fee,
- &dh->depconf.coin_pub,
- &dh->depconf.merchant,
- exchange_pub,
- exchange_sig,
- &key_state->master_pub,
- spk->valid_from,
- spk->valid_until,
- spk->valid_legal,
- &spk->master_sig,
- &acc_confirmation_cb,
- NULL /* FIXME: context! */);
- }
-
-
+ dh->exchange_sig = *exchange_sig;
+ dh->exchange_pub = *exchange_pub;
+ TEAH_get_auditors_for_dc (dh->exchange,
+ &auditor_cb,
+ dh);
return GNUNET_OK;
}
diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c
index 9743b1f09..8eedfd60a 100644
--- a/src/lib/exchange_api_handle.c
+++ b/src/lib/exchange_api_handle.c
@@ -92,46 +92,24 @@ struct KeysRequest;
/**
- * Entry in list of ongoing interactions with an auditor.
- */
-struct AuditorInteractionEntry
-{
- /**
- * DLL entry.
- */
- struct AuditorInteractionEntry *next;
-
- /**
- * DLL entry.
- */
- struct AuditorInteractionEntry *prev;
-
- /**
- * Interaction state.
- */
- struct TALER_AUDITOR_DepositConfirmationHandle *dch;
-};
-
-
-/**
* Entry in DLL of auditors used by an exchange.
*/
-struct AuditorListEntry
+struct TEAH_AuditorListEntry
{
/**
* Next pointer of DLL.
*/
- struct AuditorListEntry *next;
+ struct TEAH_AuditorListEntry *next;
/**
* Prev pointer of DLL.
*/
- struct AuditorListEntry *prev;
+ struct TEAH_AuditorListEntry *prev;
/**
* Base URL of the auditor.
*/
- const char *auditor_url;
+ char *auditor_url;
/**
* Handle to the auditor.
@@ -141,12 +119,12 @@ struct AuditorListEntry
/**
* Head of DLL of interactions with this auditor.
*/
- struct AuditorInteractionEntry *ai_head;
+ struct TEAH_AuditorInteractionEntry *ai_head;
/**
* Tail of DLL of interactions with this auditor.
*/
- struct AuditorInteractionEntry *ai_tail;
+ struct TEAH_AuditorInteractionEntry *ai_tail;
/**
* Public key of the auditor.
@@ -208,12 +186,12 @@ struct TALER_EXCHANGE_Handle
/**
* Head of DLL of auditors of this exchange.
*/
- struct AuditorListEntry *auditors_head;
+ struct TEAH_AuditorListEntry *auditors_head;
/**
* Tail of DLL of auditors of this exchange.
*/
- struct AuditorListEntry *auditors_tail;
+ struct TEAH_AuditorListEntry *auditors_tail;
/**
* Key data of the exchange, only valid if
@@ -271,6 +249,39 @@ struct KeysRequest
/**
+ * Signature of functions called with the result from our call to the
+ * auditor's /deposit-confirmation handler.
+ *
+ * @param cls closure of type `struct TEAH_AuditorInteractionEntry *`
+ * @param http_status HTTP status code, 200 on success
+ * @param ec taler protocol error status code, 0 on success
+ * @param json raw json response
+ */
+void
+TEAH_acc_confirmation_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ const json_t *json)
+{
+ struct TEAH_AuditorInteractionEntry *aie = cls;
+ struct TEAH_AuditorListEntry *ale = aie->ale;
+
+ if (MHD_HTTP_OK != http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Failed to submit deposit confirmation to auditor `%s' with HTTP status %d (EC: %d). This is acceptable if it does not happen often.\n"),
+ ale->auditor_url,
+ http_status,
+ (int) ec);
+ }
+ GNUNET_CONTAINER_DLL_remove (ale->ai_head,
+ ale->ai_tail,
+ aie);
+ GNUNET_free (aie);
+}
+
+
+/**
* Iterate over all available auditors for @a h, calling
* @param ah and giving it a chance to start a deposit
* confirmation interaction.
@@ -284,14 +295,38 @@ TEAH_get_auditors_for_dc (struct TALER_EXCHANGE_Handle *h,
TEAH_AuditorCallback ac,
void *ac_cls)
{
- // FIXME!
+ if (NULL == h->auditors_head)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("No auditor available for exchange `%s'. Not submitting deposit confirmations.\n"),
+ h->url);
+ return;
+ }
+ for (struct TEAH_AuditorListEntry *ale = h->auditors_head;
+ NULL != ale;
+ ale = ale->next)
+ {
+ struct TEAH_AuditorInteractionEntry *aie;
+
+ if (GNUNET_NO == ale->is_up)
+ continue;
+ aie = ac (ac_cls,
+ ale->ah,
+ &ale->auditor_pub);
+ if (NULL != aie)
+ {
+ aie->ale = ale;
+ GNUNET_CONTAINER_DLL_insert (ale->ai_head,
+ ale->ai_tail,
+ aie);
+ }
+ }
}
/**
- * Release memory occupied by a keys request.
- * Note that this does not cancel the request
- * itself.
+ * Release memory occupied by a keys request. Note that this does not
+ * cancel the request itself.
*
* @param kr request to free
*/
@@ -602,6 +637,90 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,
/**
+ * Function called with information about the auditor. Marks an
+ * auditor as 'up'.
+ *
+ * @param cls closure, a `struct TEAH_AuditorListEntry *`
+ * @param vi basic information about the auditor
+ * @param compat protocol compatibility information
+ */
+static void
+auditor_version_cb (void *cls,
+ const struct TALER_AUDITOR_VersionInformation *vi,
+ enum TALER_AUDITOR_VersionCompatibility compat)
+{
+ struct TEAH_AuditorListEntry *ale = cls;
+
+ if (0 != (TALER_AUDITOR_VC_INCOMPATIBLE & compat))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Auditor `%s' runs incompatible protocol version!\n"),
+ ale->auditor_url);
+ if (0 != (TALER_AUDITOR_VC_OLDER & compat))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Auditor `%s' runs outdated protocol version!\n"),
+ ale->auditor_url);
+ }
+ if (0 != (TALER_AUDITOR_VC_NEWER & compat))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Auditor `%s' runs more recent incompatible version. We should upgrade!\n"),
+ ale->auditor_url);
+ }
+ return;
+ }
+ ale->is_up = GNUNET_YES;
+}
+
+
+/**
+ * Recalculate our auditor list, we got /keys and it may have
+ * changed.
+ *
+ * @param exchange exchange for which to update the list.
+ */
+static void
+update_auditors (struct TALER_EXCHANGE_Handle *exchange)
+{
+ struct TALER_EXCHANGE_Keys *kd = &exchange->key_data;
+
+ for (unsigned int i=0;i<kd->num_auditors;i++)
+ {
+ struct TALER_EXCHANGE_AuditorInformation *auditor = &kd->auditors[i];
+ struct TEAH_AuditorListEntry *ale = NULL;
+
+ for (struct TEAH_AuditorListEntry *a = exchange->auditors_head;
+ NULL != a;
+ a = a->next)
+ {
+ if (0 == memcmp (&auditor->auditor_pub,
+ &a->auditor_pub,
+ sizeof (struct TALER_AuditorPublicKeyP)))
+ {
+ ale = a;
+ break;
+ }
+ }
+ if (NULL != ale)
+ continue; /* found, no need to add */
+ /* new auditor, add */
+ ale = GNUNET_new (struct TEAH_AuditorListEntry);
+ ale->auditor_pub = auditor->auditor_pub;
+ ale->auditor_url = GNUNET_strdup (auditor->auditor_url);
+ GNUNET_CONTAINER_DLL_insert (exchange->auditors_head,
+ exchange->auditors_tail,
+ ale);
+ ale->ah = TALER_AUDITOR_connect (exchange->ctx,
+ ale->auditor_url,
+ &auditor_version_cb,
+ ale);
+ }
+}
+
+
+
+/**
* Decode the JSON in @a resp_obj from the /keys response
* and store the data in the @a key_data.
*
@@ -827,6 +946,7 @@ decode_keys_json (const json_t *resp_obj,
GNUNET_array_grow (key_data->auditors,
key_data->auditors_size,
key_data->auditors_size * 2 + 2);
+ GNUNET_assert (NULL != ai.auditor_url);
key_data->auditors[key_data->num_auditors++] = ai;
};
}
@@ -997,6 +1117,7 @@ keys_completed_cb (void *cls,
struct TALER_EXCHANGE_AuditorInformation *anew = &kd.auditors[i];
anew->auditor_pub = aold->auditor_pub;
+ GNUNET_assert (NULL != aold->auditor_url);
anew->auditor_url = GNUNET_strdup (aold->auditor_url);
GNUNET_array_grow (anew->denom_keys,
anew->num_denom_keys,
@@ -1072,6 +1193,7 @@ keys_completed_cb (void *cls,
exchange->key_data_expiration = kr->expire;
free_keys_request (kr);
exchange->state = MHS_CERT;
+ update_auditors (exchange);
/* notify application about the key information */
exchange->cert_cb (exchange->cert_cb_cls,
&exchange->key_data,
@@ -1305,6 +1427,7 @@ deserialize_data (struct TALER_EXCHANGE_Handle *exchange,
exchange->key_data = key_data;
exchange->key_data_expiration = expire;
exchange->state = MHS_CERT;
+ update_auditors (exchange);
/* notify application about the key information */
exchange->cert_cb (exchange->cert_cb_cls,
&exchange->key_data,
@@ -1619,6 +1742,31 @@ request_keys (void *cls)
void
TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange)
{
+ struct TEAH_AuditorListEntry *ale;
+
+ while (NULL != (ale = exchange->auditors_head))
+ {
+ struct TEAH_AuditorInteractionEntry *aie;
+
+ while (NULL != (aie = ale->ai_head))
+ {
+ GNUNET_assert (aie->ale == ale);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Not sending deposit confirmation to auditor `%s' due to exchange disconnect\n"),
+ ale->auditor_url);
+ TALER_AUDITOR_deposit_confirmation_cancel (aie->dch);
+ GNUNET_CONTAINER_DLL_remove (ale->ai_head,
+ ale->ai_tail,
+ aie);
+ GNUNET_free (aie);
+ }
+ GNUNET_CONTAINER_DLL_remove (exchange->auditors_head,
+ exchange->auditors_tail,
+ ale);
+ TALER_AUDITOR_disconnect (ale->ah);
+ GNUNET_free (ale->auditor_url);
+ GNUNET_free (ale);
+ }
if (NULL != exchange->kr)
{
GNUNET_CURL_job_cancel (exchange->kr->job);
diff --git a/src/lib/exchange_api_handle.h b/src/lib/exchange_api_handle.h
index f06fa4eef..2c01e319a 100644
--- a/src/lib/exchange_api_handle.h
+++ b/src/lib/exchange_api_handle.h
@@ -27,21 +27,70 @@
/**
+ * Entry in DLL of auditors used by an exchange.
+ */
+struct TEAH_AuditorListEntry;
+
+
+/**
+ * Entry in list of ongoing interactions with an auditor.
+ */
+struct TEAH_AuditorInteractionEntry
+{
+ /**
+ * DLL entry.
+ */
+ struct TEAH_AuditorInteractionEntry *next;
+
+ /**
+ * DLL entry.
+ */
+ struct TEAH_AuditorInteractionEntry *prev;
+
+ /**
+ * Which auditor is this action associated with?
+ */
+ struct TEAH_AuditorListEntry *ale;
+
+ /**
+ * Interaction state.
+ */
+ struct TALER_AUDITOR_DepositConfirmationHandle *dch;
+};
+
+
+/**
* Function called for each auditor to give us a chance to possibly
- * launch a deposit confirmation interaction.
- *
+ * launch a deposit confirmation interaction.
+ *
* @param cls closure
* @param ah handle to the auditor
* @param auditor_pub public key of the auditor
* @return NULL if no deposit confirmation interaction was launched
*/
-typedef struct TALER_AUDITOR_DepositConfirmationHandle *
+typedef struct TEAH_AuditorInteractionEntry *
(*TEAH_AuditorCallback)(void *cls,
struct TALER_AUDITOR_Handle *ah,
const struct TALER_AuditorPublicKeyP *auditor_pub);
/**
+ * Signature of functions called with the result from our call to the
+ * auditor's /deposit-confirmation handler.
+ *
+ * @param cls closure of type `struct TEAH_AuditorInteractionEntry *`
+ * @param http_status HTTP status code, 200 on success
+ * @param ec taler protocol error status code, 0 on success
+ * @param json raw json response
+ */
+void
+TEAH_acc_confirmation_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ const json_t *json);
+
+
+/**
* Iterate over all available auditors for @a h, calling
* @param ah and giving it a chance to start a deposit
* confirmation interaction.