diff options
author | Christian Grothoff <christian@grothoff.org> | 2022-02-14 23:02:25 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2022-02-14 23:02:25 +0100 |
commit | bd77bcb52dcad4b761f3db0acaa6b71b112a31c2 (patch) | |
tree | f519ebc30bf0917d9f2e91667a20beac71284586 /src | |
parent | f4f40a31efd3028dec36c0b84a49617926b5f9c3 (diff) | |
download | exchange-bd77bcb52dcad4b761f3db0acaa6b71b112a31c2.tar.xz |
-towards fixing the protocol
Diffstat (limited to 'src')
-rw-r--r-- | src/exchange/taler-exchange-httpd_link.c | 8 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_recoup-refresh.c | 12 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_recoup.c | 12 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_refreshes_reveal.c | 7 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_withdraw.c | 4 | ||||
-rw-r--r-- | src/exchangedb/plugin_exchangedb_postgres.c | 10 | ||||
-rw-r--r-- | src/include/taler_exchangedb_plugin.h | 9 | ||||
-rw-r--r-- | src/lib/exchange_api_link.c | 17 | ||||
-rw-r--r-- | src/lib/exchange_api_recoup.c | 19 | ||||
-rw-r--r-- | src/lib/exchange_api_recoup_refresh.c | 21 | ||||
-rw-r--r-- | src/util/denom.c | 6 |
11 files changed, 120 insertions, 5 deletions
diff --git a/src/exchange/taler-exchange-httpd_link.c b/src/exchange/taler-exchange-httpd_link.c index de10f8b82..47b803ffa 100644 --- a/src/exchange/taler-exchange-httpd_link.c +++ b/src/exchange/taler-exchange-httpd_link.c @@ -91,7 +91,13 @@ handle_link_data (void *cls, TALER_JSON_pack_exchange_withdraw_values ("ewv", &pos->alg_values), GNUNET_JSON_pack_data_auto ("link_sig", - &pos->orig_coin_link_sig)); + &pos->orig_coin_link_sig), + GNUNET_JSON_pack_allow_null ( + pos->have_nonce + ? GNUNET_JSON_pack_data_auto ("cs_nonce", + &pos->nonce) + : GNUNET_JSON_pack_string ("cs_nonce", + NULL))); if ( (NULL == obj) || (0 != json_array_append_new (list, diff --git a/src/exchange/taler-exchange-httpd_recoup-refresh.c b/src/exchange/taler-exchange-httpd_recoup-refresh.c index 3e0588940..829e2cbd7 100644 --- a/src/exchange/taler-exchange-httpd_recoup-refresh.c +++ b/src/exchange/taler-exchange-httpd_recoup-refresh.c @@ -174,6 +174,7 @@ verify_and_execute_recoup_refresh ( const struct TALER_CoinPublicInfo *coin, const struct TALER_ExchangeWithdrawValues *exchange_vals, const union TALER_DenominationBlindingKeyP *coin_bks, + const struct TALER_CsNonce *nonce, const struct TALER_CoinSpendSignatureP *coin_sig) { struct RecoupContext pc; @@ -263,6 +264,9 @@ verify_and_execute_recoup_refresh ( TALER_EC_EXCHANGE_RECOUP_REFRESH_BLINDING_FAILED, NULL); } + if (TALER_DENOMINATION_CS == blinded_planchet.cipher) + blinded_planchet.details.cs_blinded_planchet.nonce + = *nonce; TALER_coin_ev_hash (&blinded_planchet, &coin->denom_pub_hash, &h_blind); @@ -360,6 +364,7 @@ TEH_handler_recoup_refresh (struct MHD_Connection *connection, union TALER_DenominationBlindingKeyP coin_bks; struct TALER_CoinSpendSignatureP coin_sig; struct TALER_ExchangeWithdrawValues exchange_vals; + struct TALER_CsNonce nonce; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("denom_pub_hash", &coin.denom_pub_hash), @@ -371,12 +376,18 @@ TEH_handler_recoup_refresh (struct MHD_Connection *connection, &coin_bks), GNUNET_JSON_spec_fixed_auto ("coin_sig", &coin_sig), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_fixed_auto ("cs_nonce", + &nonce)), GNUNET_JSON_spec_end () }; memset (&coin, 0, sizeof (coin)); + memset (&nonce, + 0, + sizeof (nonce)); coin.coin_pub = *coin_pub; ret = TALER_MHD_parse_json_data (connection, root, @@ -392,6 +403,7 @@ TEH_handler_recoup_refresh (struct MHD_Connection *connection, &coin, &exchange_vals, &coin_bks, + &nonce, &coin_sig); GNUNET_JSON_parse_free (spec); return res; diff --git a/src/exchange/taler-exchange-httpd_recoup.c b/src/exchange/taler-exchange-httpd_recoup.c index f4e426fbb..c635769c6 100644 --- a/src/exchange/taler-exchange-httpd_recoup.c +++ b/src/exchange/taler-exchange-httpd_recoup.c @@ -177,6 +177,7 @@ verify_and_execute_recoup ( const struct TALER_CoinPublicInfo *coin, const struct TALER_ExchangeWithdrawValues *exchange_vals, const union TALER_DenominationBlindingKeyP *coin_bks, + const struct TALER_CsNonce *nonce, const struct TALER_CoinSpendSignatureP *coin_sig) { struct RecoupContext pc; @@ -268,6 +269,9 @@ verify_and_execute_recoup ( TALER_EC_EXCHANGE_RECOUP_BLINDING_FAILED, NULL); } + if (TALER_DENOMINATION_CS == blinded_planchet.cipher) + blinded_planchet.details.cs_blinded_planchet.nonce + = *nonce; if (GNUNET_OK != TALER_coin_ev_hash (&blinded_planchet, &coin->denom_pub_hash, @@ -373,6 +377,7 @@ TEH_handler_recoup (struct MHD_Connection *connection, union TALER_DenominationBlindingKeyP coin_bks; struct TALER_CoinSpendSignatureP coin_sig; struct TALER_ExchangeWithdrawValues exchange_vals; + struct TALER_CsNonce nonce; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("denom_pub_hash", &coin.denom_pub_hash), @@ -384,12 +389,18 @@ TEH_handler_recoup (struct MHD_Connection *connection, &coin_bks), GNUNET_JSON_spec_fixed_auto ("coin_sig", &coin_sig), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_fixed_auto ("cs_nonce", + &nonce)), GNUNET_JSON_spec_end () }; memset (&coin, 0, sizeof (coin)); + memset (&nonce, + 0, + sizeof (nonce)); coin.coin_pub = *coin_pub; ret = TALER_MHD_parse_json_data (connection, root, @@ -408,6 +419,7 @@ TEH_handler_recoup (struct MHD_Connection *connection, &coin, &exchange_vals, &coin_bks, + &nonce, &coin_sig); GNUNET_JSON_parse_free (spec); return res; diff --git a/src/exchange/taler-exchange-httpd_refreshes_reveal.c b/src/exchange/taler-exchange-httpd_refreshes_reveal.c index 0d8f7bf9b..779b9df45 100644 --- a/src/exchange/taler-exchange-httpd_refreshes_reveal.c +++ b/src/exchange/taler-exchange-httpd_refreshes_reveal.c @@ -634,6 +634,13 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection, rrc->blinded_planchet = rcds[i].blinded_planchet; } + // FIXME: in CS-case, we MUST check if signatures + // already exist under the given nonce + // (TODO: check: refresh session hash OK?), and if so, + // we MUST return the existing signatures (c0/c1 may have changed!) + // and MUST NOT return the fresh signatures! + // => change this to a 'do_refresh_reveal' and + // change SQL to return existing signatures (if any)! qs = TEH_plugin->insert_refresh_reveal (TEH_plugin->cls, melt_serial_id, num_fresh_coins, diff --git a/src/exchange/taler-exchange-httpd_withdraw.c b/src/exchange/taler-exchange-httpd_withdraw.c index 7572f85d2..3799187c1 100644 --- a/src/exchange/taler-exchange-httpd_withdraw.c +++ b/src/exchange/taler-exchange-httpd_withdraw.c @@ -535,6 +535,10 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc, /* Clean up and send back final response */ GNUNET_JSON_parse_free (spec); + // FIXME: in CS-case, we MUST re-transmit any _existing_ signature + // (if database had a record matching the nonce) + // instead of sending a 'fresh' one back (as c0/c1 may differ in + // a client attack! { MHD_RESULT ret; diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index dfa18e9e3..ce184f48d 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -1218,6 +1218,7 @@ prepare_statements (struct PostgresClosure *pg) ",rrc.ewv" ",rrc.link_sig" ",rrc.freshcoin_index" + ",rrc.coin_ev" " FROM refresh_commitments" " JOIN refresh_revealed_coins rrc" " USING (melt_serial_id)" @@ -6385,6 +6386,7 @@ add_ldl (void *cls, pos = GNUNET_new (struct TALER_EXCHANGEDB_LinkList); { + struct TALER_BlindedPlanchet bp; struct GNUNET_PQ_ResultSpec rs[] = { GNUNET_PQ_result_spec_auto_from_type ("transfer_pub", &transfer_pub), @@ -6398,6 +6400,8 @@ add_ldl (void *cls, &pos->alg_values), TALER_PQ_result_spec_denom_pub ("denom_pub", &pos->denom_pub), + TALER_PQ_result_spec_blinded_planchet ("coin_ev", + &bp), GNUNET_PQ_result_spec_end }; @@ -6411,6 +6415,12 @@ add_ldl (void *cls, ldctx->status = GNUNET_SYSERR; return; } + if (TALER_DENOMINATION_CS == bp.cipher) + { + pos->nonce = bp.details.cs_blinded_planchet.nonce; + pos->have_nonce = true; + } + TALER_blinded_planchet_free (&bp); } if ( (NULL != ldctx->last) && (0 == GNUNET_memcmp (&transfer_pub, diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 844de5853..eea170c19 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -1381,11 +1381,20 @@ struct TALER_EXCHANGEDB_LinkList struct TALER_CoinSpendSignatureP orig_coin_link_sig; /** + * CS nonce, if cipher is CS. + */ + struct TALER_CsNonce nonce; + + /** * Offset that generated this coin in the refresh * operation. */ uint32_t coin_refresh_offset; + /** + * Set to true if @e nonce was initialized. + */ + bool have_nonce; }; diff --git a/src/lib/exchange_api_link.c b/src/lib/exchange_api_link.c index 6ebb72271..a44ccdcea 100644 --- a/src/lib/exchange_api_link.c +++ b/src/lib/exchange_api_link.c @@ -92,6 +92,7 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh, struct TALER_CoinSpendSignatureP link_sig; union TALER_DenominationBlindingKeyP bks; struct TALER_ExchangeWithdrawValues alg_values; + struct TALER_CsNonce nonce; uint32_t coin_idx; struct GNUNET_JSON_Specification spec[] = { TALER_JSON_spec_denom_pub ("denom_pub", @@ -104,6 +105,9 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh, &link_sig), GNUNET_JSON_spec_uint32 ("coin_idx", &coin_idx), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_fixed_auto ("cs_nonce", + &nonce)), GNUNET_JSON_spec_end () }; struct TALER_TransferSecretP secret; @@ -111,6 +115,9 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh, struct TALER_CoinPubHash c_hash; /* parse reply */ + memset (&nonce, + 0, + sizeof (nonce)); if (GNUNET_OK != GNUNET_JSON_parse (json, spec, @@ -143,6 +150,16 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh, GNUNET_JSON_parse_free (spec); return GNUNET_SYSERR; } + if (TALER_DENOMINATION_CS == alg_values.cipher) + { + if (GNUNET_is_zero (&nonce)) + { + GNUNET_break_op (0); + GNUNET_JSON_parse_free (spec); + return GNUNET_SYSERR; + } + pd.blinded_planchet.details.cs_blinded_planchet.nonce = nonce; + } /* extract coin and signature */ if (GNUNET_OK != TALER_denom_sig_unblind (&lci->sig, diff --git a/src/lib/exchange_api_recoup.c b/src/lib/exchange_api_recoup.c index a4ad0ccee..9b7201cd0 100644 --- a/src/lib/exchange_api_recoup.c +++ b/src/lib/exchange_api_recoup.c @@ -328,6 +328,25 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange, &coin_sig), GNUNET_JSON_pack_data_auto ("coin_blind_key_secret", &bks)); + if (TALER_DENOMINATION_CS == denom_sig->cipher) + { + struct TALER_CsNonce nonce; + + // FIXME: add this to the spec! + /* NOTE: this is not elegant, and as per the note in TALER_coin_ev_hash() + it is not strictly clear that the nonce is needed. Best case would be + to find a way to include it more 'naturally' somehow, for example with + the variant union version of bks! */ + TALER_cs_withdraw_nonce_derive (ps, + &nonce); + GNUNET_assert ( + 0 == + json_object_set_new (recoup_obj, + "cs_nonce", + GNUNET_JSON_from_data_auto ( + &nonce))); + } + { char pub_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2]; char *end; diff --git a/src/lib/exchange_api_recoup_refresh.c b/src/lib/exchange_api_recoup_refresh.c index 9133e5942..02e994155 100644 --- a/src/lib/exchange_api_recoup_refresh.c +++ b/src/lib/exchange_api_recoup_refresh.c @@ -332,6 +332,27 @@ TALER_EXCHANGE_recoup_refresh ( &coin_sig), GNUNET_JSON_pack_data_auto ("coin_blind_key_secret", &bks)); + + if (TALER_DENOMINATION_CS == denom_sig->cipher) + { + struct TALER_CsNonce nonce; + + // FIXME: add this to the spec! + /* NOTE: this is not elegant, and as per the note in TALER_coin_ev_hash() + it is not strictly clear that the nonce is needed. Best case would be + to find a way to include it more 'naturally' somehow, for example with + the variant union version of bks! */ + TALER_cs_refresh_nonce_derive (rms, + idx, + &nonce); + GNUNET_assert ( + 0 == + json_object_set_new (recoup_obj, + "cs_nonce", + GNUNET_JSON_from_data_auto ( + &nonce))); + } + { char pub_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2]; char *end; diff --git a/src/util/denom.c b/src/util/denom.c index 69e723503..30e8dc9d4 100644 --- a/src/util/denom.c +++ b/src/util/denom.c @@ -806,18 +806,16 @@ TALER_coin_ev_hash (const struct TALER_BlindedPlanchet *blinded_planchet, blinded_planchet->details.rsa_blinded_planchet.blinded_msg_size); break; case TALER_DENOMINATION_CS: + // FIMXE: c-values MUST NOT be included in idempotency check + // during withdraw/refresh, but right now they are!!! GNUNET_CRYPTO_hash_context_read ( hash_context, &blinded_planchet->details.cs_blinded_planchet.c[0], sizeof (struct GNUNET_CRYPTO_CsC) * 2); -#if FIXME - /* Must include this for refresh check, but - must EXCLUDE this in link signature (see TALER_LinkDataPS!) */ GNUNET_CRYPTO_hash_context_read ( hash_context, &blinded_planchet->details.cs_blinded_planchet.nonce, sizeof (struct TALER_CsNonce)); -#endif break; default: GNUNET_break (0); |