summaryrefslogtreecommitdiff
path: root/src/exchange-lib
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2017-04-03 22:45:48 +0200
committerChristian Grothoff <christian@grothoff.org>2017-04-03 22:45:48 +0200
commitcc3aa31732b2c214e6733206e713387d5ef8d39a (patch)
tree635d9f0eab31bf4470c2a69f871dcd82070a8f56 /src/exchange-lib
parentdbb23684031ecb892c931a89006183c741c3fc96 (diff)
downloadexchange-cc3aa31732b2c214e6733206e713387d5ef8d39a.tar.gz
exchange-cc3aa31732b2c214e6733206e713387d5ef8d39a.tar.bz2
exchange-cc3aa31732b2c214e6733206e713387d5ef8d39a.zip
implement #3887-handling in exchange-lib
Diffstat (limited to 'src/exchange-lib')
-rw-r--r--src/exchange-lib/exchange_api_common.c164
-rw-r--r--src/exchange-lib/exchange_api_reserve.c131
2 files changed, 208 insertions, 87 deletions
diff --git a/src/exchange-lib/exchange_api_common.c b/src/exchange-lib/exchange_api_common.c
index 17cfab92b..29d0f6d1c 100644
--- a/src/exchange-lib/exchange_api_common.c
+++ b/src/exchange-lib/exchange_api_common.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2015, 2016 Inria & GNUnet e.V.
+ Copyright (C) 2015-2017 Inria & 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
@@ -65,20 +65,12 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
{
json_t *transaction;
struct TALER_Amount amount;
- struct TALER_CoinSpendSignatureP sig;
- void *details;
- size_t details_size;
const char *type;
- struct GNUNET_JSON_Specification spec[] = {
+ struct GNUNET_JSON_Specification spec_glob[] = {
TALER_JSON_spec_amount ("amount",
- &amount),
+ &amount),
GNUNET_JSON_spec_string ("type",
- &type),
- GNUNET_JSON_spec_fixed_auto ("signature",
- &sig),
- GNUNET_JSON_spec_varsize ("details",
- &details,
- &details_size),
+ &type),
GNUNET_JSON_spec_end()
};
@@ -86,7 +78,7 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
off);
if (GNUNET_OK !=
GNUNET_JSON_parse (transaction,
- spec,
+ spec_glob,
NULL, NULL))
{
GNUNET_break_op (0);
@@ -96,40 +88,47 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
if (0 == strcasecmp (type,
"DEPOSIT"))
{
- const struct TALER_DepositRequestPS *dr;
+ struct TALER_DepositRequestPS dr;
struct TALER_Amount dr_amount;
+ struct TALER_CoinSpendSignatureP sig;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("signature",
+ &sig),
+ GNUNET_JSON_spec_fixed_auto ("details",
+ &dr),
+ GNUNET_JSON_spec_end()
+ };
- if (details_size != sizeof (struct TALER_DepositRequestPS))
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (transaction,
+ spec,
+ NULL, NULL))
{
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
- dr = (const struct TALER_DepositRequestPS *) details;
- if (details_size != ntohl (dr->purpose.size))
+ /* TODO #4980 */
+ if (sizeof (dr) != ntohl (dr.purpose.size))
{
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT,
- &dr->purpose,
+ &dr.purpose,
&sig.eddsa_signature,
&coin_pub->eddsa_pub))
- {
+ {
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
-
TALER_amount_ntoh (&dr_amount,
- &dr->amount_with_fee);
+ &dr.amount_with_fee);
+ /* TODO #4980 */
if (0 != TALER_amount_cmp (&dr_amount,
&amount))
{
GNUNET_break (0);
- GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
add = GNUNET_YES;
@@ -137,39 +136,47 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
else if (0 == strcasecmp (type,
"MELT"))
{
- const struct TALER_RefreshMeltCoinAffirmationPS *rm;
+ struct TALER_RefreshMeltCoinAffirmationPS rm;
struct TALER_Amount rm_amount;
+ struct TALER_CoinSpendSignatureP sig;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("signature",
+ &sig),
+ GNUNET_JSON_spec_fixed_auto ("details",
+ &rm),
+ GNUNET_JSON_spec_end()
+ };
- if (details_size != sizeof (struct TALER_RefreshMeltCoinAffirmationPS))
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (transaction,
+ spec,
+ NULL, NULL))
{
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
- rm = (const struct TALER_RefreshMeltCoinAffirmationPS *) details;
- if (details_size != ntohl (rm->purpose.size))
+ /* TODO #4980 */
+ if (sizeof (rm) != ntohl (rm.purpose.size))
{
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT,
- &rm->purpose,
+ &rm.purpose,
&sig.eddsa_signature,
&coin_pub->eddsa_pub))
{
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
TALER_amount_ntoh (&rm_amount,
- &rm->amount_with_fee);
+ &rm.amount_with_fee);
+ /* TODO #4980 */
if (0 != TALER_amount_cmp (&rm_amount,
&amount))
{
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
add = GNUNET_YES;
@@ -177,55 +184,60 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
else if (0 == strcasecmp (type,
"REFUND"))
{
- const struct TALER_RefundRequestPS *rr;
+ struct TALER_RefundRequestPS rr;
struct TALER_Amount rr_amount;
struct TALER_Amount rr_fee;
struct TALER_Amount rr_delta;
+ struct TALER_CoinSpendSignatureP sig;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("signature",
+ &sig),
+ GNUNET_JSON_spec_fixed_auto ("details",
+ &rr),
+ GNUNET_JSON_spec_end()
+ };
- if (details_size != sizeof (struct TALER_RefundRequestPS))
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (transaction,
+ spec,
+ NULL, NULL))
{
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
- rr = (const struct TALER_RefundRequestPS *) details;
- if (details_size != ntohl (rr->purpose.size))
+ /* TODO #4980 */
+ if (sizeof (rr) != ntohl (rr.purpose.size))
{
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND,
- &rr->purpose,
+ &rr.purpose,
&sig.eddsa_signature,
- &rr->merchant.eddsa_pub))
+ &rr.merchant.eddsa_pub))
{
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
TALER_amount_ntoh (&rr_amount,
- &rr->refund_amount);
- TALER_amount_ntoh (&rr_fee,
- &rr->refund_fee);
+ &rr.refund_amount);
if (GNUNET_OK !=
TALER_amount_subtract (&rr_delta,
&rr_amount,
&rr_fee))
{
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
+ /* TODO #4980 */
if (0 != TALER_amount_cmp (&rr_delta,
&amount))
{
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
- /* NOTE/FIXME: theoretically, we could also check that the given
+ /* NOTE: theoretically, we could also check that the given
merchant_pub and h_proposal_data appear in the
history under deposits. However, there is really no benefit
for the exchange to lie here, so not checking is probably OK
@@ -237,14 +249,59 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
else if (0 == strcasecmp (type,
"PAYBACK"))
{
- GNUNET_break (0); /* #3887 */
+ struct TALER_PaybackConfirmationPS pc;
+ struct TALER_Amount pc_amount;
+ struct TALER_ExchangePublicKeyP exchange_pub;
+ struct TALER_ExchangeSignatureP exchange_sig;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("exchange_sig",
+ &exchange_sig),
+ GNUNET_JSON_spec_fixed_auto ("exchange_pub",
+ &exchange_pub),
+ GNUNET_JSON_spec_fixed_auto ("details",
+ &pc),
+ GNUNET_JSON_spec_end()
+ };
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (transaction,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ /* TODO #4980 */
+ if (sizeof (pc) != ntohl (pc.purpose.size))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK,
+ &pc.purpose,
+ &exchange_sig.eddsa_signature,
+ &exchange_pub.eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ TALER_amount_ntoh (&pc_amount,
+ &pc.payback_amount);
+ /* TODO #4980 */
+ if (0 != TALER_amount_cmp (&pc_amount,
+ &amount))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ add = GNUNET_YES;
}
else
{
/* signature not supported, new version on server? */
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
if (GNUNET_YES == add)
@@ -257,7 +314,6 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
{
/* overflow in history already!? inconceivable! Bad exchange! */
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
}
@@ -277,11 +333,9 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
{
/* overflow in refund history? inconceivable! Bad exchange! */
GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
}
- GNUNET_JSON_parse_free (spec);
}
/* Finally, subtract 'rtotal' from total to handle the subtractions */
diff --git a/src/exchange-lib/exchange_api_reserve.c b/src/exchange-lib/exchange_api_reserve.c
index 900b6462e..6dd48866f 100644
--- a/src/exchange-lib/exchange_api_reserve.c
+++ b/src/exchange-lib/exchange_api_reserve.c
@@ -77,7 +77,8 @@ struct TALER_EXCHANGE_ReserveStatusHandle
* Parse history given in JSON format and return it in binary
* format.
*
- * @param[in] history JSON array with the history
+ * @param exchange connection to the exchange we can use
+ * @param history JSON array with the history
* @param reserve_pub public key of the reserve to inspect
* @param currency currency we expect the balance to be in
* @param[out] balance final balance
@@ -89,7 +90,8 @@ struct TALER_EXCHANGE_ReserveStatusHandle
* #GNUNET_SYSERR if there was a protocol violation in @a history
*/
static int
-parse_reserve_history (const json_t *history,
+parse_reserve_history (struct TALER_EXCHANGE_Handle *exchange,
+ const json_t *history,
const struct TALER_ReservePublicKeyP *reserve_pub,
const char *currency,
struct TALER_Amount *balance,
@@ -214,6 +216,7 @@ parse_reserve_history (const json_t *history,
}
TALER_amount_ntoh (&amount_from_purpose,
&withdraw_purpose.amount_with_fee);
+ /* TODO #4980 */
if (0 != TALER_amount_cmp (&amount,
&amount_from_purpose))
{
@@ -259,13 +262,75 @@ parse_reserve_history (const json_t *history,
else if (0 == strcasecmp (type,
"PAYBACK"))
{
- GNUNET_break (0); /* #3887 */
+ struct TALER_PaybackConfirmationPS pc;
+ struct TALER_Amount amount_from_purpose;
+ struct GNUNET_TIME_Absolute timestamp_from_purpose;
+ struct GNUNET_TIME_Absolute timestamp;
+ const struct TALER_EXCHANGE_Keys *key_state;
+ struct GNUNET_JSON_Specification payback_spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("details",
+ &pc),
+ GNUNET_JSON_spec_fixed_auto ("exchange_sig",
+ &rhistory[off].details.payback_details.exchange_sig),
+ GNUNET_JSON_spec_fixed_auto ("exchange_pub",
+ &rhistory[off].details.payback_details.exchange_pub),
+ GNUNET_JSON_spec_absolute_time ("timetamp",
+ &timestamp),
+ TALER_JSON_spec_amount ("amount",
+ &rhistory[off].amount),
+ GNUNET_JSON_spec_end()
+ };
+
+ rhistory[off].type = TALER_EXCHANGE_RTT_PAYBACK;
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (transaction,
+ payback_spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ rhistory[off].details.payback_details.coin_pub = pc.coin_pub;
+ TALER_amount_ntoh (&amount_from_purpose,
+ &pc.payback_amount);
+ rhistory[off].details.payback_details.timestamp = timestamp;
+ timestamp_from_purpose = GNUNET_TIME_absolute_ntoh (pc.timestamp);
+ /* TODO #4980 */
+ if ( (0 != memcmp (&pc.reserve_pub,
+ reserve_pub,
+ sizeof (*reserve_pub))) ||
+ (timestamp_from_purpose.abs_value_us !=
+ timestamp.abs_value_us) ||
+ (0 != TALER_amount_cmp (&amount_from_purpose,
+ &rhistory[off].amount)) )
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ key_state = TALER_EXCHANGE_get_keys (exchange);
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_test_signing_key (key_state,
+ &rhistory[off].details.payback_details.exchange_pub))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK,
+ &pc.purpose,
+ &rhistory[off].details.payback_details.exchange_sig.eddsa_signature,
+ &rhistory[off].details.payback_details.exchange_pub.eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
/* end type==PAYBACK */
}
else if (0 == strcasecmp (type,
"CLOSING"))
{
- GNUNET_break (0); /* #3887 / #4956 */
+ GNUNET_break (0); /* FIXME: implement with #4956 */
/* end type==CLOSING */
}
else
@@ -304,9 +369,9 @@ handle_reserve_status_finished (void *cls,
long response_code,
const json_t *json)
{
- struct TALER_EXCHANGE_ReserveStatusHandle *wsh = cls;
+ struct TALER_EXCHANGE_ReserveStatusHandle *rsh = cls;
- wsh->job = NULL;
+ rsh->job = NULL;
switch (response_code)
{
case 0:
@@ -346,8 +411,9 @@ handle_reserve_status_finished (void *cls,
struct TALER_EXCHANGE_ReserveHistory rhistory[len];
if (GNUNET_OK !=
- parse_reserve_history (history,
- &wsh->reserve_pub,
+ parse_reserve_history (rsh->exchange,
+ history,
+ &rsh->reserve_pub,
balance.currency,
&balance_from_history,
len,
@@ -366,14 +432,14 @@ handle_reserve_status_finished (void *cls,
response_code = 0;
break;
}
- wsh->cb (wsh->cb_cls,
+ rsh->cb (rsh->cb_cls,
response_code,
TALER_EC_NONE,
json,
&balance,
len,
rhistory);
- wsh->cb = NULL;
+ rsh->cb = NULL;
}
}
break;
@@ -398,14 +464,14 @@ handle_reserve_status_finished (void *cls,
response_code = 0;
break;
}
- if (NULL != wsh->cb)
- wsh->cb (wsh->cb_cls,
+ if (NULL != rsh->cb)
+ rsh->cb (rsh->cb_cls,
response_code,
TALER_JSON_get_error_code (json),
json,
NULL,
0, NULL);
- TALER_EXCHANGE_reserve_status_cancel (wsh);
+ TALER_EXCHANGE_reserve_status_cancel (rsh);
}
@@ -431,7 +497,7 @@ TALER_EXCHANGE_reserve_status (struct TALER_EXCHANGE_Handle *exchange,
TALER_EXCHANGE_ReserveStatusResultCallback cb,
void *cb_cls)
{
- struct TALER_EXCHANGE_ReserveStatusHandle *wsh;
+ struct TALER_EXCHANGE_ReserveStatusHandle *rsh;
struct GNUNET_CURL_Context *ctx;
CURL *eh;
char *pub_str;
@@ -449,12 +515,12 @@ TALER_EXCHANGE_reserve_status (struct TALER_EXCHANGE_Handle *exchange,
"/reserve/status?reserve_pub=%s",
pub_str);
GNUNET_free (pub_str);
- wsh = GNUNET_new (struct TALER_EXCHANGE_ReserveStatusHandle);
- wsh->exchange = exchange;
- wsh->cb = cb;
- wsh->cb_cls = cb_cls;
- wsh->reserve_pub = *reserve_pub;
- wsh->url = MAH_path_to_url (exchange,
+ rsh = GNUNET_new (struct TALER_EXCHANGE_ReserveStatusHandle);
+ rsh->exchange = exchange;
+ rsh->cb = cb;
+ rsh->cb_cls = cb_cls;
+ rsh->reserve_pub = *reserve_pub;
+ rsh->url = MAH_path_to_url (exchange,
arg_str);
GNUNET_free (arg_str);
@@ -462,14 +528,14 @@ TALER_EXCHANGE_reserve_status (struct TALER_EXCHANGE_Handle *exchange,
GNUNET_assert (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_URL,
- wsh->url));
+ rsh->url));
ctx = MAH_handle_to_context (exchange);
- wsh->job = GNUNET_CURL_job_add (ctx,
+ rsh->job = GNUNET_CURL_job_add (ctx,
eh,
GNUNET_NO,
&handle_reserve_status_finished,
- wsh);
- return wsh;
+ rsh);
+ return rsh;
}
@@ -477,18 +543,18 @@ TALER_EXCHANGE_reserve_status (struct TALER_EXCHANGE_Handle *exchange,
* Cancel a withdraw status request. This function cannot be used
* on a request handle if a response is already served for it.
*
- * @param wsh the withdraw status request handle
+ * @param rsh the withdraw status request handle
*/
void
-TALER_EXCHANGE_reserve_status_cancel (struct TALER_EXCHANGE_ReserveStatusHandle *wsh)
+TALER_EXCHANGE_reserve_status_cancel (struct TALER_EXCHANGE_ReserveStatusHandle *rsh)
{
- if (NULL != wsh->job)
+ if (NULL != rsh->job)
{
- GNUNET_CURL_job_cancel (wsh->job);
- wsh->job = NULL;
+ GNUNET_CURL_job_cancel (rsh->job);
+ rsh->job = NULL;
}
- GNUNET_free (wsh->url);
- GNUNET_free (wsh);
+ GNUNET_free (rsh->url);
+ GNUNET_free (rsh);
}
@@ -663,7 +729,8 @@ reserve_withdraw_payment_required (struct TALER_EXCHANGE_ReserveWithdrawHandle *
struct TALER_EXCHANGE_ReserveHistory rhistory[len];
if (GNUNET_OK !=
- parse_reserve_history (history,
+ parse_reserve_history (wsh->exchange,
+ history,
&wsh->reserve_pub,
balance.currency,
&balance_from_history,