implement withdraw (nonce reuse check missing)
This commit is contained in:
parent
4c7aa09784
commit
9074e66ebc
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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.
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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));
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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 ()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user