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 json_t *root,
const char *const args[]) 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_WithdrawNonce nonce;
struct TALER_DenominationHash denom_pub_hash; struct TALER_DenominationHash denom_pub_hash;
struct TALER_DenominationCsPublicR r_pub; struct TALER_DenominationCsPublicR r_pub;

View File

@ -2442,7 +2442,19 @@ TEH_keys_denomination_sign (const struct TALER_DenominationHash *h_denom_pub,
msg, msg,
msg_size, msg_size,
ec); 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: default:
*ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; *ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
return none; return none;

View File

@ -98,15 +98,13 @@ struct WithdrawContext
/** /**
* Blinded planchet. * Blinded planchet.
*/ */
void *blinded_msg; //FIXME:
/** /**
* Number of bytes in @e blinded_msg. * Number of bytes in @e blinded_msg.
*/ */
size_t blinded_msg_len; size_t blinded_msg_len;
struct TALER_BlindedPlanchet blinded_planchet;
/**
* Set to the resulting signed coin data to be returned to the client.
*/ */
struct TALER_EXCHANGEDB_CollectableBlindcoin collectable; struct TALER_EXCHANGEDB_CollectableBlindcoin collectable;
@ -324,15 +322,48 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
{ {
struct WithdrawContext wc; struct WithdrawContext wc;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
//FIXME:
GNUNET_JSON_spec_varsize ("coin_ev", GNUNET_JSON_spec_varsize ("coin_ev",
&wc.blinded_msg, &wc.blinded_msg,
&wc.blinded_msg_len), &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", GNUNET_JSON_spec_fixed_auto ("reserve_sig",
&wc.collectable.reserve_sig), &wc.collectable.reserve_sig),
GNUNET_JSON_spec_fixed_auto ("denom_pub_hash", GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
&wc.collectable.denom_pub_hash), &wc.collectable.denom_pub_hash),
GNUNET_JSON_spec_end () 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; enum TALER_ErrorCode ec;
struct TEH_DenominationKey *dk; struct TEH_DenominationKey *dk;
@ -445,7 +476,7 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
return mret; return mret;
} }
} }
//FIXME:
if (0 > if (0 >
TALER_amount_add (&wc.collectable.amount_with_fee, TALER_amount_add (&wc.collectable.amount_with_fee,
&dk->meta.value, &dk->meta.value,
@ -456,6 +487,61 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
MHD_HTTP_INTERNAL_SERVER_ERROR, MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_EXCHANGE_WITHDRAW_AMOUNT_FEE_OVERFLOW, TALER_EC_EXCHANGE_WITHDRAW_AMOUNT_FEE_OVERFLOW,
NULL); 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, TALER_amount_hton (&wc.wsrd.amount_with_fee,
&wc.collectable.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); = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW);
wc.wsrd.h_denomination_pub wc.wsrd.h_denomination_pub
= wc.collectable.denom_pub_hash; = wc.collectable.denom_pub_hash;
TALER_coin_ev_hash (wc.blinded_msg, switch (wc.blinded_planchet.cipher)
wc.blinded_msg_len, {
&wc.wsrd.h_coin_envelope); 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 != if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify ( GNUNET_CRYPTO_eddsa_verify (
TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW, TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW,
@ -481,23 +588,50 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
TALER_LOG_WARNING ( TALER_LOG_WARNING (
"Client supplied invalid signature for withdraw request\n"); "Client supplied invalid signature for withdraw request\n");
GNUNET_JSON_parse_free (spec); 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, return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_FORBIDDEN, MHD_HTTP_FORBIDDEN,
TALER_EC_EXCHANGE_WITHDRAW_RESERVE_SIGNATURE_INVALID, TALER_EC_EXCHANGE_WITHDRAW_RESERVE_SIGNATURE_INVALID,
NULL); NULL);
} }
// TODO: if CS: check nonce for reuse
/* Sign before transaction! */ /* Sign before transaction! */
ec = TALER_EC_NONE; ec = TALER_EC_NONE;
wc.collectable.sig switch (wc.blinded_planchet.cipher)
= TEH_keys_denomination_sign (&wc.collectable.denom_pub_hash, {
wc.blinded_msg, case TALER_DENOMINATION_RSA:
wc.blinded_msg_len, wc.collectable.sig = TEH_keys_denomination_sign (
&ec); &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) if (TALER_EC_NONE != ec)
{ {
GNUNET_break (0); GNUNET_break (0);
GNUNET_JSON_parse_free (spec); 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, return TALER_MHD_reply_with_ec (rc->connection,
ec, ec,
NULL); NULL);
@ -519,12 +653,16 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
(or we might have done it optimistically above). */ (or we might have done it optimistically above). */
TALER_blinded_denom_sig_free (&wc.collectable.sig); TALER_blinded_denom_sig_free (&wc.collectable.sig);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
if (NULL != coin_ev_spec)
GNUNET_JSON_parse_free (coin_ev_spec);
return mhd_ret; return mhd_ret;
} }
} }
/* Clean up and send back final response */ /* Clean up and send back final response */
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
if (NULL != coin_ev_spec)
GNUNET_JSON_parse_free (coin_ev_spec);
{ {
MHD_RESULT ret; MHD_RESULT ret;

View File

@ -1332,6 +1332,30 @@ TALER_TESTING_cmd_withdraw_amount_reuse_key (
unsigned int expected_response_code); 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 * Create withdraw command, letting the caller specify the
* amount by a denomination key. * amount by a denomination key.

View File

@ -388,6 +388,7 @@ parse_denom_sig (void *cls,
} }
return GNUNET_OK; return GNUNET_OK;
} }
// TODO: case TALER_DENOMINATION_CS:
default: default:
GNUNET_break_op (0); GNUNET_break_op (0);
return GNUNET_SYSERR; return GNUNET_SYSERR;
@ -483,6 +484,29 @@ parse_blinded_denom_sig (void *cls,
} }
return GNUNET_OK; 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: default:
GNUNET_break_op (0); GNUNET_break_op (0);
return GNUNET_SYSERR; return GNUNET_SYSERR;

