exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

commit 3340ddb38d5af7573f2715f39d847a80c052dea8
parent d4f372748e094177d1b6a36cf685ada5afb066b6
Author: Christian Grothoff <christian@grothoff.org>
Date:   Tue,  7 Apr 2026 20:45:34 +0200

fix issue where merchant backend with wrong public key would get access token (ugh) and KYC OK if account was previously involved in reserve_in; breaks kyc-fail-recover-simple

Diffstat:
Msrc/exchange/taler-exchange-httpd_common_kyc.c | 5+++--
Msrc/exchange/taler-exchange-httpd_get-kyc-check-H_NORMALIZED_PAYTO.c | 29++++++++---------------------
Msrc/exchangedb/exchange_do_lookup_kyc_requirement_by_row.sql | 31+++++--------------------------
Msrc/exchangedb/pg_lookup_kyc_requirement_by_row.c | 27+++------------------------
Msrc/exchangedb/pg_lookup_kyc_requirement_by_row.h | 14+++-----------
Msrc/include/taler/taler_exchangedb_plugin.h | 14+++-----------
6 files changed, 25 insertions(+), 95 deletions(-)

diff --git a/src/exchange/taler-exchange-httpd_common_kyc.c b/src/exchange/taler-exchange-httpd_common_kyc.c @@ -1609,11 +1609,12 @@ legitimization_check_run ( break; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "get_kyc_rules returned %d/%d/%d/%d\n", + "get_kyc_rules returned %d/%d/%d/%d(%d)\n", (int) qs, ! no_account_pub, ! no_reserve_pub, - NULL != jrules); + NULL != jrules, + (int) lch->have_merchant_pub); lch->lcr.kyc.have_account_pub = ! no_account_pub; diff --git a/src/exchange/taler-exchange-httpd_get-kyc-check-H_NORMALIZED_PAYTO.c b/src/exchange/taler-exchange-httpd_get-kyc-check-H_NORMALIZED_PAYTO.c @@ -83,7 +83,7 @@ struct KycPoller /** * Public key from the account owner authorizing this - * operation. Optional, see @e have_pub. + * operation. */ union TALER_AccountPublicKeyP account_pub; @@ -103,11 +103,6 @@ struct KycPoller */ bool suspended; - /** - * True if we have an @e account_pub. - */ - bool have_pub; - }; @@ -218,7 +213,6 @@ TEH_handler_kyc_check ( struct KycPoller *kyp = rc->rh_ctx; json_t *jrules = NULL; json_t *jlimits = NULL; - union TALER_AccountPublicKeyP reserve_pub; struct TALER_AccountAccessTokenP access_token; bool aml_review; bool kyc_required; @@ -229,6 +223,7 @@ TEH_handler_kyc_check ( if (NULL == kyp) { bool sig_required = true; + bool acc_required = true; kyp = GNUNET_new (struct KycPoller); kyp->connection = rc->connection; @@ -261,7 +256,7 @@ TEH_handler_kyc_check ( rc->connection, TALER_HTTP_HEADER_ACCOUNT_OWNER_PUBKEY, &kyp->account_pub, - kyp->have_pub); + acc_required); TALER_MHD_parse_request_timeout (rc->connection, &kyp->timeout); { @@ -327,16 +322,13 @@ TEH_handler_kyc_check ( bool do_suspend; GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Looking up KYC requirements for account %s (%s)\n", - TALER_B2S (&kyp->h_payto), - kyp->have_pub ? "with account-pub" : "legacy wallet"); + "Looking up KYC requirements for account %s\n", + TALER_B2S (&kyp->h_payto)); qs = TEH_plugin->lookup_kyc_requirement_by_row ( TEH_plugin->cls, &kyp->h_payto, - kyp->have_pub, &kyp->account_pub, &is_wallet, - &reserve_pub.reserve_pub, &access_token, &rule_gen, &jrules, @@ -375,14 +367,9 @@ TEH_handler_kyc_check ( (unsigned long long) kyp->min_rule, (int) kyp->lpt); access_ok = - ( (! GNUNET_is_zero (&kyp->account_pub) && - (GNUNET_OK == - TALER_account_kyc_auth_verify (&kyp->account_pub, - &kyp->account_sig)) ) || - (! GNUNET_is_zero (&reserve_pub) && - (GNUNET_OK == - TALER_account_kyc_auth_verify (&reserve_pub, - &kyp->account_sig)) ) ); + (GNUNET_OK == + TALER_account_kyc_auth_verify (&kyp->account_pub, + &kyp->account_sig)); if (GNUNET_TIME_absolute_is_future (kyp->timeout) && (rule_gen <= kyp->min_rule) ) { diff --git a/src/exchangedb/exchange_do_lookup_kyc_requirement_by_row.sql b/src/exchangedb/exchange_do_lookup_kyc_requirement_by_row.sql @@ -19,9 +19,7 @@ DROP FUNCTION IF EXISTS exchange_do_lookup_kyc_requirement_by_row; CREATE FUNCTION exchange_do_lookup_kyc_requirement_by_row( IN in_h_normalized_payto BYTEA, - IN in_account_pub BYTEA, -- NULL allowed - OUT out_account_pub BYTEA, -- NULL allowed - OUT out_reserve_pub BYTEA, -- NULL allowed + IN in_account_pub BYTEA, OUT out_access_token BYTEA, -- NULL if 'out_not_found' OUT out_jrules JSONB, -- NULL allowed OUT out_is_wallet BOOLEAN, -- NULL allowed @@ -57,11 +55,9 @@ THEN END IF; -- It is definitively OK if we were given a public key AND it matches -my_ok = (in_account_pub IS NOT NULL) AND - (my_wtrec.target_pub = in_account_pub); +my_ok = (my_wtrec.target_pub = in_account_pub); -IF ( (NOT my_ok) AND - (in_account_pub IS NOT NULL) ) +IF (NOT my_ok) THEN -- We were given an in_account_pub, but it did not match the -- target pub. @@ -92,11 +88,9 @@ THEN END IF; END IF; -IF (NOT my_ok AND - ( (in_account_pub IS NOT NULL) OR - (my_wtrec.target_pub IS NULL) ) ) +IF (NOT my_ok) THEN - -- RAISE WARNING 'No match and target_pub is NOT NULL'; + -- RAISE WARNING 'No match'; -- We failed to find a matching public key for in_account_pub, and -- either the client provided a specific one to match OR -- we could not return any one that could even work, which means @@ -112,7 +106,6 @@ END IF; out_not_found = FALSE; out_is_wallet = my_wtrec.is_wallet; -out_account_pub = my_wtrec.target_pub; out_access_token = my_wtrec.access_token; -- Check if there are active measures for the account. @@ -141,18 +134,4 @@ THEN out_rule_gen=my_lorec.outcome_serial_id; END IF; --- Check most recent reserve_in wire transfer, we also --- allow that reserve public key for authentication! --- Only needed for old wallets that don't pass --- in the account pub explicitly. -SELECT reserve_pub - INTO out_reserve_pub - FROM reserves_in - WHERE wire_source_h_payto - IN (SELECT wt.wire_target_h_payto - FROM wire_targets wt - WHERE h_normalized_payto=in_h_normalized_payto) - ORDER BY execution_date DESC, reserve_in_serial_id DESC - LIMIT 1; - END $$; diff --git a/src/exchangedb/pg_lookup_kyc_requirement_by_row.c b/src/exchangedb/pg_lookup_kyc_requirement_by_row.c @@ -30,10 +30,8 @@ enum GNUNET_DB_QueryStatus TEH_PG_lookup_kyc_requirement_by_row ( void *cls, const struct TALER_NormalizedPaytoHashP *h_payto, - bool have_pub, - union TALER_AccountPublicKeyP *account_pub, + const union TALER_AccountPublicKeyP *account_pub, enum GNUNET_GenericReturnValue *is_wallet, - struct TALER_ReservePublicKeyP *reserve_pub, struct TALER_AccountAccessTokenP *access_token, uint64_t *rule_gen, json_t **jrules, @@ -43,9 +41,7 @@ TEH_PG_lookup_kyc_requirement_by_row ( struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (h_payto), - have_pub - ? GNUNET_PQ_query_param_auto_from_type (account_pub) - : GNUNET_PQ_query_param_null (), + GNUNET_PQ_query_param_auto_from_type (account_pub), GNUNET_PQ_query_param_end }; bool bis_wallet; @@ -53,14 +49,6 @@ TEH_PG_lookup_kyc_requirement_by_row ( bool not_found; struct GNUNET_PQ_ResultSpec rs[] = { GNUNET_PQ_result_spec_allow_null ( - GNUNET_PQ_result_spec_auto_from_type ("account_pub", - account_pub), - NULL), - GNUNET_PQ_result_spec_allow_null ( - GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", - reserve_pub), - NULL), - GNUNET_PQ_result_spec_allow_null ( GNUNET_PQ_result_spec_auto_from_type ("access_token", access_token), NULL), @@ -95,22 +83,13 @@ TEH_PG_lookup_kyc_requirement_by_row ( *aml_review = false; *is_wallet = GNUNET_SYSERR; *rule_gen = 0; - if (! have_pub) - memset (account_pub, - 0, - sizeof (*account_pub)); - memset (reserve_pub, - 0, - sizeof (*reserve_pub)); memset (access_token, 0, sizeof (*access_token)); PREPARE (pg, "lookup_kyc_requirement_by_row", "SELECT " - " out_account_pub AS account_pub" - ",out_reserve_pub AS reserve_pub" - ",out_access_token AS access_token" + " out_access_token AS access_token" ",out_jrules::TEXT AS jrules" ",out_is_wallet AS is_wallet" ",out_not_found AS not_found" diff --git a/src/exchangedb/pg_lookup_kyc_requirement_by_row.h b/src/exchangedb/pg_lookup_kyc_requirement_by_row.h @@ -31,16 +31,10 @@ * * @param cls closure * @param h_payto identifies account to look up requirement for - * @param have_pub true if @a account_pub is provided as an input, - * false if it is merely provided for the public key to be returned - * @param[out] account_pub set to public key of the account - * needed to authorize access, all zeros if not known + * @param account_pub set to public key of the account + * needed to authorize access * @param[out] is_wallet set to #GNUNET_YES if the account is * that of a wallet (#GNUNET_SYSERR is used if unknown) - * @param[out] reserve_pub set to last reserve public key - * used for a wire transfer from the account to the - * exchange; alternatively used to authorize access, - * all zeros if not known * @param[out] access_token set to the access token to begin * work on KYC processes for this account * @param[out] rule_gen row ID of the last decision this @@ -57,10 +51,8 @@ enum GNUNET_DB_QueryStatus TEH_PG_lookup_kyc_requirement_by_row ( void *cls, const struct TALER_NormalizedPaytoHashP *h_payto, - bool have_pub, - union TALER_AccountPublicKeyP *account_pub, + const union TALER_AccountPublicKeyP *account_pub, enum GNUNET_GenericReturnValue *is_wallet, - struct TALER_ReservePublicKeyP *reserve_pub, struct TALER_AccountAccessTokenP *access_token, uint64_t *rule_gen, json_t **jrules, diff --git a/src/include/taler/taler_exchangedb_plugin.h b/src/include/taler/taler_exchangedb_plugin.h @@ -7243,16 +7243,10 @@ struct TALER_EXCHANGEDB_Plugin * * @param cls closure * @param h_payto identifies account to look up requirement for - * @param have_pub true if @a account_pub is provided as an input, - * false if it is merely provided for the public key to be returned - * @param[in,out] account_pub set to public key of the account - * needed to authorize access, all zeros if not known + * @param account_pub set to public key of the account + * needed to authorize access * @param[out] is_wallet set to #GNUNET_YES if the account is * that of a wallet (#GNUNET_SYSERR is used if unknown) - * @param[out] reserve_pub set to last reserve public key - * used for a wire transfer from the account to the - * exchange; alternatively used to authorize access, - * all zeros if not known * @param[out] access_token set to the access token to begin * work on KYC processes for this account * @param[out] rule_gen row ID of the last decision this @@ -7269,10 +7263,8 @@ struct TALER_EXCHANGEDB_Plugin (*lookup_kyc_requirement_by_row)( void *cls, const struct TALER_NormalizedPaytoHashP *h_payto, - bool have_pub, - union TALER_AccountPublicKeyP *account_pub, + const union TALER_AccountPublicKeyP *account_pub, enum GNUNET_GenericReturnValue *is_wallet, - struct TALER_ReservePublicKeyP *reserve_pub, struct TALER_AccountAccessTokenP *access_token, uint64_t *rule_gen, json_t **jrules,