From 2d01575f5810be410e49564288268671945eb625 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 9 Nov 2024 20:35:01 +0100 Subject: implement protocol v22, fixes #9185 --- src/exchange/taler-exchange-httpd_batch-deposit.c | 21 ++++++++ src/exchange/taler-exchange-httpd_config.h | 2 +- src/exchangedb/0005-legitimization_processes.sql | 2 +- src/exchangedb/0007-batch_deposits.sql | 21 ++++---- src/exchangedb/exchange-0007.sql.in | 1 + src/exchangedb/exchange_do_deposit.sql | 3 ++ src/exchangedb/pg_do_deposit.c | 6 ++- src/include/taler_crypto_lib.h | 23 +++++++-- src/include/taler_exchange_service.h | 6 +++ src/include/taler_exchangedb_plugin.h | 6 +++ src/lib/Makefile.am | 2 +- src/lib/exchange_api_batch_deposit.c | 6 +++ src/lib/exchange_api_handle.c | 4 +- src/util/merchant_signatures.c | 59 +++++++++++++++-------- 14 files changed, 124 insertions(+), 38 deletions(-) diff --git a/src/exchange/taler-exchange-httpd_batch-deposit.c b/src/exchange/taler-exchange-httpd_batch-deposit.c index e46d2124a..07651a470 100644 --- a/src/exchange/taler-exchange-httpd_batch-deposit.c +++ b/src/exchange/taler-exchange-httpd_batch-deposit.c @@ -904,6 +904,10 @@ bdc_phase_parse (struct BatchDepositContext *bdc, &bd->wire_salt), GNUNET_JSON_spec_fixed_auto ("merchant_pub", &bd->merchant_pub), + GNUNET_JSON_spec_mark_optional ( /* since v22, we are compatible */ + GNUNET_JSON_spec_fixed_auto ("merchant_sig", + &bd->merchant_sig), + NULL), GNUNET_JSON_spec_fixed_auto ("h_contract_terms", &bd->h_contract_terms), GNUNET_JSON_spec_mark_optional ( @@ -950,6 +954,23 @@ bdc_phase_parse (struct BatchDepositContext *bdc, return; } } + if ( (! GNUNET_is_zero (&bd->merchant_sig)) && + (GNUNET_OK != + TALER_merchant_contract_verify ( + &bd->h_contract_terms, + &bd->merchant_pub, + &bd->merchant_sig)) ) + { + GNUNET_break_op (0); + GNUNET_JSON_parse_free (spec); + finish_loop (bdc, + TALER_MHD_reply_with_error ( + bdc->rc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "merchant_sig")); + return; + } bdc->policy_json = json_incref ((json_t *) policy_json); GNUNET_log (GNUNET_ERROR_TYPE_INFO, diff --git a/src/exchange/taler-exchange-httpd_config.h b/src/exchange/taler-exchange-httpd_config.h index 486a8b83b..e033ac29c 100644 --- a/src/exchange/taler-exchange-httpd_config.h +++ b/src/exchange/taler-exchange-httpd_config.h @@ -41,7 +41,7 @@ * * Returned via both /config and /keys endpoints. */ -#define EXCHANGE_PROTOCOL_VERSION "21:0:4" +#define EXCHANGE_PROTOCOL_VERSION "22:0:5" /** diff --git a/src/exchangedb/0005-legitimization_processes.sql b/src/exchangedb/0005-legitimization_processes.sql index c1bffca7d..d8222bf6c 100644 --- a/src/exchangedb/0005-legitimization_processes.sql +++ b/src/exchangedb/0005-legitimization_processes.sql @@ -22,7 +22,7 @@ LANGUAGE plpgsql AS $$ BEGIN PERFORM create_partitioned_table( - 'ALTER TABLE legitimization_processes' + 'ALTER TABLE %I' ' ADD COLUMN legitimization_measure_serial_id BIGINT' ',ADD COLUMN measure_index INT4 DEFAULT(0)' ',ADD COLUMN error_code INT4 DEFAULT (0)' diff --git a/src/exchangedb/0007-batch_deposits.sql b/src/exchangedb/0007-batch_deposits.sql index 65055f6ad..44c832484 100644 --- a/src/exchangedb/0007-batch_deposits.sql +++ b/src/exchangedb/0007-batch_deposits.sql @@ -14,25 +14,28 @@ -- TALER; see the file COPYING. If not, see -- -CREATE FUNCTION alter_table_batch_deposits7() +CREATE FUNCTION alter_table_batch_deposits7( + IN partition_suffix TEXT DEFAULT NULL +) RETURNS VOID LANGUAGE plpgsql AS $$ -DECLARE - table_name TEXT DEFAULT 'batch_deposits'; BEGIN - EXECUTE FORMAT ( - 'ALTER TABLE ' || table_name || + PERFORM create_partitioned_table( + 'ALTER TABLE %I' ' ADD COLUMN merchant_sig BYTEA CHECK(LENGTH(merchant_sig)=64)' ' DEFAULT NULL' - ';' + ';', + 'batch_deposits' + ,'' + ,partition_suffix ); PERFORM comment_partitioned_column( - 'signature by the merchant over the contract terms' - ,'batch_deposits' + 'signature by the merchant over the contract terms, of purpuse TALER_SIGNATURE_MERCHANT_CONTRACT' ,'merchant_sig' - ,NULL + ,'batch_deposits' + ,partition_suffix ); END $$; diff --git a/src/exchangedb/exchange-0007.sql.in b/src/exchangedb/exchange-0007.sql.in index 6d634e22c..9a03e2fa1 100644 --- a/src/exchangedb/exchange-0007.sql.in +++ b/src/exchangedb/exchange-0007.sql.in @@ -21,6 +21,7 @@ SET search_path TO exchange; #include "0007-wire_targets.sql" #include "0007-legitimization_outcomes.sql" +#include "0007-batch_deposits.sql" COMMIT; diff --git a/src/exchangedb/exchange_do_deposit.sql b/src/exchangedb/exchange_do_deposit.sql index ef1d94919..8ada2c497 100644 --- a/src/exchangedb/exchange_do_deposit.sql +++ b/src/exchangedb/exchange_do_deposit.sql @@ -19,6 +19,7 @@ CREATE FUNCTION exchange_do_deposit( -- For batch_deposits IN in_shard INT8, IN in_merchant_pub BYTEA, + IN in_merchant_sig BYTEA, IN in_wallet_timestamp INT8, IN in_exchange_timestamp INT8, IN in_refund_deadline INT8, @@ -88,6 +89,7 @@ END IF; INSERT INTO batch_deposits (shard ,merchant_pub + ,merchant_sig ,wallet_timestamp ,exchange_timestamp ,refund_deadline @@ -102,6 +104,7 @@ INSERT INTO batch_deposits VALUES (in_shard ,in_merchant_pub + ,in_merchant_sig ,in_wallet_timestamp ,in_exchange_timestamp ,in_refund_deadline diff --git a/src/exchangedb/pg_do_deposit.c b/src/exchangedb/pg_do_deposit.c index ed689696a..da8ddf793 100644 --- a/src/exchangedb/pg_do_deposit.c +++ b/src/exchangedb/pg_do_deposit.c @@ -46,6 +46,9 @@ TEH_PG_do_deposit ( /* data for batch_deposits */ GNUNET_PQ_query_param_uint64 (&deposit_shard), GNUNET_PQ_query_param_auto_from_type (&bd->merchant_pub), + GNUNET_is_zero (&bd->merchant_sig) + ? GNUNET_PQ_query_param_null () + : GNUNET_PQ_query_param_auto_from_type (&bd->merchant_sig), GNUNET_PQ_query_param_timestamp (&bd->wallet_timestamp), GNUNET_PQ_query_param_timestamp (exchange_timestamp), GNUNET_PQ_query_param_timestamp (&bd->refund_deadline), @@ -113,7 +116,8 @@ TEH_PG_do_deposit ( ",out_insufficient_balance_coin_index AS insufficient_balance_coin_index" ",out_conflict AS conflicted" " FROM exchange_do_deposit" - " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17);"); + " ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18);") + ; qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "call_deposit", params, diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h index 6edc15d5c..52dbb75d1 100644 --- a/src/include/taler_crypto_lib.h +++ b/src/include/taler_crypto_lib.h @@ -5995,14 +5995,29 @@ TALER_merchant_pay_verify ( * Sign contract sent by the merchant to the wallet. * * @param h_contract_terms hash of the contract terms - * @param merch_priv private key to sign with - * @param[out] merch_sig where to write the signature + * @param merchant_priv private key to sign with + * @param[out] merchant_sig where to write the signature */ void TALER_merchant_contract_sign ( const struct TALER_PrivateContractHashP *h_contract_terms, - const struct TALER_MerchantPrivateKeyP *merch_priv, - struct GNUNET_CRYPTO_EddsaSignature *merch_sig); + const struct TALER_MerchantPrivateKeyP *merchant_priv, + struct TALER_MerchantSignatureP *merchant_sig); + + +/** + * Verify contract signature sent by the merchant to the wallet. + * + * @param h_contract_terms hash of the contract terms + * @param merchant_pub public key of the merchant + * @param merchant_sig signature to check + * @return #GNUNET_OK if the signature is valid + */ +enum GNUNET_GenericReturnValue +TALER_merchant_contract_verify ( + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_MerchantPublicKeyP *merchant_pub, + struct TALER_MerchantSignatureP *merchant_sig); /* **************** /management/extensions offline signing **************** */ diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index f2b62c9d6..c561e0e8f 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -1245,6 +1245,12 @@ struct TALER_EXCHANGE_DepositContractDetail */ struct TALER_MerchantPublicKeyP merchant_pub; + /** + * The signature of the merchant (used to show that the merchant indeed + * agree to the deposit). + */ + struct TALER_MerchantSignatureP merchant_sig; + /** * Salt used to hash the @e merchant_payto_uri. */ diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index c633675d8..66e0c4587 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -1779,6 +1779,12 @@ struct TALER_EXCHANGEDB_BatchDeposit */ struct TALER_MerchantPublicKeyP merchant_pub; + /** + * Signature of the merchant over the contract, of purpose + * #TALER_SIGNATURE_MERCHANT_CONTRACT. + */ + struct TALER_MerchantSignatureP merchant_sig; + /** * Hash over the proposal data between merchant and customer * (remains unknown to the Exchange). diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 88d00765f..cd7e5aed5 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -18,7 +18,7 @@ lib_LTLIBRARIES = \ libtalerexchange.la libtalerexchange_la_LDFLAGS = \ - -version-info 12:0:0 \ + -version-info 13:0:0 \ -no-undefined libtalerexchange_la_SOURCES = \ exchange_api_add_aml_decision.c \ diff --git a/src/lib/exchange_api_batch_deposit.c b/src/lib/exchange_api_batch_deposit.c index 26f00c7a7..23bef742f 100644 --- a/src/lib/exchange_api_batch_deposit.c +++ b/src/lib/exchange_api_batch_deposit.c @@ -668,6 +668,10 @@ TALER_EXCHANGE_batch_deposit ( json_decref (deposits); return NULL; } + if (! GNUNET_is_zero (&dcd->merchant_sig)) + { + /* FIXME #9185: check merchant_sig!? */ + } if (GNUNET_is_zero (&cdd->h_age_commitment)) h_age_commitmentp = NULL; else @@ -730,6 +734,8 @@ TALER_EXCHANGE_batch_deposit ( dcd->wallet_timestamp), GNUNET_JSON_pack_data_auto ("merchant_pub", &dcd->merchant_pub), + GNUNET_JSON_pack_data_auto ("merchant_sig", + &dcd->merchant_sig), GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_timestamp ("refund_deadline", dcd->refund_deadline)), diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c index 9acb7c2b0..acb40151e 100644 --- a/src/lib/exchange_api_handle.c +++ b/src/lib/exchange_api_handle.c @@ -40,12 +40,12 @@ * Which version of the Taler protocol is implemented * by this library? Used to determine compatibility. */ -#define EXCHANGE_PROTOCOL_CURRENT 21 +#define EXCHANGE_PROTOCOL_CURRENT 22 /** * How many versions are we backwards compatible with? */ -#define EXCHANGE_PROTOCOL_AGE 4 +#define EXCHANGE_PROTOCOL_AGE 5 /** * Set to 1 for extra debug logging. diff --git a/src/util/merchant_signatures.c b/src/util/merchant_signatures.c index 56d93ab87..32948578b 100644 --- a/src/util/merchant_signatures.c +++ b/src/util/merchant_signatures.c @@ -95,11 +95,11 @@ TALER_merchant_deposit_verify ( .h_wire = *h_wire }; - return - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION, - &tps, - &merchant_sig->eddsa_sig, - &merchant->eddsa_pub); + return GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION, + &tps, + &merchant_sig->eddsa_sig, + &merchant->eddsa_pub); } @@ -183,11 +183,11 @@ TALER_merchant_refund_verify ( TALER_amount_hton (&rr.refund_amount, amount); - return - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND, - &rr, - &merchant_sig->eddsa_sig, - &merchant_pub->eddsa_pub); + return GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_MERCHANT_REFUND, + &rr, + &merchant_sig->eddsa_sig, + &merchant_pub->eddsa_pub); } @@ -303,11 +303,11 @@ TALER_merchant_pay_verify ( .h_contract_terms = *h_contract_terms }; - return - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_PAYMENT_OK, - &pr, - &merchant_sig->eddsa_sig, - &merchant_pub->eddsa_pub); + return GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_MERCHANT_PAYMENT_OK, + &pr, + &merchant_sig->eddsa_sig, + &merchant_pub->eddsa_pub); } @@ -329,11 +329,12 @@ struct TALER_ProposalDataPS struct TALER_PrivateContractHashP hash; }; + void TALER_merchant_contract_sign ( const struct TALER_PrivateContractHashP *h_contract_terms, - const struct TALER_MerchantPrivateKeyP *merch_priv, - struct GNUNET_CRYPTO_EddsaSignature *merch_sig) + const struct TALER_MerchantPrivateKeyP *merchant_priv, + struct TALER_MerchantSignatureP *merchant_sig) { struct TALER_ProposalDataPS pdps = { .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT), @@ -341,9 +342,29 @@ TALER_merchant_contract_sign ( .hash = *h_contract_terms }; - GNUNET_CRYPTO_eddsa_sign (&merch_priv->eddsa_priv, + GNUNET_CRYPTO_eddsa_sign (&merchant_priv->eddsa_priv, &pdps, - merch_sig); + &merchant_sig->eddsa_sig); +} + + +enum GNUNET_GenericReturnValue +TALER_merchant_contract_verify ( + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_MerchantPublicKeyP *merchant_pub, + struct TALER_MerchantSignatureP *merchant_sig) +{ + struct TALER_ProposalDataPS pdps = { + .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT), + .purpose.size = htonl (sizeof (pdps)), + .hash = *h_contract_terms + }; + + return GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_MERCHANT_CONTRACT, + &pdps, + &merchant_sig->eddsa_sig, + &merchant_pub->eddsa_pub); } -- cgit v1.2.3