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:
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 */