View File

@ -125,14 +125,21 @@ TALER_JSON_pack_blinded_denom_sig (
switch (sig->cipher) switch (sig->cipher)
{ {
case TALER_DENOMINATION_RSA: case TALER_DENOMINATION_RSA:
ps.object ps.object = GNUNET_JSON_PACK (
= GNUNET_JSON_PACK ( GNUNET_JSON_pack_uint64 ("cipher",
GNUNET_JSON_pack_uint64 ("cipher", TALER_DENOMINATION_RSA),
TALER_DENOMINATION_RSA), GNUNET_JSON_pack_rsa_signature ("blinded_rsa_signature",
GNUNET_JSON_pack_rsa_signature ("blinded_rsa_signature", sig->details.blinded_rsa_signature));
sig->details.blinded_rsa_signature)); break;
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; break;
// TODO: case TALER_DENOMINATION_CS:
default: default:
GNUNET_assert (0); GNUNET_assert (0);
} }

View File

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

View File

@ -437,11 +437,26 @@ TALER_EXCHANGE_withdraw2 (
TALER_amount_hton (&req.amount_with_fee, TALER_amount_hton (&req.amount_with_fee,
&wh->requested_amount); &wh->requested_amount);
TALER_coin_ev_hash ( switch (dk->key.cipher)
pd->blinded_planchet.details.rsa_blinded_planchet.blinded_msg, {
pd->blinded_planchet.details.rsa_blinded_planchet. case TALER_DENOMINATION_RSA:
blinded_msg_size, TALER_coin_ev_hash (
&req.h_coin_envelope); 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, GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv,
&req, &req,
&reserve_sig.eddsa_signature); &reserve_sig.eddsa_signature);
@ -449,17 +464,44 @@ TALER_EXCHANGE_withdraw2 (
{ {
json_t *withdraw_obj; json_t *withdraw_obj;
switch (dk->key.cipher)
withdraw_obj = GNUNET_JSON_PACK ( {
GNUNET_JSON_pack_data_auto ("denom_pub_hash", case TALER_DENOMINATION_RSA:
&pd->denom_pub_hash), withdraw_obj = GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_varsize ("coin_ev", GNUNET_JSON_pack_data_auto ("denom_pub_hash",
pd->blinded_planchet.details. &pd->denom_pub_hash),
rsa_blinded_planchet.blinded_msg, GNUNET_JSON_pack_data_varsize ("coin_ev",
pd->blinded_planchet.details. pd->blinded_planchet.details.
rsa_blinded_planchet.blinded_msg_size), rsa_blinded_planchet.blinded_msg,
GNUNET_JSON_pack_data_auto ("reserve_sig", pd->blinded_planchet.details.
&reserve_sig)); 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, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Attempting to withdraw from reserve %s\n", "Attempting to withdraw from reserve %s\n",
TALER_B2S (&wh->reserve_pub)); TALER_B2S (&wh->reserve_pub));

View File

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

View File

@ -670,7 +670,16 @@ extract_blinded_denom_sig (void *cls,
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
return GNUNET_OK; 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: default:
GNUNET_break (0); GNUNET_break (0);
} }

View File

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

View File

@ -266,13 +266,6 @@ reserve_withdraw_cb (void *cls,
switch (wr->hr.http_status) switch (wr->hr.http_status)
{ {
case MHD_HTTP_OK: 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, TALER_denom_sig_deep_copy (&ws->sig,
&wr->details.success.sig); &wr->details.success.sig);
if (0 != ws->total_backoff.rel_value_us) if (0 != ws->total_backoff.rel_value_us)
@ -661,6 +654,8 @@ TALER_TESTING_cmd_withdraw_amount_reuse_key (
const char *coin_ref, const char *coin_ref,
unsigned int expected_response_code) 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; struct TALER_TESTING_Command cmd;
cmd = TALER_TESTING_cmd_withdraw_amount (label, 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 * Create withdraw command, letting the caller specify the
* amount by a denomination key. * amount by a denomination key.