implement withdraw (nonce reuse check missing)

This commit is contained in:
Lucien Heuzeveldt 2022-01-08 20:41:01 +01:00 committed by Gian Demarmels
parent 4c7aa09784
commit 9074e66ebc
No known key found for this signature in database
GPG Key ID: 030CEDDCCC92D778
12 changed files with 425 additions and 109 deletions

View File

@ -37,10 +37,6 @@ TEH_handler_csr (struct TEH_RequestContext *rc,
const json_t *root,
const char *const args[])
{
// TODO: should we have something similar to struct WithdrawContext?
// as far as I can tell this isn't necessary because we don't have
// other functions that the context should be passed to
// struct CsRContext csrc;
struct TALER_WithdrawNonce nonce;
struct TALER_DenominationHash denom_pub_hash;
struct TALER_DenominationCsPublicR r_pub;

View File

@ -2442,7 +2442,19 @@ TEH_keys_denomination_sign (const struct TALER_DenominationHash *h_denom_pub,
msg,
msg_size,
ec);
// TODO: case TALER_DENOMINATION_CS:
case TALER_DENOMINATION_CS:
if (sizeof (struct TALER_BlindedCsPlanchet) != msg_size)
{
*ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
return none;
}
struct TALER_BlindedCsPlanchet *blinded_cs_planchet = ((struct
TALER_BlindedCsPlanchet
*) msg);
return TALER_CRYPTO_helper_cs_sign (ksh->helpers->csdh,
&hd->h_details.h_cs,
blinded_cs_planchet,
ec);
default:
*ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
return none;

View File

@ -98,15 +98,13 @@ struct WithdrawContext
/**
* Blinded planchet.
*/
void *blinded_msg;
//FIXME:
/**
* Number of bytes in @e blinded_msg.
*/
size_t blinded_msg_len;
/**
* Set to the resulting signed coin data to be returned to the client.
struct TALER_BlindedPlanchet blinded_planchet;
*/
struct TALER_EXCHANGEDB_CollectableBlindcoin collectable;
@ -324,15 +322,48 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
{
struct WithdrawContext wc;
struct GNUNET_JSON_Specification spec[] = {
//FIXME:
GNUNET_JSON_spec_varsize ("coin_ev",
&wc.blinded_msg,
&wc.blinded_msg_len),
// field "coin_ev" will be parsed later due to different parsing depending
// on denomination cipher, see coin_ev_..._spec
GNUNET_JSON_spec_fixed_auto ("reserve_sig",
&wc.collectable.reserve_sig),
GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
&wc.collectable.denom_pub_hash),
GNUNET_JSON_spec_end ()
};
// holds pointer to coin_ev_rsa/cs_spec for freeing
struct GNUNET_JSON_Specification *coin_ev_spec = NULL;
struct GNUNET_JSON_Specification coin_ev_rsa_spec[] = {
GNUNET_JSON_spec_varsize (
"coin_ev",
(void **) &wc.blinded_planchet.details.rsa_blinded_planchet.blinded_msg,
&wc.blinded_planchet.details.rsa_blinded_planchet.blinded_msg_size),
GNUNET_JSON_spec_end ()
};
json_t *coin_ev_cs_json;
struct GNUNET_JSON_Specification coin_ev_cs_json_spec[] = {
GNUNET_JSON_spec_json ("coin_ev",
&coin_ev_cs_json),
GNUNET_JSON_spec_end ()
};
struct GNUNET_JSON_Specification coin_ev_cs_spec[] = {
GNUNET_JSON_spec_fixed (
"nonce",
&wc.blinded_planchet.details.cs_blinded_planchet.nonce,
sizeof (wc.blinded_planchet.details.cs_blinded_planchet.nonce)),
GNUNET_JSON_spec_fixed (
"c0",
&wc.blinded_planchet.details.cs_blinded_planchet.c[0],
sizeof (wc.blinded_planchet.details.cs_blinded_planchet.c[0])),
GNUNET_JSON_spec_fixed (
"c1",
&wc.blinded_planchet.details.cs_blinded_planchet.c[1],
sizeof (wc.blinded_planchet.details.cs_blinded_planchet.c[1])),
GNUNET_JSON_spec_end ()
};
enum TALER_ErrorCode ec;
struct TEH_DenominationKey *dk;
@ -445,7 +476,7 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
return mret;
}
}
//FIXME:
if (0 >
TALER_amount_add (&wc.collectable.amount_with_fee,
&dk->meta.value,
@ -456,6 +487,61 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_EXCHANGE_WITHDRAW_AMOUNT_FEE_OVERFLOW,
NULL);
// parse coin_ev field, must be done after dk lookup to know denom cipher
{
enum GNUNET_GenericReturnValue res;
wc.blinded_planchet.cipher = dk->denom_pub.cipher;
switch (wc.blinded_planchet.cipher)
{
case TALER_DENOMINATION_RSA:
res = TALER_MHD_parse_json_data (rc->connection,
root,
coin_ev_rsa_spec);
if (GNUNET_OK != res)
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
coin_ev_spec = coin_ev_rsa_spec;
break;
case TALER_DENOMINATION_CS:
// coin_ev for CS is nested
res = TALER_MHD_parse_json_data (rc->connection,
root,
coin_ev_cs_json_spec);
if (GNUNET_OK != res)
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
res = TALER_MHD_parse_json_data (rc->connection,
coin_ev_cs_json,
coin_ev_cs_spec);
GNUNET_JSON_parse_free (coin_ev_cs_json_spec);
if (GNUNET_OK != res)
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
coin_ev_spec = coin_ev_cs_spec;
break;
default:
GNUNET_break (0);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_FORBIDDEN,
TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
NULL);
}
}
{
if (0 >
TALER_amount_add (&wc.collectable.amount_with_fee,
&dk->meta.value,
&dk->meta.fee_withdraw))
{
GNUNET_JSON_parse_free (spec);
if (NULL != coin_ev_spec)
GNUNET_JSON_parse_free (coin_ev_spec);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_EXCHANGE_WITHDRAW_AMOUNT_FEE_OVERFLOW,
NULL);
}
TALER_amount_hton (&wc.wsrd.amount_with_fee,
&wc.collectable.amount_with_fee);
}
TALER_amount_hton (&wc.wsrd.amount_with_fee,
&wc.collectable.amount_with_fee);
@ -468,9 +554,30 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
= htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW);
wc.wsrd.h_denomination_pub
= wc.collectable.denom_pub_hash;
TALER_coin_ev_hash (wc.blinded_msg,
wc.blinded_msg_len,
switch (wc.blinded_planchet.cipher)
{
case TALER_DENOMINATION_RSA:
TALER_coin_ev_hash (
wc.blinded_planchet.details.rsa_blinded_planchet.blinded_msg,
wc.blinded_planchet.details.rsa_blinded_planchet.blinded_msg_size,
&wc.wsrd.h_coin_envelope);
break;
case TALER_DENOMINATION_CS:
TALER_coin_ev_hash (
&wc.blinded_planchet.details.cs_blinded_planchet,
sizeof (wc.blinded_planchet.details.cs_blinded_planchet),
&wc.wsrd.h_coin_envelope);
break;
default:
GNUNET_break (0);
GNUNET_JSON_parse_free (spec);
if (NULL != coin_ev_spec)
GNUNET_JSON_parse_free (coin_ev_spec);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_FORBIDDEN,
TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
NULL);
}
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (
TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW,
@ -481,23 +588,50 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
TALER_LOG_WARNING (
"Client supplied invalid signature for withdraw request\n");
GNUNET_JSON_parse_free (spec);
if (NULL != coin_ev_spec)
GNUNET_JSON_parse_free (coin_ev_spec);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_FORBIDDEN,
TALER_EC_EXCHANGE_WITHDRAW_RESERVE_SIGNATURE_INVALID,
NULL);
}
// TODO: if CS: check nonce for reuse
/* Sign before transaction! */
ec = TALER_EC_NONE;
wc.collectable.sig
= TEH_keys_denomination_sign (&wc.collectable.denom_pub_hash,
wc.blinded_msg,
wc.blinded_msg_len,
switch (wc.blinded_planchet.cipher)
{
case TALER_DENOMINATION_RSA:
wc.collectable.sig = TEH_keys_denomination_sign (
&wc.collectable.denom_pub_hash,
wc.blinded_planchet.details.rsa_blinded_planchet.blinded_msg,
wc.blinded_planchet.details.rsa_blinded_planchet.blinded_msg_size,
&ec);
break;
case TALER_DENOMINATION_CS:
wc.collectable.sig = TEH_keys_denomination_sign (
&wc.collectable.denom_pub_hash,
&wc.blinded_planchet.details.cs_blinded_planchet,
sizeof (wc.blinded_planchet.details.cs_blinded_planchet),
&ec);
break;
default:
GNUNET_break (0);
GNUNET_JSON_parse_free (spec);
if (NULL != coin_ev_spec)
GNUNET_JSON_parse_free (coin_ev_spec);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_FORBIDDEN,
TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
NULL);
}
if (TALER_EC_NONE != ec)
{
GNUNET_break (0);
GNUNET_JSON_parse_free (spec);
if (NULL != coin_ev_spec)
GNUNET_JSON_parse_free (coin_ev_spec);
return TALER_MHD_reply_with_ec (rc->connection,
ec,
NULL);
@ -519,12 +653,16 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
(or we might have done it optimistically above). */
TALER_blinded_denom_sig_free (&wc.collectable.sig);
GNUNET_JSON_parse_free (spec);
if (NULL != coin_ev_spec)
GNUNET_JSON_parse_free (coin_ev_spec);
return mhd_ret;
}
}
/* Clean up and send back final response */
GNUNET_JSON_parse_free (spec);
if (NULL != coin_ev_spec)
GNUNET_JSON_parse_free (coin_ev_spec);
{
MHD_RESULT ret;

View File

@ -1332,6 +1332,30 @@ TALER_TESTING_cmd_withdraw_amount_reuse_key (
unsigned int expected_response_code);
/**
* Create a CS withdraw command, letting the caller specify
* the desired amount as string and also re-using an existing
* coin private key in the process (violating the specification,
* which will result in an error when spending the coin!).
*
* @param label command label.
* @param reserve_reference command providing us with a reserve to withdraw from
* @param amount how much we withdraw.
* @param coin_ref reference to (withdraw/reveal) command of a coin
* from which we should re-use the private key
* @param expected_response_code which HTTP response code
* we expect from the exchange.
* @return the withdraw command to be executed by the interpreter.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_withdraw_cs_amount_reuse_key (
const char *label,
const char *reserve_reference,
const char *amount,
const char *coin_ref,
unsigned int expected_response_code);
/**
* Create withdraw command, letting the caller specify the
* amount by a denomination key.

View File

@ -388,6 +388,7 @@ parse_denom_sig (void *cls,
}
return GNUNET_OK;
}
// TODO: case TALER_DENOMINATION_CS:
default:
GNUNET_break_op (0);
return GNUNET_SYSERR;
@ -483,6 +484,29 @@ parse_blinded_denom_sig (void *cls,
}
return GNUNET_OK;
}
case TALER_DENOMINATION_CS:
{
struct GNUNET_JSON_Specification ispec[] = {
GNUNET_JSON_spec_uint32 ("b",
&denom_sig->details.blinded_cs_answer.b),
GNUNET_JSON_spec_fixed_auto ("s",
&denom_sig->details.blinded_cs_answer.
s_scalar),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (root,
ispec,
&emsg,
&eline))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
break;
default:
GNUNET_break_op (0);
return GNUNET_SYSERR;

View File

@ -125,14 +125,21 @@ TALER_JSON_pack_blinded_denom_sig (
switch (sig->cipher)
{
case TALER_DENOMINATION_RSA:
ps.object
= GNUNET_JSON_PACK (
ps.object = GNUNET_JSON_PACK (
GNUNET_JSON_pack_uint64 ("cipher",
TALER_DENOMINATION_RSA),
GNUNET_JSON_pack_rsa_signature ("blinded_rsa_signature",
sig->details.blinded_rsa_signature));
break;
// TODO: case TALER_DENOMINATION_CS:
case TALER_DENOMINATION_CS:
ps.object = GNUNET_JSON_PACK (
GNUNET_JSON_pack_uint64 ("cipher",
TALER_DENOMINATION_CS),
GNUNET_JSON_pack_uint64 ("b",
sig->details.blinded_cs_answer.b),
GNUNET_JSON_pack_data_auto ("s",
&sig->details.blinded_cs_answer.s_scalar));
break;
default:
GNUNET_assert (0);
}

View File

@ -58,11 +58,21 @@ struct TALER_EXCHANGE_WithdrawHandle
*/
void *cb_cls;
/**
* Reserve private key.
*/
const struct TALER_ReservePrivateKeyP *reserve_priv;
/**
* Secrets of the planchet.
*/
struct TALER_PlanchetSecretsP ps;
/**
* Details of the planchet.
*/
struct TALER_PlanchetDetail pd;
/**
* Denomination key we are withdrawing.
*/
@ -162,24 +172,44 @@ withdraw_cs_stage_two_callback (void *cls,
const struct TALER_EXCHANGE_CsRResponse *csrr)
{
struct TALER_EXCHANGE_WithdrawHandle *wh = cls;
// TODO: this should only be set for non-OK cases
wh->csrh = NULL;
GNUNET_assert (TALER_DENOMINATION_CS == wh->pk.key.cipher);
switch (csrr->hr.http_status)
{
case MHD_HTTP_OK:
wh->ps.cs_r_pub = csrr->details.success.r_pubs;
TALER_blinding_secret_create (&wh->ps.blinding_key,
wh->pk.key.cipher,
&wh->ps.coin_priv,
&wh->ps.cs_r_pub);
if (GNUNET_OK !=
TALER_planchet_prepare (&wh->pk.key,
&wh->ps,
&wh->c_hash,
&wh->pd))
{
GNUNET_break (0);
GNUNET_free (wh);
}
wh->wh2 = TALER_EXCHANGE_withdraw2 (wh->exchange,
&wh->pd,
wh->reserve_priv,
&handle_reserve_withdraw_finished,
wh);
break;
default:
// the CSR request went wrong -> serve response to the callback
struct TALER_EXCHANGE_WithdrawResponse wr = {
.hr = csrr->hr
};
// switch (csrr->hr.http_status)
// {
// case MHD_HTTP_OK:
// // TODO: implement rest of withdraw
// break;
// default:
// break;
// }
// TODO: this should only be called for non-OK cases
wh->cb (wh->cb_cls,
&wr);
TALER_EXCHANGE_withdraw_cancel (wh);
break;
}
}
@ -210,16 +240,19 @@ TALER_EXCHANGE_withdraw (
TALER_EXCHANGE_WithdrawCallback res_cb,
void *res_cb_cls)
{
struct TALER_PlanchetDetail pd;
struct TALER_EXCHANGE_WithdrawHandle *wh;
wh = GNUNET_new (struct TALER_EXCHANGE_WithdrawHandle);
wh->exchange = exchange;
wh->cb = res_cb;
wh->cb_cls = res_cb_cls;
wh->pk = *pk;
wh->reserve_priv = reserve_priv;
wh->ps = *ps;
wh->pk = *pk;
wh->csrh = NULL;
TALER_denom_pub_deep_copy (&wh->pk.key,
&pk->key);
switch (pk->key.cipher)
{
case TALER_DENOMINATION_RSA:
@ -227,27 +260,28 @@ TALER_EXCHANGE_withdraw (
TALER_planchet_prepare (&pk->key,
ps,
&wh->c_hash,
&pd))
&wh->pd))
{
GNUNET_break (0);
GNUNET_free (wh);
return NULL;
}
TALER_denom_pub_deep_copy (&wh->pk.key,
&pk->key);
wh->wh2 = TALER_EXCHANGE_withdraw2 (exchange,
&pd,
reserve_priv,
&wh->pd,
wh->reserve_priv,
&handle_reserve_withdraw_finished,
wh);
GNUNET_free (pd.blinded_planchet.details.rsa_blinded_planchet.blinded_msg);
GNUNET_free (
wh->pd.blinded_planchet.details.rsa_blinded_planchet.blinded_msg);
return wh;
case TALER_DENOMINATION_CS:
struct TALER_WithdrawNonce nonce;
TALER_cs_withdraw_nonce_derive (&ps->coin_priv, &nonce);
TALER_cs_withdraw_nonce_derive (&ps->coin_priv,
&wh->pd.blinded_planchet.details.
cs_blinded_planchet.nonce);
wh->csrh = TALER_EXCHANGE_csr (exchange,
pk,
&nonce,
&wh->pd.blinded_planchet.details.
cs_blinded_planchet.nonce,
&withdraw_cs_stage_two_callback,
wh);
return wh;

View File

@ -437,11 +437,26 @@ TALER_EXCHANGE_withdraw2 (
TALER_amount_hton (&req.amount_with_fee,
&wh->requested_amount);
switch (dk->key.cipher)
{
case TALER_DENOMINATION_RSA:
TALER_coin_ev_hash (
pd->blinded_planchet.details.rsa_blinded_planchet.blinded_msg,
pd->blinded_planchet.details.rsa_blinded_planchet.
blinded_msg_size,
&req.h_coin_envelope);
break;
case TALER_DENOMINATION_CS:
TALER_coin_ev_hash (
&pd->blinded_planchet.details.cs_blinded_planchet,
sizeof (pd->blinded_planchet.details.cs_blinded_planchet),
&req.h_coin_envelope);
break;
default:
GNUNET_break (0);
GNUNET_free (wh);
return NULL;
}
GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv,
&req,
&reserve_sig.eddsa_signature);
@ -449,7 +464,9 @@ TALER_EXCHANGE_withdraw2 (
{
json_t *withdraw_obj;
switch (dk->key.cipher)
{
case TALER_DENOMINATION_RSA:
withdraw_obj = GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto ("denom_pub_hash",
&pd->denom_pub_hash),
@ -460,6 +477,31 @@ TALER_EXCHANGE_withdraw2 (
rsa_blinded_planchet.blinded_msg_size),
GNUNET_JSON_pack_data_auto ("reserve_sig",
&reserve_sig));
break;
case TALER_DENOMINATION_CS:
json_t *coin_ev_object = GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto ("nonce",
&pd->blinded_planchet.details.
cs_blinded_planchet.nonce),
GNUNET_JSON_pack_data_auto ("c0",
&pd->blinded_planchet.details.
cs_blinded_planchet.c[0]),
GNUNET_JSON_pack_data_auto ("c1",
&pd->blinded_planchet.details.
cs_blinded_planchet.c[1]));
withdraw_obj = GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto ("denom_pub_hash",
&pd->denom_pub_hash),
GNUNET_JSON_pack_object_steal ("coin_ev",
coin_ev_object),
GNUNET_JSON_pack_data_auto ("reserve_sig",
&reserve_sig));
break;
default:
GNUNET_break (0);
GNUNET_free (wh);
return NULL;
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Attempting to withdraw from reserve %s\n",
TALER_B2S (&wh->reserve_pub));

