more code towards fixing #5447

This commit is contained in:
Christian Grothoff 2019-01-13 16:22:16 +01:00
parent 54fc83ee6b
commit 91566ddee2
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
5 changed files with 301 additions and 87 deletions

2
.gitignore vendored
View File

@ -107,3 +107,5 @@ contrib/auditor-report.pdf
src/bank-lib/taler-bank-transfer src/bank-lib/taler-bank-transfer
src/bank-lib/test_bank_api_twisted src/bank-lib/test_bank_api_twisted
src/lib/test_exchange_api_new src/lib/test_exchange_api_new
src/lib/test_auditor_api
src/lib/test_exchange_api_overlapping_keys_bug

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER 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 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 terms of the GNU General Public License as published by the Free Software
@ -75,6 +75,16 @@ struct TALER_EXCHANGE_DepositHandle
*/ */
struct TALER_DepositConfirmationPS depconf; 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. * Value of the /deposit transaction, including fee.
*/ */
@ -89,21 +99,52 @@ struct TALER_EXCHANGE_DepositHandle
/** /**
* Signature of functions called with the result from our call to the * Function called for each auditor to give us a chance to possibly
* auditor's /deposit-confirmation handler. * launch a deposit confirmation interaction.
* *
* @param cls closure * @param cls closure
* @param http_status HTTP status code, 200 on success * @param ah handle to the auditor
* @param ec taler protocol error status code, 0 on success * @param auditor_pub public key of the auditor
* @param json raw json response * @return NULL if no deposit confirmation interaction was launched
*/ */
static void static struct TEAH_AuditorInteractionEntry *
acc_confirmation_cb (void *cls, auditor_cb (void *cls,
unsigned int http_status, struct TALER_AUDITOR_Handle *ah,
enum TALER_ErrorCode ec, const struct TALER_AuditorPublicKeyP *auditor_pub)
const json_t *json)
{ {
/* 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 * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
*/ */
static int 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, const json_t *json,
struct TALER_ExchangeSignatureP *exchange_sig, struct TALER_ExchangeSignatureP *exchange_sig,
struct TALER_ExchangePublicKeyP *exchange_pub) struct TALER_ExchangePublicKeyP *exchange_pub)
@ -155,37 +196,11 @@ verify_deposit_signature_ok (const struct TALER_EXCHANGE_DepositHandle *dh,
GNUNET_break_op (0); GNUNET_break_op (0);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
if (0 /* #5447: replace with "for all auditors, if auditor selected for DC notification... */) dh->exchange_sig = *exchange_sig;
{ dh->exchange_pub = *exchange_pub;
struct TALER_AUDITOR_DepositConfirmationHandle *dch; TEAH_get_auditors_for_dc (dh->exchange,
const struct TALER_EXCHANGE_SigningPublicKey *spk; &auditor_cb,
struct TALER_Amount amount_without_fee; dh);
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! */);
}
return GNUNET_OK; return GNUNET_OK;
} }

View File

