merchant

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

commit 229d3a0aba2dd48000e46765037d87490078c549
parent ddbe83488339297e5c887c277ea2e28782cd5597
Author: Christian Grothoff <grothoff@gnunet.org>
Date:   Thu, 14 Aug 2025 11:11:43 +0200

fix output token signing offset computations

Diffstat:
Msrc/backend/taler-merchant-httpd_post-orders-ID-pay.c | 58++++++++++++++++++++++++++++++++++++++++------------------
1 file changed, 40 insertions(+), 18 deletions(-)

diff --git a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c @@ -3087,12 +3087,13 @@ test_tfk_mandatory (enum TALER_MERCHANTDB_TokenFamilyKind tfk) * #GNUNET_OK on success */ static enum GNUNET_GenericReturnValue -sign_token_envelopes (struct PayContext *pc, - struct TALER_MERCHANT_ContractTokenFamilyKey *key, - struct TALER_TokenIssuePrivateKey *priv, - bool mandatory, - unsigned int index, - unsigned int expected_num) +sign_token_envelopes ( + struct PayContext *pc, + const struct TALER_MERCHANT_ContractTokenFamilyKey *key, + const struct TALER_TokenIssuePrivateKey *priv, + bool mandatory, + unsigned int index, + unsigned int expected_num) { unsigned int num_signed = 0; @@ -3128,11 +3129,13 @@ sign_token_envelopes (struct PayContext *pc, TALER_token_issue_sign (priv, &env->blinded_token, &output->sig); - output->h_issue.hash = key->pub.public_key->pub_key_hash; + output->h_issue.hash + = key->pub.public_key->pub_key_hash; num_signed++; } - if (num_signed != expected_num) + if (mandatory && + (num_signed != expected_num) ) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Expected %d token envelopes for public key with valid_after " @@ -3208,8 +3211,9 @@ handle_output_token (struct PayContext *pc, enum GNUNET_DB_QueryStatus qs; bool mandatory; - /* Locate token family in the contract. This should never fail if - * the contract passed validation before insertion. */ + /* Locate token family in the contract. + This should ever fail as this invariant should + have been checked when the contract was created. */ family = find_family (pc, output->details.token.token_family_slug); if (NULL == family) @@ -3444,6 +3448,9 @@ phase_validate_tokens (struct PayContext *pc) const struct TALER_MERCHANT_ContractChoice *selected = &pc->check_contract.contract_terms->details.v1.choices[ pc->parse_wallet_data.choice_index]; + unsigned int output_off; + unsigned int cnt; + bool donau_seen = false; pc->validate_tokens.max_fee = selected->max_fee; pc->validate_tokens.brutto = selected->amount; @@ -3505,6 +3512,7 @@ phase_validate_tokens (struct PayContext *pc) } /* calculate pc->output_tokens_len */ + output_off = 0; for (unsigned int i = 0; i<selected->outputs_len; i++) { const struct TALER_MERCHANT_ContractOutput *output @@ -3516,25 +3524,34 @@ phase_validate_tokens (struct PayContext *pc) GNUNET_assert (0); break; case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN: + cnt = output->details.token.count; // FIXME: replace assert by returning 400 - GNUNET_assert (pc->output_tokens_len + output->details.token.count - >= pc->output_tokens_len); - pc->output_tokens_len += output->details.token.count; + GNUNET_assert (output_off + cnt + >= output_off); + output_off += cnt; break; case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT: + /* check that this output type appears at most once */ + if (donau_seen) + { + // FIXME: return 400, duplicate donau + } + donau_seen = true; // FIXME: replace assert by returning 400 - // FIXME: also check that this output type only appears ONCE - GNUNET_assert (pc->output_tokens_len + pc->parse_wallet_data.num_bkps - >= pc->output_tokens_len); - pc->output_tokens_len += pc->parse_wallet_data.num_bkps; + GNUNET_assert (output_off + pc->parse_wallet_data.num_bkps + >= output_off); + output_off += pc->parse_wallet_data.num_bkps; break; } } + pc->output_tokens_len = output_off; pc->output_tokens = GNUNET_new_array (pc->output_tokens_len, struct SignedOutputToken); + /* compute non-donau outputs */ + output_off = 0; for (unsigned int i = 0; i<selected->outputs_len; i++) { const struct TALER_MERCHANT_ContractOutput *output @@ -3546,14 +3563,18 @@ phase_validate_tokens (struct PayContext *pc) GNUNET_assert (0); break; case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN: + cnt = output->details.token.count; + GNUNET_assert (output_off + cnt + <= pc->output_tokens_len); if (GNUNET_OK != handle_output_token (pc, output, - i)) + output_off)) { /* Error is already scheduled from handle_output_token. */ return; } + output_off += cnt; break; case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT: #ifndef HAVE_DONAU_DONAU_SERVICE_H @@ -3575,6 +3596,7 @@ phase_validate_tokens (struct PayContext *pc) /* Error is already scheduled from handle_output_donation_receipt. */ return; } + output_off += pc->parse_wallet_data.num_bkps; continue; #endif } /* switch on output token */