View File

@ -290,7 +290,9 @@ qconv_denom_sig (void *cls,
denom_sig->details.rsa_signature,
&tbuf);
break;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
tlen = sizeof (denom_sig->details.cs_signature);
break;
default:
GNUNET_assert (0);
}
@ -307,7 +309,11 @@ qconv_denom_sig (void *cls,
tlen);
GNUNET_free (tbuf);
break;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
memcpy (&buf[sizeof (be)],
&denom_sig->details.cs_signature,
tlen);
break;
default:
GNUNET_assert (0);
}
@ -380,7 +386,9 @@ qconv_blinded_denom_sig (void *cls,
denom_sig->details.blinded_rsa_signature,
&tbuf);
break;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
tlen = sizeof (denom_sig->details.blinded_cs_answer);
break;
default:
GNUNET_assert (0);
}
@ -397,7 +405,11 @@ qconv_blinded_denom_sig (void *cls,
tlen);
GNUNET_free (tbuf);
break;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
memcpy (&buf[sizeof (be)],
&denom_sig->details.blinded_cs_answer,
tlen);
break;
default:
GNUNET_assert (0);
}

View File

@ -670,7 +670,16 @@ extract_blinded_denom_sig (void *cls,
return GNUNET_SYSERR;
}
return GNUNET_OK;
// FIXME: add CS case!
case TALER_DENOMINATION_CS:
if (sizeof (sig->details.blinded_cs_answer) != len)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
memcpy (&sig->details.blinded_cs_answer,
res,
len);
return GNUNET_OK;
default:
GNUNET_break (0);
}

