diff options
author | Özgür Kesim <oec-taler@kesim.org> | 2022-06-29 14:40:15 +0200 |
---|---|---|
committer | Özgür Kesim <oec-taler@kesim.org> | 2022-06-29 14:43:16 +0200 |
commit | 72695e8e41bb75b44d3d09ad5316eb9d48ac25d7 (patch) | |
tree | db2ad0db48d12408a48d4cadfb0772deea896a6e /src | |
parent | e3690a9eb44d5feb0a44dc995612a601aa95aacd (diff) |
Handle age restricted coin when minimum age was not required
When a customer pays with a coin that is age restricted while the
contract did not ask for a minimum age, it is required that the customer
provides 'h_age_commitment', the hash of the age commitment that went
into the FDH of the coin. This is needed for the deposit of the age
restricted coin.
Fixes #7252
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/taler-merchant-httpd_post-orders-ID-pay.c | 73 |
1 files changed, 44 insertions, 29 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 index 2e78c10d..43b68ff4 100644 --- a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c +++ b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c @@ -1131,7 +1131,7 @@ process_pay_with_exchange ( const struct TALER_EXCHANGE_DenomPublicKey *denom_details; enum TALER_ErrorCode ec; unsigned int http_status; - bool age_verification_required = false; + bool is_age_restricted_denom = false; struct TALER_AgeCommitmentHash ach = {0}; struct TALER_AgeCommitmentHash *achp = NULL; @@ -1176,6 +1176,7 @@ process_pay_with_exchange ( (json_t *) TALER_EXCHANGE_get_keys_raw (exchange_handle))))); return; } + if (GNUNET_OK != TMH_AUDITORS_check_dk (exchange_handle, denom_details, @@ -1210,15 +1211,18 @@ process_pay_with_exchange ( /* Now that we have the details about the denomination, we can verify age * restriction requirements, if applicable. Note that denominations with an * age_mask equal to zero always pass the age verification. */ - age_verification_required = 0 < pc->minimum_age && - 0 < denom_details->key.age_mask.bits; + is_age_restricted_denom = 0 < denom_details->key.age_mask.bits; - if (age_verification_required) + if (is_age_restricted_denom + && (0 < pc->minimum_age)) { + /* Minimum age given and restricted coind provided: We need to verify the + * minimum age */ unsigned int code = 0; if (dc->no_age_commitment) { + GNUNET_break_op (0); code = TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_COMMITMENT_MISSING; goto AGE_FAIL; } @@ -1227,6 +1231,7 @@ process_pay_with_exchange ( if ((dc->age_commitment.num + 1) != __builtin_popcount (dc->age_commitment.mask.bits)) { + GNUNET_break_op (0); code = TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_COMMITMENT_SIZE_MISMATCH; goto AGE_FAIL; @@ -1242,6 +1247,7 @@ process_pay_with_exchange ( AGE_FAIL: if (0 < code) { + GNUNET_free (dc->age_commitment.keys); resume_pay_with_response ( pc, MHD_HTTP_BAD_REQUEST, @@ -1256,9 +1262,31 @@ AGE_FAIL: * Calculate the hash of the age commitment. */ TALER_age_commitment_hash (&dc->age_commitment, &ach); - + GNUNET_free (dc->age_commitment.keys); achp = &ach; } + else if (is_age_restricted_denom) + { + /* The contract did not ask for a minimum_age but the client paid + * with a coin that has age restriction enabled. We need the hash + * of the age commitment in this case in order to verify the coin + * and to deposit it with the exchange. */ + if (dc->no_h_age_commitment) + { + GNUNET_break_op (0); + resume_pay_with_response ( + pc, + MHD_HTTP_BAD_REQUEST, + TALER_MHD_MAKE_JSON_PACK ( + TALER_JSON_pack_ec ( + TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_COMMITMENT_HASH_MISSING), + GNUNET_JSON_pack_data_auto ("h_denom_pub", + &denom_details->h_key))); + return; + } + + achp = &dc->h_age_commitment; + } dc->deposit_fee = denom_details->fees.deposit; dc->refund_fee = denom_details->fees.refund; @@ -2066,7 +2094,6 @@ parse_pay (struct PayContext *pc) { struct DepositConfirmation *dc = &pc->dc[coins_index]; const char *exchange_url; - bool no_minimum_age_sig; struct GNUNET_JSON_Specification ispec[] = { GNUNET_JSON_spec_fixed_auto ("coin_sig", &dc->coin_sig), @@ -2086,7 +2113,7 @@ parse_pay (struct PayContext *pc) GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_fixed_auto ("minimum_age_sig", &dc->minimum_age_sig), - &no_minimum_age_sig), + &dc->no_minimum_age_sig), GNUNET_JSON_spec_mark_optional ( TALER_JSON_spec_age_commitment ("age_commitment", &dc->age_commitment), @@ -2149,32 +2176,20 @@ parse_pay (struct PayContext *pc) // Check the consistency of the (potential) age restriction // information. + if (dc->no_age_commitment != dc->no_minimum_age_sig) { - char *error = NULL; - - if (0 < dc->pc->minimum_age && - dc->no_minimum_age_sig && - dc->no_age_commitment) - error = "required: 'mininum_age_sig' and 'age_commitment'"; - - if (! dc->no_age_commitment && - dc->no_h_age_commitment) - error = "only one allowed: 'age_commitment' vs. 'h_age_commitment'"; - - if (NULL != error) - { - GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); - return (MHD_YES == - TALER_MHD_reply_with_error ( - pc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - error) + GNUNET_break_op (0); + GNUNET_JSON_parse_free (spec); + return (MHD_YES == + TALER_MHD_reply_with_error ( + pc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "inconsistent: 'age_commitment' vs. 'minimum_age_sig'" ) + ) ? GNUNET_NO : GNUNET_SYSERR; - } } } } |