@ -91,47 +91,25 @@ enum ExchangeHandleState
struct KeysRequest; 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. * Entry in DLL of auditors used by an exchange.
*/ */
struct AuditorListEntry struct TEAH_AuditorListEntry
{ {
/** /**
* Next pointer of DLL. * Next pointer of DLL.
*/ */
struct AuditorListEntry *next; struct TEAH_AuditorListEntry *next;
/** /**
* Prev pointer of DLL. * Prev pointer of DLL.
*/ */
struct AuditorListEntry *prev; struct TEAH_AuditorListEntry *prev;
/** /**
* Base URL of the auditor. * Base URL of the auditor.
*/ */
const char *auditor_url; char *auditor_url;
/** /**
* Handle to the auditor. * Handle to the auditor.
@ -141,12 +119,12 @@ struct AuditorListEntry
/** /**
* Head of DLL of interactions with this auditor. * 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. * Tail of DLL of interactions with this auditor.
*/ */
struct AuditorInteractionEntry *ai_tail; struct TEAH_AuditorInteractionEntry *ai_tail;
/** /**
* Public key of the auditor. * Public key of the auditor.
@ -208,12 +186,12 @@ struct TALER_EXCHANGE_Handle
/** /**
* Head of DLL of auditors of this exchange. * 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. * 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 * Key data of the exchange, only valid if
@ -270,6 +248,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 * Iterate over all available auditors for @a h, calling
* @param ah and giving it a chance to start a deposit * @param ah and giving it a chance to start a deposit
@ -284,14 +295,38 @@ TEAH_get_auditors_for_dc (struct TALER_EXCHANGE_Handle *h,
TEAH_AuditorCallback ac, TEAH_AuditorCallback ac,
void *ac_cls) 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. * Release memory occupied by a keys request. Note that this does not
* Note that this does not cancel the request * cancel the request itself.
* itself.
* *
* @param kr request to free * @param kr request to free
*/ */
@ -601,6 +636,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 * Decode the JSON in @a resp_obj from the /keys response
* and store the data in the @a key_data. * 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, GNUNET_array_grow (key_data->auditors,
key_data->auditors_size, key_data->auditors_size,
key_data->auditors_size * 2 + 2); key_data->auditors_size * 2 + 2);
GNUNET_assert (NULL != ai.auditor_url);
key_data->auditors[key_data->num_auditors++] = ai; 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]; struct TALER_EXCHANGE_AuditorInformation *anew = &kd.auditors[i];
anew->auditor_pub = aold->auditor_pub; anew->auditor_pub = aold->auditor_pub;
GNUNET_assert (NULL != aold->auditor_url);
anew->auditor_url = GNUNET_strdup (aold->auditor_url); anew->auditor_url = GNUNET_strdup (aold->auditor_url);
GNUNET_array_grow (anew->denom_keys, GNUNET_array_grow (anew->denom_keys,
anew->num_denom_keys, anew->num_denom_keys,
@ -1072,6 +1193,7 @@ keys_completed_cb (void *cls,
exchange->key_data_expiration = kr->expire; exchange->key_data_expiration = kr->expire;
free_keys_request (kr); free_keys_request (kr);
exchange->state = MHS_CERT; exchange->state = MHS_CERT;
update_auditors (exchange);
/* notify application about the key information */ /* notify application about the key information */
exchange->cert_cb (exchange->cert_cb_cls, exchange->cert_cb (exchange->cert_cb_cls,
&exchange->key_data, &exchange->key_data,
@ -1305,6 +1427,7 @@ deserialize_data (struct TALER_EXCHANGE_Handle *exchange,
exchange->key_data = key_data; exchange->key_data = key_data;
exchange->key_data_expiration = expire; exchange->key_data_expiration = expire;
exchange->state = MHS_CERT; exchange->state = MHS_CERT;
update_auditors (exchange);
/* notify application about the key information */ /* notify application about the key information */
exchange->cert_cb (exchange->cert_cb_cls, exchange->cert_cb (exchange->cert_cb_cls,
&exchange->key_data, &exchange->key_data,
@ -1619,6 +1742,31 @@ request_keys (void *cls)
void void
TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange) 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) if (NULL != exchange->kr)
{ {
GNUNET_CURL_job_cancel (exchange->kr->job); GNUNET_CURL_job_cancel (exchange->kr->job);

View File

@ -26,6 +26,39 @@
#include "taler_crypto_lib.h" #include "taler_crypto_lib.h"
/**
* 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 * Function called for each auditor to give us a chance to possibly
* launch a deposit confirmation interaction. * launch a deposit confirmation interaction.
@ -35,12 +68,28 @@
* @param auditor_pub public key of the auditor * @param auditor_pub public key of the auditor
* @return NULL if no deposit confirmation interaction was launched * @return NULL if no deposit confirmation interaction was launched
*/ */
typedef struct TALER_AUDITOR_DepositConfirmationHandle * typedef struct TEAH_AuditorInteractionEntry *
(*TEAH_AuditorCallback)(void *cls, (*TEAH_AuditorCallback)(void *cls,
struct TALER_AUDITOR_Handle *ah, struct TALER_AUDITOR_Handle *ah,
const struct TALER_AuditorPublicKeyP *auditor_pub); 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 * Iterate over all available auditors for @a h, calling
* @param ah and giving it a chance to start a deposit * @param ah and giving it a chance to start a deposit