View File

@ -413,49 +413,49 @@ run (void *cls,
/**
* Move money to the exchange's bank account.
*/
CMD_TRANSFER_TO_EXCHANGE ("create-reserve-1",
CMD_TRANSFER_TO_EXCHANGE ("create-reserve-cs-1",
"EUR:6.02"),
TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-1",
TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-cs-1",
"EUR:6.02",
bc.user42_payto,
bc.exchange_payto,
"create-reserve-1"),
"create-reserve-cs-1"),
/**
* Make a reserve exist, according to the previous
* transfer.
*/
CMD_EXEC_WIREWATCH ("wirewatch-1"),
CMD_EXEC_WIREWATCH ("wirewatch-cs-1"),
/**
* Withdraw EUR:5.
*/
TALER_TESTING_cmd_withdraw_cs_amount ("withdraw-cs-coin-1",
"create-reserve-1",
"create-reserve-cs-1",
"EUR:5",
MHD_HTTP_OK),
// TODO: rest of the tests
// /**
// * Withdraw EUR:1 using the SAME private coin key as for the previous coin
// * (in violation of the specification, to be detected on spending!).
// */
// TALER_TESTING_cmd_withdraw_amount_reuse_key ("withdraw-coin-1x",
// "create-reserve-1",
// "EUR:1",
// "withdraw-coin-1",
// MHD_HTTP_OK),
// /**
// * Check the reserve is depleted.
// */
// TALER_TESTING_cmd_status ("status-1",
// "create-reserve-1",
// "EUR:0",
// MHD_HTTP_OK),
// /*
// * Try to overdraw.
// */
// TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-2",
// "create-reserve-1",
// "EUR:5",
// MHD_HTTP_CONFLICT),
/**
* Withdraw EUR:1 using the SAME private coin key as for the previous coin
* (in violation of the specification, to be detected on spending!).
*/
TALER_TESTING_cmd_withdraw_cs_amount_reuse_key ("withdraw-cs-coin-1x",
"create-reserve-cs-1",
"EUR:1",
"withdraw-cs-coin-1",
MHD_HTTP_OK),
/**
* Check the reserve is depleted.
*/
TALER_TESTING_cmd_status ("status-cs-1",
"create-reserve-cs-1",
"EUR:0",
MHD_HTTP_OK),
/*
* Try to overdraw.
*/
TALER_TESTING_cmd_withdraw_cs_amount ("withdraw-cs-coin-2",
"create-reserve-cs-1",
"EUR:5",
MHD_HTTP_CONFLICT),
// TODO: add test for nonce reuse
TALER_TESTING_cmd_end ()
};

