diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/exchange/taler-exchange-httpd_link.c | 6 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_refreshes_reveal.c | 19 | ||||
-rw-r--r-- | src/exchangedb/exchange-0001.sql | 3 | ||||
-rw-r--r-- | src/exchangedb/irbt_callbacks.c | 2 | ||||
-rw-r--r-- | src/exchangedb/lrbt_callbacks.c | 3 | ||||
-rw-r--r-- | src/exchangedb/plugin_exchangedb_postgres.c | 24 | ||||
-rw-r--r-- | src/exchangedb/test_exchangedb.c | 7 | ||||
-rw-r--r-- | src/include/taler_exchangedb_plugin.h | 18 | ||||
-rw-r--r-- | src/include/taler_pq_lib.h | 27 | ||||
-rw-r--r-- | src/lib/exchange_api_link.c | 26 | ||||
-rw-r--r-- | src/lib/exchange_api_refresh_common.c | 4 | ||||
-rw-r--r-- | src/pq/pq_query_helper.c | 88 | ||||
-rw-r--r-- | src/pq/pq_result_helper.c | 108 | ||||
-rw-r--r-- | src/testing/test_exchange_api.c | 41 | ||||
-rw-r--r-- | src/util/crypto.c | 1 |
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, |