aboutsummaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/exchange_api_common.c155
-rw-r--r--src/lib/exchange_api_deposit.c57
-rw-r--r--src/lib/exchange_api_melt.c56
-rw-r--r--src/lib/exchange_api_recoup.c40
4 files changed, 269 insertions, 39 deletions
diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c
index 17be0d51b..feaef7b3d 100644
--- a/src/lib/exchange_api_common.c
+++ b/src/lib/exchange_api_common.c
@@ -447,6 +447,7 @@ TALER_EXCHANGE_free_reserve_history (
* @param currency expected currency for the coin
* @param coin_pub public key of the coin
* @param history history of the coin in json encoding
+ * @param[out] h_denom_pub set to the hash of the coin's denomination (if available)
* @param[out] total how much of the coin has been spent according to @a history
* @return #GNUNET_OK if @a history is valid, #GNUNET_SYSERR if not
*/
@@ -456,6 +457,7 @@ TALER_EXCHANGE_verify_coin_history (
const char *currency,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
json_t *history,
+ struct GNUNET_HashCode *h_denom_pub,
struct TALER_Amount *total)
{
size_t len;
@@ -558,6 +560,7 @@ TALER_EXCHANGE_verify_coin_history (
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
+ *h_denom_pub = dr.h_denom_pub;
if (NULL != dk)
{
/* check that deposit fee matches our expectations from /keys! */
@@ -615,6 +618,7 @@ TALER_EXCHANGE_verify_coin_history (
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
+ *h_denom_pub = rm.h_denom_pub;
if (NULL != dk)
{
/* check that melt fee matches our expectations from /keys! */
@@ -703,16 +707,159 @@ TALER_EXCHANGE_verify_coin_history (
else if (0 == strcasecmp (type,
"RECOUP"))
{
- struct TALER_RecoupConfirmationPS pc;
+ struct TALER_RecoupConfirmationPS pc = {
+ .purpose.size = htonl (sizeof (pc)),
+ .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP),
+ .coin_pub = *coin_pub
+ };
+ struct TALER_RecoupRequestPS rr = {
+ .purpose.size = htonl (sizeof (pc)),
+ .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP),
+ .coin_pub = *coin_pub
+ };
struct TALER_ExchangePublicKeyP exchange_pub;
struct TALER_ExchangeSignatureP exchange_sig;
+ struct TALER_CoinSpendSignatureP coin_sig;
struct GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_amount_nbo ("amount",
+ &pc.recoup_amount),
GNUNET_JSON_spec_fixed_auto ("exchange_sig",
&exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub",
&exchange_pub),
GNUNET_JSON_spec_fixed_auto ("reserve_pub",
&pc.reserve_pub),
+ GNUNET_JSON_spec_fixed_auto ("coin_sig",
+ &coin_sig),
+ GNUNET_JSON_spec_fixed_auto ("coin_blind",
+ &rr.coin_blind),
+ GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
+ &rr.h_denom_pub),
+ TALER_JSON_spec_absolute_time_nbo ("timestamp",
+ &pc.timestamp),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (transaction,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ TALER_amount_hton (&pc.recoup_amount,
+ &amount);
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP,
+ &pc,
+ &exchange_sig.eddsa_signature,
+ &exchange_pub.eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_RECOUP,
+ &rr,
+ &coin_sig.eddsa_signature,
+ &coin_pub->eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ *h_denom_pub = rr.h_denom_pub;
+ add = GNUNET_YES;
+ }
+ else if (0 == strcasecmp (type,
+ "RECOUP-REFRESH"))
+ {
+ struct TALER_RecoupRefreshConfirmationPS pc = {
+ .purpose.size = htonl (sizeof (pc)),
+ .purpose.purpose = htonl (
+ TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH),
+ .coin_pub = *coin_pub
+ };
+ struct TALER_RecoupRequestPS rr = {
+ .purpose.size = htonl (sizeof (pc)),
+ .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP),
+ .coin_pub = *coin_pub
+ };
+ struct TALER_ExchangePublicKeyP exchange_pub;
+ struct TALER_ExchangeSignatureP exchange_sig;
+ struct TALER_CoinSpendSignatureP coin_sig;
+ struct GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_amount_nbo ("amount",
+ &pc.recoup_amount),
+ GNUNET_JSON_spec_fixed_auto ("exchange_sig",
+ &exchange_sig),
+ GNUNET_JSON_spec_fixed_auto ("exchange_pub",
+ &exchange_pub),
+ GNUNET_JSON_spec_fixed_auto ("coin_sig",
+ &coin_sig),
+ GNUNET_JSON_spec_fixed_auto ("old_coin_pub",
+ &pc.old_coin_pub),
+ GNUNET_JSON_spec_fixed_auto ("coin_blind",
+ &rr.coin_blind),
+ GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
+ &rr.h_denom_pub),
+ TALER_JSON_spec_absolute_time_nbo ("timestamp",
+ &pc.timestamp),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (transaction,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ TALER_amount_hton (&pc.recoup_amount,
+ &amount);
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (
+ TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH,
+ &pc,
+ &exchange_sig.eddsa_signature,
+ &exchange_pub.eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_RECOUP,
+ &rr,
+ &coin_sig.eddsa_signature,
+ &coin_pub->eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ *h_denom_pub = rr.h_denom_pub;
+ add = GNUNET_YES;
+ }
+ else if (0 == strcasecmp (type,
+ "OLD-COIN-RECOUP"))
+ {
+ struct TALER_RecoupRefreshConfirmationPS pc = {
+ .purpose.size = htonl (sizeof (pc)),
+ .purpose.purpose = htonl (
+ TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH),
+ .old_coin_pub = *coin_pub
+ };
+ struct TALER_ExchangePublicKeyP exchange_pub;
+ struct TALER_ExchangeSignatureP exchange_sig;
+ struct GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_amount_nbo ("amount",
+ &pc.recoup_amount),
+ GNUNET_JSON_spec_fixed_auto ("exchange_sig",
+ &exchange_sig),
+ GNUNET_JSON_spec_fixed_auto ("exchange_pub",
+ &exchange_pub),
+ GNUNET_JSON_spec_fixed_auto ("coin_pub",
+ &pc.coin_pub),
TALER_JSON_spec_absolute_time_nbo ("timestamp",
&pc.timestamp),
GNUNET_JSON_spec_end ()
@@ -726,9 +873,6 @@ TALER_EXCHANGE_verify_coin_history (
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- pc.purpose.size = htonl (sizeof (pc));
- pc.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP);
- pc.coin_pub = *coin_pub;
TALER_amount_hton (&pc.recoup_amount,
&amount);
if (GNUNET_OK !=
@@ -749,6 +893,7 @@ TALER_EXCHANGE_verify_coin_history (
GNUNET_assert (GNUNET_SYSERR == add);
return GNUNET_SYSERR;
}
+
if (GNUNET_YES == add)
{
/* This amount should be added to the total */
@@ -779,9 +924,11 @@ TALER_EXCHANGE_verify_coin_history (
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
+
}
}
+
/* Finally, subtract 'rtotal' from total to handle the subtractions */
if (0 >
TALER_amount_subtract (total,
diff --git a/src/lib/exchange_api_deposit.c b/src/lib/exchange_api_deposit.c
index ba3ba48e0..51783dbb4 100644
--- a/src/lib/exchange_api_deposit.c
+++ b/src/lib/exchange_api_deposit.c
@@ -246,13 +246,18 @@ verify_deposit_signature_ok (struct TALER_EXCHANGE_DepositHandle *dh,
* @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not
*/
static int
-verify_deposit_signature_forbidden (
+verify_deposit_signature_conflict (
const struct TALER_EXCHANGE_DepositHandle *dh,
const json_t *json)
{
json_t *history;
struct TALER_Amount total;
+ enum TALER_ErrorCode ec;
+ struct GNUNET_HashCode h_denom_pub;
+ memset (&h_denom_pub,
+ 0,
+ sizeof (h_denom_pub));
history = json_object_get (json,
"history");
if (GNUNET_OK !=
@@ -260,30 +265,46 @@ verify_deposit_signature_forbidden (
dh->dki.value.currency,
&dh->depconf.coin_pub,
history,
+ &h_denom_pub,
&total))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- if (0 >
- TALER_amount_add (&total,
- &total,
- &dh->amount_with_fee))
+ ec = TALER_JSON_get_error_code (json);
+ switch (ec)
{
- /* clearly not OK if our transaction would have caused
- the overflow... */
- return GNUNET_OK;
- }
+ case TALER_EC_DEPOSIT_INSUFFICIENT_FUNDS:
+ if (0 >
+ TALER_amount_add (&total,
+ &total,
+ &dh->amount_with_fee))
+ {
+ /* clearly not OK if our transaction would have caused
+ the overflow... */
+ return GNUNET_OK;
+ }
- if (0 >= TALER_amount_cmp (&total,
- &dh->dki.value))
- {
- /* transaction should have still fit */
- GNUNET_break (0);
+ if (0 >= TALER_amount_cmp (&total,
+ &dh->dki.value))
+ {
+ /* transaction should have still fit */
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ /* everything OK, proof of double-spending was provided */
+ return GNUNET_OK;
+ case TALER_EC_COIN_CONFLICTING_DENOMINATION_KEY:
+ if (0 != GNUNET_memcmp (&dh->dki.h_key,
+ &h_denom_pub))
+ return GNUNET_OK; /* indeed, proof with different denomination key provided */
+ /* invalid proof provided */
+ return GNUNET_SYSERR;
+ default:
+ /* unexpected error code */
+ GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- /* everything OK, proof of double-spending was provided */
- return GNUNET_OK;
}
@@ -343,8 +364,8 @@ handle_deposit_finished (void *cls,
case MHD_HTTP_CONFLICT:
/* Double spending; check signatures on transaction history */
if (GNUNET_OK !=
- verify_deposit_signature_forbidden (dh,
- j))
+ verify_deposit_signature_conflict (dh,
+ j))
{
GNUNET_break_op (0);
hr.http_status = 0;
diff --git a/src/lib/exchange_api_melt.c b/src/lib/exchange_api_melt.c
index 1ef83bf73..2c1e85d7b 100644
--- a/src/lib/exchange_api_melt.c
+++ b/src/lib/exchange_api_melt.c
@@ -178,6 +178,8 @@ verify_melt_signature_conflict (struct TALER_EXCHANGE_MeltHandle *mh,
GNUNET_JSON_spec_end ()
};
const struct MeltedCoin *mc;
+ enum TALER_ErrorCode ec;
+ struct GNUNET_HashCode h_denom_pub;
/* parse JSON reply */
if (GNUNET_OK !=
@@ -211,6 +213,9 @@ verify_melt_signature_conflict (struct TALER_EXCHANGE_MeltHandle *mh,
}
/* verify coin history */
+ memset (&h_denom_pub,
+ 0,
+ sizeof (h_denom_pub));
history = json_object_get (json,
"history");
if (GNUNET_OK !=
@@ -218,6 +223,7 @@ verify_melt_signature_conflict (struct TALER_EXCHANGE_MeltHandle *mh,
original_value.currency,
&coin_pub,
history,
+ &h_denom_pub,
&total))
{
GNUNET_break_op (0);
@@ -226,27 +232,43 @@ verify_melt_signature_conflict (struct TALER_EXCHANGE_MeltHandle *mh,
}
json_decref (history);
- /* check if melt operation was really too expensive given history */
- if (0 >
- TALER_amount_add (&total,
- &total,
- &melt_value_with_fee))
+ ec = TALER_JSON_get_error_code (json);
+ switch (ec)
{
- /* clearly not OK if our transaction would have caused
- the overflow... */
- return GNUNET_OK;
- }
+ case TALER_EC_MELT_INSUFFICIENT_FUNDS:
+ /* check if melt operation was really too expensive given history */
+ if (0 >
+ TALER_amount_add (&total,
+ &total,
+ &melt_value_with_fee))
+ {
+ /* clearly not OK if our transaction would have caused
+ the overflow... */
+ return GNUNET_OK;
+ }
- if (0 >= TALER_amount_cmp (&total,
- &original_value))
- {
- /* transaction should have still fit */
- GNUNET_break (0);
+ if (0 >= TALER_amount_cmp (&total,
+ &original_value))
+ {
+ /* transaction should have still fit */
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+
+ /* everything OK, valid proof of double-spending was provided */
+ return GNUNET_OK;
+ case TALER_EC_COIN_CONFLICTING_DENOMINATION_KEY:
+ if (0 != GNUNET_memcmp (&mh->dki.h_key,
+ &h_denom_pub))
+ return GNUNET_OK; /* indeed, proof with different denomination key provided */
+ /* invalid proof provided */
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ default:
+ /* unexpected error code */
+ GNUNET_break_op (0);
return GNUNET_SYSERR;
}
-
- /* everything OK, valid proof of double-spending was provided */
- return GNUNET_OK;
}
diff --git a/src/lib/exchange_api_recoup.c b/src/lib/exchange_api_recoup.c
index 723b41789..d8c59827c 100644
--- a/src/lib/exchange_api_recoup.c
+++ b/src/lib/exchange_api_recoup.c
@@ -187,7 +187,9 @@ handle_recoup_finished (void *cls,
/* Insufficient funds, proof attached */
json_t *history;
struct TALER_Amount total;
+ struct GNUNET_HashCode h_denom_pub;
const struct TALER_EXCHANGE_DenomPublicKey *dki;
+ enum TALER_ErrorCode ec;
dki = &ph->pk;
history = json_object_get (j,
@@ -197,6 +199,7 @@ handle_recoup_finished (void *cls,
dki->fee_deposit.currency,
&ph->coin_pub,
history,
+ &h_denom_pub,
&total))
{
GNUNET_break_op (0);
@@ -208,6 +211,43 @@ handle_recoup_finished (void *cls,
hr.ec = TALER_JSON_get_error_code (j);
hr.hint = TALER_JSON_get_error_hint (j);
}
+ ec = TALER_JSON_get_error_code (j);
+ switch (ec)
+ {
+ case TALER_EC_RECOUP_COIN_BALANCE_ZERO:
+ if (0 > TALER_amount_cmp (&total,
+ &dki->value))
+ {
+ /* recoup MAY have still been possible */
+ /* FIXME: This code may falsely complain, as we do not
+ know that the smallest denomination offered by the
+ exchange is here. We should look at the key
+ structure of ph->exchange, and find the smallest
+ _currently withdrawable_ denomination and check
+ if the value remaining would suffice... */GNUNET_break_op (0);
+ hr.http_status = 0;
+ hr.ec = TALER_EC_RECOUP_REPLY_MALFORMED;
+ break;
+ }
+ break;
+ case TALER_EC_COIN_CONFLICTING_DENOMINATION_KEY:
+ if (0 == GNUNET_memcmp (&ph->pk.h_key,
+ &h_denom_pub))
+ {
+ /* invalid proof provided */
+ GNUNET_break_op (0);
+ hr.http_status = 0;
+ hr.ec = TALER_EC_RECOUP_REPLY_MALFORMED;
+ break;
+ }
+ /* valid error from exchange */
+ break;
+ default:
+ GNUNET_break_op (0);
+ hr.http_status = 0;
+ hr.ec = TALER_EC_RECOUP_REPLY_MALFORMED;
+ break;
+ }
ph->cb (ph->cb_cls,
&hr,
NULL,