View File

@ -266,13 +266,6 @@ reserve_withdraw_cb (void *cls,
switch (wr->hr.http_status)
{
case MHD_HTTP_OK:
// TODO: remove
// temporary make test successful when CS
if (TALER_DENOMINATION_CS == ws->cipher)
{
break;
}
TALER_denom_sig_deep_copy (&ws->sig,
&wr->details.success.sig);
if (0 != ws->total_backoff.rel_value_us)
@ -661,6 +654,8 @@ TALER_TESTING_cmd_withdraw_amount_reuse_key (
const char *coin_ref,
unsigned int expected_response_code)
{
// TODO: ATM this is hardcoded to RSA denominations
// (use TALER_TESTING_cmd_withdraw_cs_amount for Clause Schnorr)
struct TALER_TESTING_Command cmd;
cmd = TALER_TESTING_cmd_withdraw_amount (label,
@ -676,6 +671,29 @@ TALER_TESTING_cmd_withdraw_amount_reuse_key (
}
struct TALER_TESTING_Command
TALER_TESTING_cmd_withdraw_cs_amount_reuse_key (
const char *label,
const char *reserve_reference,
const char *amount,
const char *coin_ref,
unsigned int expected_response_code)
{
struct TALER_TESTING_Command cmd;
cmd = TALER_TESTING_cmd_withdraw_cs_amount (label,
reserve_reference,
amount,
expected_response_code);
{
struct WithdrawState *ws = cmd.cls;
ws->reuse_coin_key_ref = coin_ref;
}
return cmd;
}
/**
* Create withdraw command, letting the caller specify the
* amount by a denomination key.