merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

commit 3c76780d16abacb829d29b4d8ea882852218789d
parent 84bd5a2f569516ed9c8617b25da17cac7adeac44
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sun,  2 Aug 2026 21:07:48 +0200

prevent OOB on trait tokens (testing library)

Diffstat:
Msrc/backend/taler-merchant-httpd_mfa.c | 20++++++++++++++++++++
Msrc/testing/testing_api_cmd_pay_order.c | 30++++++++++++------------------
2 files changed, 32 insertions(+), 18 deletions(-)

diff --git a/src/backend/taler-merchant-httpd_mfa.c b/src/backend/taler-merchant-httpd_mfa.c @@ -189,6 +189,26 @@ mfa_challenge_check ( case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: break; } + + /* The MFA challenge table (merchant.tan_challenges) is global across + instances and challenge IDs are only unique globally. Ensure the + challenge actually belongs to the instance handling this request; + otherwise one instance could satisfy its MFA requirement using + another instance's challenge. (Defense-in-depth: challenge_id and + the body hash already bind the challenge to a specific request.) */ + if ( (NULL != hc->instance) && + (NULL != hc->instance->settings.id) && + ( (NULL == instance_id) || + (0 != strcmp (instance_id, + hc->instance->settings.id)) ) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Challenge %s is for a different instance!\n", + challenge_id); + GNUNET_free (instance_id); + *solved = false; + return GNUNET_OK; + } GNUNET_free (instance_id); if (xop != op) diff --git a/src/testing/testing_api_cmd_pay_order.c b/src/testing/testing_api_cmd_pay_order.c @@ -1508,19 +1508,11 @@ pay_traits (void *cls, const char *trait, unsigned int index) { - struct PayState *ps = cls; const char *order_id; const struct TALER_TESTING_Command *proposal_cmd; const struct TALER_MerchantPublicKeyP *merchant_pub; - if (NULL != ps->token_reference && - index >= ps->num_issued_tokens) - { - GNUNET_break (0); - return GNUNET_NO; - } - if (NULL == (proposal_cmd = TALER_TESTING_interpreter_lookup_command (ps->is, @@ -1551,6 +1543,16 @@ pay_traits (void *cls, &ps->amount_with_fee_parsed)); { struct TALER_TESTING_Trait traits[] = { + /* these must be first, see 'off' below */ + TALER_TESTING_make_trait_token_priv ( + index, + &ps->issued_tokens[index].token_priv), + TALER_TESTING_make_trait_token_issue_pub ( + index, + &ps->issued_tokens[index].issue_pub), + TALER_TESTING_make_trait_token_issue_sig ( + index, + &ps->issued_tokens[index].issue_sig), TALER_TESTING_make_trait_proposal_reference (ps->proposal_reference), TALER_TESTING_make_trait_coin_reference (0, ps->coin_reference), @@ -1560,19 +1562,11 @@ pay_traits (void *cls, TALER_TESTING_make_trait_amount (&ps->amount_with_fee_parsed), TALER_TESTING_make_trait_otp_key (ps->pos_key), TALER_TESTING_make_trait_otp_alg (&ps->pos_alg), - TALER_TESTING_make_trait_token_priv (index, - &ps->issued_tokens[index]. - token_priv), - TALER_TESTING_make_trait_token_issue_pub (index, - &ps->issued_tokens[index]. - issue_pub), - TALER_TESTING_make_trait_token_issue_sig (index, - &ps->issued_tokens[index]. - issue_sig), TALER_TESTING_trait_end () }; + unsigned int off = (index >= ps->num_issued_tokens) ? 3 : 0; - return TALER_TESTING_get_trait (traits, + return TALER_TESTING_get_trait (&traits[off], ret, trait, index);