summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2022-02-10 23:39:00 +0100
committerChristian Grothoff <christian@grothoff.org>2022-02-10 23:39:00 +0100
commit532d4ad0dca62055056e5b6093e82daa3541f690 (patch)
tree65e2d5b783d0a84b33779b8d0e89225d0e765353
parentd58d89dcab91823dff208d230e1b1b3a742810bd (diff)
downloadexchange-532d4ad0dca62055056e5b6093e82daa3541f690.tar.gz
exchange-532d4ad0dca62055056e5b6093e82daa3541f690.tar.bz2
exchange-532d4ad0dca62055056e5b6093e82daa3541f690.zip
-fixes to tests, and half-baked fixes for CS-/link (still fails)
-rw-r--r--src/exchange/taler-exchange-httpd_link.c6
-rw-r--r--src/exchange/taler-exchange-httpd_refreshes_reveal.c19
-rw-r--r--src/exchangedb/exchange-0001.sql3
-rw-r--r--src/exchangedb/irbt_callbacks.c2
-rw-r--r--src/exchangedb/lrbt_callbacks.c3
-rw-r--r--src/exchangedb/plugin_exchangedb_postgres.c24
-rw-r--r--src/exchangedb/test_exchangedb.c7
-rw-r--r--src/include/taler_exchangedb_plugin.h18
-rw-r--r--src/include/taler_pq_lib.h27
-rw-r--r--src/lib/exchange_api_link.c26
-rw-r--r--src/lib/exchange_api_refresh_common.c4
-rw-r--r--src/pq/pq_query_helper.c88
-rw-r--r--src/pq/pq_result_helper.c108
-rw-r--r--src/testing/test_exchange_api.c41
-rw-r--r--src/util/crypto.c1
15 files changed, 354 insertions, 23 deletions
diff --git a/src/exchange/taler-exchange-httpd_link.c b/src/exchange/taler-exchange-httpd_link.c
index d3c0d6a5a..de10f8b82 100644
--- a/src/exchange/taler-exchange-httpd_link.c
+++ b/src/exchange/taler-exchange-httpd_link.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2019 Taler Systems SA
+ Copyright (C) 2014-2019, 2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
@@ -86,6 +86,10 @@ handle_link_data (void *cls,
&pos->denom_pub),
TALER_JSON_pack_blinded_denom_sig ("ev_sig",
&pos->ev_sig),
+ GNUNET_JSON_pack_uint64 ("coin_idx",
+ pos->coin_refresh_offset),
+ TALER_JSON_pack_exchange_withdraw_values ("ewv",
+ &pos->alg_values),
GNUNET_JSON_pack_data_auto ("link_sig",
&pos->orig_coin_link_sig));
if ( (NULL == obj) ||
diff --git a/src/exchange/taler-exchange-httpd_refreshes_reveal.c b/src/exchange/taler-exchange-httpd_refreshes_reveal.c
index 568278144..e0d97bb3d 100644
--- a/src/exchange/taler-exchange-httpd_refreshes_reveal.c
+++ b/src/exchange/taler-exchange-httpd_refreshes_reveal.c
@@ -105,7 +105,10 @@ struct RevealContext
/**
* Array of information about fresh coins being revealed.
*/
- const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs;
+ /* FIXME: const would be nicer here, but we initalize
+ the 'alg_values' in the verification
+ routine; suboptimal to be fixed... */
+ struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrcs;
/**
* Envelopes to be signed.
@@ -141,7 +144,6 @@ check_commitment (struct RevealContext *rctx,
struct MHD_Connection *connection,
MHD_RESULT *mhd_ret)
{
- struct TALER_ExchangeWithdrawValues alg_values[rctx->num_fresh_coins];
struct TALER_CsNonce nonces[rctx->num_fresh_coins];
unsigned int aoff = 0;
@@ -184,8 +186,10 @@ check_commitment (struct RevealContext *rctx,
for (unsigned int j = 0; j<rctx->num_fresh_coins; j++)
{
const struct TALER_DenominationPublicKey *dk = &rctx->dks[j]->denom_pub;
+ struct TALER_ExchangeWithdrawValues *alg_values
+ = &rctx->rrcs[j].exchange_vals;
- alg_values[j].cipher = dk->cipher;
+ alg_values->cipher = dk->cipher;
switch (dk->cipher)
{
case TALER_DENOMINATION_INVALID:
@@ -200,7 +204,7 @@ check_commitment (struct RevealContext *rctx,
ec = TEH_keys_denomination_cs_r_pub (
&rctx->rrcs[j].h_denom_pub,
&nonces[aoff],
- &alg_values[j].details.cs_values.r_pub_pair);
+ &alg_values->details.cs_values.r_pub_pair);
if (TALER_EC_NONE != ec)
{
*mhd_ret = TALER_MHD_reply_with_error (connection,
@@ -251,12 +255,13 @@ check_commitment (struct RevealContext *rctx,
aoff = 0;
for (unsigned int j = 0; j<rctx->num_fresh_coins; j++)
{
- const struct TALER_DenominationPublicKey *dk =
- &rctx->dks[j]->denom_pub;
+ const struct TALER_DenominationPublicKey *dk
+ = &rctx->dks[j]->denom_pub;
struct TALER_RefreshCoinData *rcd = &rce->new_coins[j];
struct TALER_CoinSpendPrivateKeyP coin_priv;
union TALER_DenominationBlindingKeyP bks;
- const struct TALER_ExchangeWithdrawValues *alg_value = &alg_values[j];
+ const struct TALER_ExchangeWithdrawValues *alg_value
+ = &rctx->rrcs[j].exchange_vals;
struct TALER_PlanchetDetail pd;
struct TALER_CoinPubHash c_hash;
struct TALER_PlanchetSecretsP ps;
diff --git a/src/exchangedb/exchange-0001.sql b/src/exchangedb/exchange-0001.sql
index a8e79335b..66856f60c 100644
--- a/src/exchangedb/exchange-0001.sql
+++ b/src/exchangedb/exchange-0001.sql
@@ -377,6 +377,7 @@ CREATE TABLE IF NOT EXISTS refresh_revealed_coins
,coin_ev BYTEA NOT NULL -- UNIQUE
,h_coin_ev BYTEA NOT NULL CHECK(LENGTH(h_coin_ev)=64) -- UNIQUE
,ev_sig BYTEA NOT NULL
+ ,ewv BYTEA NOT NULL
-- ,PRIMARY KEY (melt_serial_id, freshcoin_index) -- done per shard
)
PARTITION BY HASH (melt_serial_id);
@@ -390,6 +391,8 @@ COMMENT ON COLUMN refresh_revealed_coins.freshcoin_index
IS 'index of the fresh coin being created (one melt operation may result in multiple fresh coins)';
COMMENT ON COLUMN refresh_revealed_coins.coin_ev
IS 'envelope of the new coin to be signed';
+COMMENT ON COLUMN refresh_revealed_coins.ewv
+ IS 'exchange contributed values in the creation of the fresh coin (see /csr)';
COMMENT ON COLUMN refresh_revealed_coins.h_coin_ev
IS 'hash of the envelope of the new coin to be signed (for lookups)';
COMMENT ON COLUMN refresh_revealed_coins.ev_sig
diff --git a/src/exchangedb/irbt_callbacks.c b/src/exchangedb/irbt_callbacks.c
index 0e0264e89..cb0685ba6 100644
--- a/src/exchangedb/irbt_callbacks.c
+++ b/src/exchangedb/irbt_callbacks.c
@@ -440,6 +440,8 @@ irbt_cb_table_refresh_revealed_coins (
GNUNET_PQ_query_param_auto_from_type (&h_coin_ev),
TALER_PQ_query_param_blinded_denom_sig (
&td->details.refresh_revealed_coins.ev_sig),
+ TALER_PQ_query_param_exchange_withdraw_values (
+ &td->details.refresh_revealed_coins.ewv),
GNUNET_PQ_query_param_uint64 (
&td->details.refresh_revealed_coins.denominations_serial),
GNUNET_PQ_query_param_uint64 (
diff --git a/src/exchangedb/lrbt_callbacks.c b/src/exchangedb/lrbt_callbacks.c
index 04be98696..dd7852131 100644
--- a/src/exchangedb/lrbt_callbacks.c
+++ b/src/exchangedb/lrbt_callbacks.c
@@ -790,6 +790,9 @@ lrbt_cb_table_refresh_revealed_coins (void *cls,
TALER_PQ_result_spec_blinded_denom_sig (
"ev_sig",
&td.details.refresh_revealed_coins.ev_sig),
+ TALER_PQ_result_spec_exchange_withdraw_values (
+ "ewv",
+ &td.details.refresh_revealed_coins.ewv),
GNUNET_PQ_result_spec_uint64 (
"denominations_serial",
&td.details.refresh_revealed_coins.denominations_serial),
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c
index 9694b73ce..7b8763eb6 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -891,13 +891,14 @@ prepare_statements (struct PostgresClosure *pg)
",link_sig "
",denominations_serial "
",coin_ev"
+ ",ewv"
",h_coin_ev"
",ev_sig"
") SELECT $1, $2, $3, "
- " denominations_serial, $5, $6, $7"
+ " denominations_serial, $5, $6, $7, $8"
" FROM denominations"
" WHERE denom_pub_hash=$4;",
- 7),
+ 8),
/* Obtain information about the coins created in a refresh
operation, used in #postgres_get_refresh_reveal() */
GNUNET_PQ_make_prepare (
@@ -908,6 +909,7 @@ prepare_statements (struct PostgresClosure *pg)
",rrc.h_coin_ev"
",rrc.link_sig"
",rrc.coin_ev"
+ ",rrc.ewv"
",rrc.ev_sig"
" FROM refresh_commitments"
" JOIN refresh_revealed_coins rrc"
@@ -1213,7 +1215,9 @@ prepare_statements (struct PostgresClosure *pg)
" tp.transfer_pub"
",denoms.denom_pub"
",rrc.ev_sig"
+ ",rrc.ewv"
",rrc.link_sig"
+ ",rrc.freshcoin_index"
" FROM refresh_commitments"
" JOIN refresh_revealed_coins rrc"
" USING (melt_serial_id)"
@@ -2241,6 +2245,7 @@ prepare_statements (struct PostgresClosure *pg)
",link_sig"
",coin_ev"
",ev_sig"
+ ",ewv"
",denominations_serial"
",melt_serial_id"
" FROM refresh_revealed_coins"
@@ -2532,11 +2537,12 @@ prepare_statements (struct PostgresClosure *pg)
",coin_ev"
",h_coin_ev"
",ev_sig"
+ ",ewv"
",denominations_serial"
",melt_serial_id"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7, $8);",
- 8),
+ "($1, $2, $3, $4, $5, $6, $7, $8, $9);",
+ 9),
GNUNET_PQ_make_prepare (
"insert_into_table_refresh_transfer_keys",
"INSERT INTO refresh_transfer_keys"
@@ -6095,6 +6101,8 @@ postgres_insert_refresh_reveal (
GNUNET_PQ_query_param_auto_from_type (&rrc->orig_coin_link_sig),
GNUNET_PQ_query_param_auto_from_type (&rrc->h_denom_pub),
TALER_PQ_query_param_blinded_planchet (&rrc->blinded_planchet),
+ // FIXME: needed? review link protocol!
+ TALER_PQ_query_param_exchange_withdraw_values (&rrc->exchange_vals),
GNUNET_PQ_query_param_auto_from_type (&rrc->coin_envelope_hash),
TALER_PQ_query_param_blinded_denom_sig (&rrc->coin_sig),
GNUNET_PQ_query_param_end
@@ -6203,6 +6211,9 @@ add_revealed_coins (void *cls,
&rrc->coin_envelope_hash),
TALER_PQ_result_spec_blinded_planchet ("coin_ev",
&rrc->blinded_planchet),
+ // FIXME: needed? review link protocol!
+ TALER_PQ_result_spec_exchange_withdraw_values ("ewv",
+ &rrc->exchange_vals),
TALER_PQ_result_spec_blinded_denom_sig ("ev_sig",
&rrc->coin_sig),
GNUNET_PQ_result_spec_end
@@ -6384,6 +6395,11 @@ add_ldl (void *cls,
&pos->orig_coin_link_sig),
TALER_PQ_result_spec_blinded_denom_sig ("ev_sig",
&pos->ev_sig),
+ GNUNET_PQ_result_spec_uint32 ("freshcoin_index",
+ &pos->coin_refresh_offset),
+ // FIXME: needed? review link protocol!
+ TALER_PQ_result_spec_exchange_withdraw_values ("ewv",
+ &pos->alg_values),
TALER_PQ_result_spec_denom_pub ("denom_pub",
&pos->denom_pub),
GNUNET_PQ_result_spec_end
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
index f86f5451c..e290502c6 100644
--- a/src/exchangedb/test_exchangedb.c
+++ b/src/exchangedb/test_exchangedb.c
@@ -1565,6 +1565,8 @@ run (void *cls)
TALER_denom_sig_unblind (&ds,
&cbc2.sig,
&bks,
+ &c_hash,
+ &alg_values,
&dkp->pub));
FAILIF (GNUNET_OK !=
TALER_denom_pub_verify (&dkp->pub,
@@ -1582,6 +1584,8 @@ run (void *cls)
TALER_denom_sig_unblind (&deposit.coin.denom_sig,
&cbc.sig,
&bks,
+ &c_hash,
+ &alg_values,
&dkp->pub));
deadline = GNUNET_TIME_timestamp_get ();
{
@@ -1760,6 +1764,7 @@ run (void *cls)
rp->blinded_msg_size);
TALER_denom_pub_hash (&new_dkp[cnt]->pub,
&ccoin->h_denom_pub);
+ ccoin->exchange_vals = alg_values;
TALER_coin_ev_hash (bp,
&ccoin->h_denom_pub,
&ccoin->coin_envelope_hash);
@@ -2167,6 +2172,8 @@ run (void *cls)
TALER_denom_sig_unblind (&deposit.coin.denom_sig,
&cbc.sig,
&bks,
+ &c_hash,
+ &alg_values,
&dkp->pub));
RND_BLK (&deposit.csig);
RND_BLK (&deposit.merchant_pub);
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
index 8269672fe..1cd90c28f 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -317,6 +317,7 @@ struct TALER_EXCHANGEDB_TableData
uint64_t denominations_serial;
void *coin_ev;
size_t coin_ev_size;
+ struct TALER_ExchangeWithdrawValues ewv;
// h_coin_ev omitted, to be recomputed!
struct TALER_BlindedDenominationSignature ev_sig;
} refresh_revealed_coins;
@@ -1369,11 +1370,22 @@ struct TALER_EXCHANGEDB_LinkList
struct TALER_BlindedDenominationSignature ev_sig;
/**
+ * Exchange-provided values during the coin generation.
+ */
+ struct TALER_ExchangeWithdrawValues alg_values;
+
+ /**
* Signature of the original coin being refreshed over the
* link data, of type #TALER_SIGNATURE_WALLET_COIN_LINK
*/
struct TALER_CoinSpendSignatureP orig_coin_link_sig;
+ /**
+ * Offset that generated this coin in the refresh
+ * operation.
+ */
+ uint32_t coin_refresh_offset;
+
};
@@ -1646,6 +1658,12 @@ struct TALER_EXCHANGEDB_RefreshRevealedCoin
struct TALER_BlindedDenominationSignature coin_sig;
/**
+ * Values contributed from the exchange to the
+ * coin generation (see /csr).
+ */
+ struct TALER_ExchangeWithdrawValues exchange_vals;
+
+ /**
* Blinded message to be signed (in envelope).
*/
struct TALER_BlindedPlanchet blinded_planchet;
diff --git a/src/include/taler_pq_lib.h b/src/include/taler_pq_lib.h
index fa3128462..81f5c9872 100644
--- a/src/include/taler_pq_lib.h
+++ b/src/include/taler_pq_lib.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015, 2016 Taler Systems SA
+ Copyright (C) 2014-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -103,6 +103,18 @@ TALER_PQ_query_param_blinded_denom_sig (
/**
+ * Generate query parameter for the exchange's contribution during a
+ * withdraw. Internally, the various attributes of the @a alg_values will be
+ * serialized into on variable-size BLOB.
+ *
+ * @param x pointer to the query parameter to pass
+ */
+struct GNUNET_PQ_QueryParam
+TALER_PQ_query_param_exchange_withdraw_values (
+ const struct TALER_ExchangeWithdrawValues *alg_values);
+
+
+/**
* Generate query parameter for a JSON object (stored as a string
* in the DB). Note that @a x must really be a JSON object or array,
* passing just a value (string, integer) is not supported and will
@@ -180,6 +192,19 @@ TALER_PQ_result_spec_blinded_denom_sig (
/**
+ * Exchange withdraw values expected.
+ *
+ * @param name name of the field in the table
+ * @param[out] ewv where to store the exchange values
+ * @return array entry for the result specification to use
+ */
+struct GNUNET_PQ_ResultSpec
+TALER_PQ_result_spec_exchange_withdraw_values (
+ const char *name,
+ struct TALER_ExchangeWithdrawValues *ewv);
+
+
+/**
* Blinded planchet expected.
*
* @param name name of the field in the table
diff --git a/src/lib/exchange_api_link.c b/src/lib/exchange_api_link.c
index cfa70617e..0b2a1336b 100644
--- a/src/lib/exchange_api_link.c
+++ b/src/lib/exchange_api_link.c
@@ -95,18 +95,25 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,
struct TALER_DenominationPublicKey rpub;
struct TALER_CoinSpendSignatureP link_sig;
union TALER_DenominationBlindingKeyP bks;
+ struct TALER_ExchangeWithdrawValues alg_values;
+ uint32_t coin_idx;
struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_denom_pub ("denom_pub",
&rpub),
TALER_JSON_spec_blinded_denom_sig ("ev_sig",
&bsig),
+ // FIXME: add to spec!
+ TALER_JSON_spec_exchange_withdraw_values ("ewv",
+ &alg_values),
GNUNET_JSON_spec_fixed_auto ("link_sig",
&link_sig),
+ // FIXME: add to spec!
+ GNUNET_JSON_spec_uint32 ("coin_idx",
+ &coin_idx),
GNUNET_JSON_spec_end ()
};
struct TALER_TransferSecretP secret;
struct TALER_PlanchetSecretsP ps;
- struct TALER_ExchangeWithdrawValues alg_values;
struct TALER_PlanchetDetail pd;
struct TALER_CoinPubHash c_hash;
@@ -125,9 +132,6 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,
TALER_transfer_secret_to_planchet_secret (&secret,
coin_num,
&ps);
-
- // TODO: implement cipher handling
- alg_values.cipher = TALER_DENOMINATION_RSA;
TALER_planchet_setup_coin_priv (&ps,
&alg_values,
coin_priv);
@@ -165,6 +169,20 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,
GNUNET_CRYPTO_eddsa_key_get_public (&lh->coin_priv.eddsa_priv,
&old_coin_pub.eddsa_pub);
+ // FIXME-NEXT: this is probably the wrong 'ps'!
+ // However, the 'right' PS is not something the
+ // exchange could even give us. So probably we
+ // really need to change the derivation structure
+ // during refresh to derive the nonces differently
+ // and make /link possible!
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Link using PS(%u)=%s\n",
+ (unsigned int) coin_idx,
+ TALER_B2S (&ps));
+ TALER_cs_refresh_nonce_derive (
+ &ps,
+ coin_idx,
+ &pd.blinded_planchet.details.cs_blinded_planchet.nonce);
TALER_coin_ev_hash (&pd.blinded_planchet,
&pd.denom_pub_hash,
&coin_envelope_hash);
diff --git a/src/lib/exchange_api_refresh_common.c b/src/lib/exchange_api_refresh_common.c
index b901bab32..c15527369 100644
--- a/src/lib/exchange_api_refresh_common.c
+++ b/src/lib/exchange_api_refresh_common.c
@@ -150,6 +150,10 @@ TALER_EXCHANGE_get_melt_data_ (
so this computation is redundant, and here additionally
repeated KAPPA times. Could be avoided with slightly
more bookkeeping in the future */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Refresh using PS(%u)=%s\n",
+ j,
+ TALER_B2S (&ps));
TALER_cs_refresh_nonce_derive (
ps,
j,
diff --git a/src/pq/pq_query_helper.c b/src/pq/pq_query_helper.c
index 8d6df60ce..9bffdd320 100644
--- a/src/pq/pq_query_helper.c
+++ b/src/pq/pq_query_helper.c
@@ -531,6 +531,94 @@ TALER_PQ_query_param_blinded_planchet (
* Function called to convert input argument into SQL parameters.
*
* @param cls closure
+ * @param data pointer to input argument
+ * @param data_len number of bytes in @a data (if applicable)
+ * @param[out] param_values SQL data to set
+ * @param[out] param_lengths SQL length data to set
+ * @param[out] param_formats SQL format data to set
+ * @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
+ * @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc()
+ * @param scratch_length number of entries left in @a scratch
+ * @return -1 on error, number of offsets used in @a scratch otherwise
+ */
+static int
+qconv_exchange_withdraw_values (void *cls,
+ const void *data,
+ size_t data_len,
+ void *param_values[],
+ int param_lengths[],
+ int param_formats[],
+ unsigned int param_length,
+ void *scratch[],
+ unsigned int scratch_length)
+{
+ const struct TALER_ExchangeWithdrawValues *alg_values = data;
+ size_t tlen;
+ size_t len;
+ uint32_t be[2];
+ char *buf;
+
+ (void) cls;
+ (void) data_len;
+ GNUNET_assert (1 == param_length);
+ GNUNET_assert (scratch_length > 0);
+ GNUNET_break (NULL == cls);
+ be[0] = htonl ((uint32_t) alg_values->cipher);
+ be[1] = htonl (0x010000); /* magic marker: EWV */
+ switch (alg_values->cipher)
+ {
+ case TALER_DENOMINATION_RSA:
+ tlen = 0;
+ break;
+ case TALER_DENOMINATION_CS:
+ tlen = sizeof (struct TALER_ExchangeWithdrawCsValues);
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+ len = tlen + sizeof (be);
+ buf = GNUNET_malloc (len);
+ memcpy (buf,
+ &be,
+ sizeof (be));
+ switch (alg_values->cipher)
+ {
+ case TALER_DENOMINATION_RSA:
+ break;
+ case TALER_DENOMINATION_CS:
+ memcpy (&buf[sizeof (be)],
+ &alg_values->details.cs_values,
+ tlen);
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+ scratch[0] = buf;
+ param_values[0] = (void *) buf;
+ param_lengths[0] = len;
+ param_formats[0] = 1;
+ return 1;
+}
+
+
+struct GNUNET_PQ_QueryParam
+TALER_PQ_query_param_exchange_withdraw_values (
+ const struct TALER_ExchangeWithdrawValues *alg_values)
+{
+ struct GNUNET_PQ_QueryParam res = {
+ .conv = &qconv_exchange_withdraw_values,
+ .data = alg_values,
+ .num_params = 1
+ };
+
+ return res;
+}
+
+
+/**
+ * Function called to convert input argument into SQL parameters.
+ *
+ * @param cls closure
* @param data pointer to input argument, here a `json_t *`
* @param data_len number of bytes in @a data (if applicable)
* @param[out] param_values SQL data to set
diff --git a/src/pq/pq_result_helper.c b/src/pq/pq_result_helper.c
index 6ee5da53e..33edc889b 100644
--- a/src/pq/pq_result_helper.c
+++ b/src/pq/pq_result_helper.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015, 2016, 2021 Taler Systems SA
+ Copyright (C) 2014-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -855,4 +855,110 @@ TALER_PQ_result_spec_blinded_planchet (
}
+/**
+ * Extract data from a Postgres database @a result at row @a row.
+ *
+ * @param cls closure
+ * @param result where to extract data from
+ * @param int row to extract data from
+ * @param fname name (or prefix) of the fields to extract from
+ * @param[in,out] dst_size where to store size of result, may be NULL
+ * @param[out] dst where to store the result
+ * @return
+ * #GNUNET_YES if all results could be extracted
+ * #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
+ */
+static enum GNUNET_GenericReturnValue
+extract_exchange_withdraw_values (void *cls,
+ PGresult *result,
+ int row,
+ const char *fname,
+ size_t *dst_size,
+ void *dst)
+{
+ struct TALER_ExchangeWithdrawValues *alg_values = dst;
+ size_t len;
+ const char *res;
+ int fnum;
+ uint32_t be[2];
+
+ (void) cls;
+ (void) dst_size;
+ fnum = PQfnumber (result,
+ fname);
+ if (fnum < 0)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (PQgetisnull (result,
+ row,
+ fnum))
+ return GNUNET_NO;
+
+ /* if a field is null, continue but
+ * remember that we now return a different result */
+ len = PQgetlength (result,
+ row,
+ fnum);
+ res = PQgetvalue (result,
+ row,
+ fnum);
+ if (len < sizeof (be))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ memcpy (&be,
+ res,
+ sizeof (be));
+ if (0x010000 != ntohl (be[1])) /* magic marker: EWV */
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ res += sizeof (be);
+ len -= sizeof (be);
+ alg_values->cipher = ntohl (be[0]);
+ switch (alg_values->cipher)
+ {
+ case TALER_DENOMINATION_RSA:
+ if (0 != len)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+ case TALER_DENOMINATION_CS:
+ if (sizeof (struct TALER_ExchangeWithdrawCsValues) != len)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ memcpy (&alg_values->details.cs_values,
+ res,
+ len);
+ return GNUNET_OK;
+ default:
+ GNUNET_break (0);
+ }
+ return GNUNET_SYSERR;
+}
+
+
+struct GNUNET_PQ_ResultSpec
+TALER_PQ_result_spec_exchange_withdraw_values (
+ const char *name,
+ struct TALER_ExchangeWithdrawValues *ewv)
+{
+ struct GNUNET_PQ_ResultSpec res = {
+ .conv = &extract_exchange_withdraw_values,
+ .dst = (void *) ewv,
+ .fname = name
+ };
+
+ return res;
+}
+
+
/* end of pq_result_helper.c */
diff --git a/src/testing/test_exchange_api.c b/src/testing/test_exchange_api.c
index 1b31b646a..d045c21ea 100644
--- a/src/testing/test_exchange_api.c
+++ b/src/testing/test_exchange_api.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014--2020 Taler Systems SA
+ Copyright (C) 2014--2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as
@@ -41,9 +41,12 @@
*/
static char *config_file;
+/**
+ * Special configuration file to use when we want reserves
+ * to expire 'immediately'.
+ */
static char *config_file_expire_reserve_now;
-
/**
* Exchange configuration data.
*/
@@ -54,6 +57,14 @@ static struct TALER_TESTING_ExchangeConfiguration ec;
*/
static struct TALER_TESTING_BankConfiguration bc;
+/**
+ * Some tests behave differently when using CS as we cannot
+ * re-use the coin private key for different denominations
+ * due to the derivation of it with the /csr values. Hence
+ * some tests behave differently in CS mode, hence this
+ * flag.
+ */
+static bool uses_cs;
/**
* Execute the taler-exchange-wirewatch command with
@@ -142,6 +153,11 @@ run (void *cls,
/**
* Withdraw EUR:1 using the SAME private coin key as for the previous coin
* (in violation of the specification, to be detected on spending!).
+ * However, note that this does NOT work with 'CS', as for a different
+ * denomination we get different R0/R1 values from the exchange, and
+ * thus will generate a different coin private key as R0/R1 are hashed
+ * into the coin priv. So here, we fail to 'reuse' the key due to the
+ * cryptographic construction!
*/
TALER_TESTING_cmd_withdraw_amount_reuse_key ("withdraw-coin-1x",
"create-reserve-1",
@@ -180,6 +196,13 @@ run (void *cls,
TALER_TESTING_cmd_deposit_replay ("deposit-simple-replay",
"deposit-simple",
MHD_HTTP_OK),
+ /* This creates a conflict, as we have the same coin public key (reuse!),
+ but different denomination public keys (which is not allowed).
+ However, note that this does NOT work with 'CS', as for a different
+ denomination we get different R0/R1 values from the exchange, and
+ thus will generate a different coin private key as R0/R1 are hashed
+ into the coin priv. So here, we fail to 'reuse' the key due to the
+ cryptographic construction! */
TALER_TESTING_cmd_deposit ("deposit-reused-coin-key-failure",
"withdraw-coin-1x",
0,
@@ -187,7 +210,9 @@ run (void *cls,
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO,
"EUR:1",
- MHD_HTTP_CONFLICT),
+ uses_cs
+ ? MHD_HTTP_OK
+ : MHD_HTTP_CONFLICT),
/**
* Try to double spend using different wire details.
*/
@@ -230,7 +255,10 @@ run (void *cls,
struct TALER_TESTING_Command refresh[] = {
/**
* Try to melt the coin that shared the private key with another
- * coin (should fail). */
+ * coin (should fail). Note that in the CS-case, we fail also
+ * with MHD_HTTP_CONFLICT, but for a different reason: here it
+ * is not a denomination conflict, but a double-spending conflict.
+ */
TALER_TESTING_cmd_melt ("refresh-melt-reused-coin-key-failure",
"withdraw-coin-1x",
MHD_HTTP_CONFLICT,
@@ -839,7 +867,9 @@ run (void *cls,
config_file),
/* Check recoup is failing for the coin with the reused coin key */
TALER_TESTING_cmd_recoup ("recoup-2x",
- MHD_HTTP_CONFLICT,
+ uses_cs
+ ? MHD_HTTP_OK
+ : MHD_HTTP_CONFLICT,
"withdraw-coin-1x",
"EUR:1"),
TALER_TESTING_cmd_recoup ("recoup-2",
@@ -988,6 +1018,7 @@ main (int argc,
NULL);
cipher = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
GNUNET_assert (NULL != cipher);
+ uses_cs = (0 == strcmp (cipher, "cs"));
GNUNET_asprintf (&config_file,
"test_exchange_api-%s.conf",
cipher);
diff --git a/src/util/crypto.c b/src/util/crypto.c
index 447805bfe..76657f41d 100644
--- a/src/util/crypto.c
+++ b/src/util/crypto.c
@@ -277,6 +277,7 @@ TALER_planchet_blinding_secret_create (
}
+// FIXME: move to denom.c?
void
TALER_planchet_setup_coin_priv (
const struct TALER_PlanchetSecretsP *ps,