diff options
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/Makefile.am | 1 | ||||
| -rw-r--r-- | src/lib/exchange_api_batch_deposit.c | 647 | ||||
| -rw-r--r-- | src/lib/exchange_api_common.c | 62 | ||||
| -rw-r--r-- | src/lib/exchange_api_common.h | 20 | ||||
| -rw-r--r-- | src/lib/exchange_api_deposit.c | 81 | ||||
| -rw-r--r-- | src/lib/exchange_api_handle.c | 2 | ||||
| -rw-r--r-- | src/lib/exchange_api_purse_create_with_deposit.c | 4 | ||||
| -rw-r--r-- | src/lib/exchange_api_purse_create_with_merge.c | 4 | 
8 files changed, 740 insertions, 81 deletions
| diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 844ca52f..76157c43 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -22,6 +22,7 @@ libtalerexchange_la_LDFLAGS = \    -no-undefined  libtalerexchange_la_SOURCES = \    exchange_api_auditor_add_denomination.c \ +  exchange_api_batch_deposit.c \    exchange_api_batch_withdraw.c \    exchange_api_batch_withdraw2.c \    exchange_api_curl_defaults.c exchange_api_curl_defaults.h \ diff --git a/src/lib/exchange_api_batch_deposit.c b/src/lib/exchange_api_batch_deposit.c new file mode 100644 index 00000000..be77f682 --- /dev/null +++ b/src/lib/exchange_api_batch_deposit.c @@ -0,0 +1,647 @@ +/* +   This file is part of TALER +   Copyright (C) 2014-2022 Taler Systems SA + +   TALER is free software; you can redistribute it and/or modify it under the +   terms of the GNU General Public License as published by the Free Software +   Foundation; either version 3, or (at your option) any later version. + +   TALER is distributed in the hope that it will be useful, but WITHOUT ANY +   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +   A PARTICULAR PURPOSE.  See the GNU General Public License for more details. + +   You should have received a copy of the GNU General Public License along with +   TALER; see the file COPYING.  If not, see +   <http://www.gnu.org/licenses/> + */ +/** + * @file lib/exchange_api_batch_deposit.c + * @brief Implementation of the /batch-deposit request of the exchange's HTTP API + * @author Sree Harsha Totakura <sreeharsha@totakura.in> + * @author Christian Grothoff + */ +#include "platform.h" +#include <jansson.h> +#include <microhttpd.h> /* just for HTTP status codes */ +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_json_lib.h> +#include <gnunet/gnunet_curl_lib.h> +#include "taler_json_lib.h" +#include "taler_auditor_service.h" +#include "taler_exchange_service.h" +#include "exchange_api_common.h" +#include "exchange_api_handle.h" +#include "taler_signatures.h" +#include "exchange_api_curl_defaults.h" + + +/** + * 1:#AUDITOR_CHANCE is the probability that we report deposits + * to the auditor. + * + * 20==5% of going to auditor. This is possibly still too high, but set + * deliberately this high for testing + */ +#define AUDITOR_CHANCE 20 + +/** + * @brief A Deposit Handle + */ +struct TALER_EXCHANGE_BatchDepositHandle +{ + +  /** +   * The connection to exchange this request handle will use +   */ +  struct TALER_EXCHANGE_Handle *exchange; + +  /** +   * The url for this request. +   */ +  char *url; + +  /** +   * Context for #TEH_curl_easy_post(). Keeps the data that must +   * persist for Curl to make the upload. +   */ +  struct TALER_CURL_PostContext ctx; + +  /** +   * Handle for the request. +   */ +  struct GNUNET_CURL_Job *job; + +  /** +   * Function to call with the result. +   */ +  TALER_EXCHANGE_BatchDepositResultCallback cb; + +  /** +   * Closure for @a cb. +   */ +  void *cb_cls; + +  /** +   * Details about the contract. +   */ +  struct TALER_EXCHANGE_DepositContractDetail dcd; + +  /** +   * Array with details about the coins. +   */ +  struct TALER_EXCHANGE_CoinDepositDetail *cdds; + +  /** +   * Hash of the merchant's wire details. +   */ +  struct TALER_MerchantWireHashP h_wire; + +  /** +   * Hash over the extensions, or all zero. +   */ +  struct TALER_ExtensionContractHashP h_extensions; + +  /** +   * Time when this confirmation was generated / when the exchange received +   * the deposit request. +   */ +  struct GNUNET_TIME_Timestamp exchange_timestamp; + +  /** +   * Exchange signatures, set for #auditor_cb. +   */ +  struct TALER_ExchangeSignatureP *exchange_sigs; + +  /** +   * Exchange signing public key, set for #auditor_cb. +   */ +  struct TALER_ExchangePublicKeyP exchange_pub; + +  /** +   * Chance that we will inform the auditor about the deposit +   * is 1:n, where the value of this field is "n". +   */ +  unsigned int auditor_chance; + +  /** +   * Length of the @e cdds array. +   */ +  unsigned int num_cdds; + +}; + + +/** + * Function called for each auditor to give us a chance to possibly + * launch a deposit confirmation interaction. + * + * @param cls closure + * @param ah handle to the auditor + * @param auditor_pub public key of the auditor + * @return NULL if no deposit confirmation interaction was launched + */ +static struct TEAH_AuditorInteractionEntry * +auditor_cb (void *cls, +            struct TALER_AUDITOR_Handle *ah, +            const struct TALER_AuditorPublicKeyP *auditor_pub) +{ +  struct TALER_EXCHANGE_BatchDepositHandle *dh = cls; +  const struct TALER_EXCHANGE_Keys *key_state; +  const struct TALER_EXCHANGE_SigningPublicKey *spk; +  struct TEAH_AuditorInteractionEntry *aie; +  struct TALER_Amount amount_without_fee; +  const struct TALER_EXCHANGE_DenomPublicKey *dki; +  unsigned int coin; + +  if (0 != +      GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, +                                dh->auditor_chance)) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_INFO, +                "Not providing deposit confirmation to auditor\n"); +    return NULL; +  } +  coin = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, +                                   dh->num_cdds); +  GNUNET_log (GNUNET_ERROR_TYPE_INFO, +              "Will provide deposit confirmation to auditor `%s'\n", +              TALER_B2S (auditor_pub)); +  key_state = TALER_EXCHANGE_get_keys (dh->exchange); +  dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state, +                                                     &dh->cdds[coin].h_denom_pub); +  GNUNET_assert (NULL != dki); +  spk = TALER_EXCHANGE_get_signing_key_info (key_state, +                                             &dh->exchange_pub); +  if (NULL == spk) +  { +    GNUNET_break_op (0); +    return NULL; +  } +  GNUNET_assert (0 <= +                 TALER_amount_subtract (&amount_without_fee, +                                        &dh->cdds[coin].amount, +                                        &dki->fees.deposit)); +  aie = GNUNET_new (struct TEAH_AuditorInteractionEntry); +  aie->dch = TALER_AUDITOR_deposit_confirmation ( +    ah, +    &dh->h_wire, +    &dh->h_extensions, +    &dh->dcd.h_contract_terms, +    dh->exchange_timestamp, +    dh->dcd.wire_deadline, +    dh->dcd.refund_deadline, +    &amount_without_fee, +    &dh->cdds[coin].coin_pub, +    &dh->dcd.merchant_pub, +    &dh->exchange_pub, +    &dh->exchange_sigs[coin], +    &key_state->master_pub, +    spk->valid_from, +    spk->valid_until, +    spk->valid_legal, +    &spk->master_sig, +    &TEAH_acc_confirmation_cb, +    aie); +  return aie; +} + + +/** + * Function called when we're done processing the + * HTTP /deposit request. + * + * @param cls the `struct TALER_EXCHANGE_BatchDepositHandle` + * @param response_code HTTP response code, 0 on error + * @param response parsed JSON result, NULL on error + */ +static void +handle_deposit_finished (void *cls, +                         long response_code, +                         const void *response) +{ +  struct TALER_EXCHANGE_BatchDepositHandle *dh = cls; +  const json_t *j = response; +  struct TALER_EXCHANGE_BatchDepositResult dr = { +    .hr.reply = j, +    .hr.http_status = (unsigned int) response_code +  }; +  const struct TALER_EXCHANGE_Keys *keys; + +  dh->job = NULL; +  keys = TALER_EXCHANGE_get_keys (dh->exchange); +  switch (response_code) +  { +  case 0: +    dr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; +    break; +  case MHD_HTTP_OK: +    { +      const struct TALER_EXCHANGE_Keys *key_state; +      json_t *sigs; +      json_t *sig; +      unsigned int idx; +      struct GNUNET_JSON_Specification spec[] = { +        GNUNET_JSON_spec_json ("exchange_sigs", +                               &sigs), +        GNUNET_JSON_spec_fixed_auto ("exchange_pub", +                                     &dh->exchange_pub), +        GNUNET_JSON_spec_mark_optional ( +          GNUNET_JSON_spec_string ("transaction_base_url", +                                   &dr.details.success.transaction_base_url), +          NULL), +        GNUNET_JSON_spec_timestamp ("exchange_timestamp", +                                    &dh->exchange_timestamp), +        GNUNET_JSON_spec_end () +      }; + +      if (GNUNET_OK != +          GNUNET_JSON_parse (j, +                             spec, +                             NULL, NULL)) +      { +        GNUNET_break_op (0); +        dr.hr.http_status = 0; +        dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; +        break; +      } +      if (json_array_size (sigs) != dh->num_cdds) +      { +        GNUNET_break_op (0); +        dr.hr.http_status = 0; +        dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; +        break; +      } +      dh->exchange_sigs = GNUNET_new_array (dh->num_cdds, +                                            struct TALER_ExchangeSignatureP); +      key_state = TALER_EXCHANGE_get_keys (dh->exchange); +      if (GNUNET_OK != +          TALER_EXCHANGE_test_signing_key (key_state, +                                           &dh->exchange_pub)) +      { +        GNUNET_break_op (0); +        dr.hr.http_status = 0; +        dr.hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE; +        break; +      } +      json_array_foreach (sigs, idx, sig) +      { +        struct GNUNET_JSON_Specification ispec[] = { +          GNUNET_JSON_spec_fixed_auto ("exchange_sig", +                                       &dh->exchange_sigs[idx]), +          GNUNET_JSON_spec_end () +        }; +        struct TALER_Amount amount_without_fee; +        const struct TALER_EXCHANGE_DenomPublicKey *dki; + +        if (GNUNET_OK != +            GNUNET_JSON_parse (sig, +                               ispec, +                               NULL, NULL)) +        { +          GNUNET_break_op (0); +          dr.hr.http_status = 0; +          dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; +          GNUNET_JSON_parse_free (spec); +          break; +        } +        dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state, +                                                           &dh->cdds[idx]. +                                                           h_denom_pub); +        GNUNET_assert (NULL != dki); +        GNUNET_assert (0 <= +                       TALER_amount_subtract (&amount_without_fee, +                                              &dh->cdds[idx].amount, +                                              &dki->fees.deposit)); + +        if (GNUNET_OK != +            TALER_exchange_online_deposit_confirmation_verify ( +              &dh->dcd.h_contract_terms, +              &dh->h_wire, +              &dh->h_extensions, +              dh->exchange_timestamp, +              dh->dcd.wire_deadline, +              dh->dcd.refund_deadline, +              &amount_without_fee, +              &dh->cdds[idx].coin_pub, +              &dh->dcd.merchant_pub, +              &dh->exchange_pub, +              &dh->exchange_sigs[idx])) +        { +          GNUNET_break_op (0); +          dr.hr.http_status = 0; +          dr.hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE; +          break; +        } +      } +      TEAH_get_auditors_for_dc (dh->exchange, +                                &auditor_cb, +                                dh); +    } +    dr.details.success.exchange_sigs = dh->exchange_sigs; +    dr.details.success.exchange_pub = &dh->exchange_pub; +    dr.details.success.deposit_timestamp = dh->exchange_timestamp; +    dr.details.success.num_signatures = dh->num_cdds; +    break; +  case MHD_HTTP_BAD_REQUEST: +    /* This should never happen, either us or the exchange is buggy +       (or API version conflict); just pass JSON reply to the application */ +    dr.hr.ec = TALER_JSON_get_error_code (j); +    dr.hr.hint = TALER_JSON_get_error_hint (j); +    break; +  case MHD_HTTP_FORBIDDEN: +    dr.hr.ec = TALER_JSON_get_error_code (j); +    dr.hr.hint = TALER_JSON_get_error_hint (j); +    /* Nothing really to verify, exchange says one of the signatures is +       invalid; as we checked them, this should never happen, we +       should pass the JSON reply to the application */ +    break; +  case MHD_HTTP_NOT_FOUND: +    dr.hr.ec = TALER_JSON_get_error_code (j); +    dr.hr.hint = TALER_JSON_get_error_hint (j); +    /* Nothing really to verify, this should never +       happen, we should pass the JSON reply to the application */ +    break; +  case MHD_HTTP_CONFLICT: +    { +      const struct TALER_EXCHANGE_Keys *key_state; +      struct TALER_CoinSpendPublicKeyP coin_pub; +      struct GNUNET_JSON_Specification spec[] = { +        GNUNET_JSON_spec_fixed_auto ("coin_pub", +                                     &coin_pub), +        GNUNET_JSON_spec_end () +      }; +      const struct TALER_EXCHANGE_DenomPublicKey *dki; +      bool found = false; + +      if (GNUNET_OK != +          GNUNET_JSON_parse (j, +                             spec, +                             NULL, NULL)) +      { +        GNUNET_break_op (0); +        dr.hr.http_status = 0; +        dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; +        break; +      } +      for (unsigned int i = 0; i<dh->num_cdds; i++) +      { +        if (0 != +            GNUNET_memcmp (&coin_pub, +                           &dh->cdds[i].coin_pub)) +          continue; +        key_state = TALER_EXCHANGE_get_keys (dh->exchange); +        dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state, +                                                           &dh->cdds[i]. +                                                           h_denom_pub); +        GNUNET_assert (NULL != dki); +        if (GNUNET_OK != +            TALER_EXCHANGE_check_coin_conflict_ ( +              keys, +              j, +              dki, +              &dh->cdds[i].coin_pub, +              &dh->cdds[i].coin_sig, +              &dh->cdds[i].amount)) +        { +          GNUNET_break_op (0); +          dr.hr.http_status = 0; +          dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; +          break; +        } +        found = true; +        break; +      } +      if (! found) +      { +        GNUNET_break_op (0); +        dr.hr.http_status = 0; +        dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; +        break; +      } +      dr.hr.ec = TALER_JSON_get_error_code (j); +      dr.hr.hint = TALER_JSON_get_error_hint (j); +    } +    break; +  case MHD_HTTP_GONE: +    /* could happen if denomination was revoked */ +    /* Note: one might want to check /keys for revocation +       signature here, alas tricky in case our /keys +       is outdated => left to clients */ +    dr.hr.ec = TALER_JSON_get_error_code (j); +    dr.hr.hint = TALER_JSON_get_error_hint (j); +    break; +  case MHD_HTTP_INTERNAL_SERVER_ERROR: +    dr.hr.ec = TALER_JSON_get_error_code (j); +    dr.hr.hint = TALER_JSON_get_error_hint (j); +    /* Server had an internal issue; we should retry, but this API +       leaves this to the application */ +    break; +  default: +    /* unexpected response code */ +    dr.hr.ec = TALER_JSON_get_error_code (j); +    dr.hr.hint = TALER_JSON_get_error_hint (j); +    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                "Unexpected response code %u/%d for exchange deposit\n", +                (unsigned int) response_code, +                dr.hr.ec); +    GNUNET_break_op (0); +    break; +  } +  dh->cb (dh->cb_cls, +          &dr); +  TALER_EXCHANGE_batch_deposit_cancel (dh); +} + + +struct TALER_EXCHANGE_BatchDepositHandle * +TALER_EXCHANGE_batch_deposit ( +  struct TALER_EXCHANGE_Handle *exchange, +  const struct TALER_EXCHANGE_DepositContractDetail *dcd, +  unsigned int num_cdds, +  const struct TALER_EXCHANGE_CoinDepositDetail *cdds, +  TALER_EXCHANGE_BatchDepositResultCallback cb, +  void *cb_cls, +  enum TALER_ErrorCode *ec) +{ +  const struct TALER_EXCHANGE_Keys *key_state; +  struct TALER_EXCHANGE_BatchDepositHandle *dh; +  struct GNUNET_CURL_Context *ctx; +  json_t *deposit_obj; +  json_t *deposits; +  CURL *eh; +  struct TALER_Amount amount_without_fee; + +  GNUNET_assert (GNUNET_YES == +                 TEAH_handle_is_ready (exchange)); +  if (GNUNET_TIME_timestamp_cmp (dcd->refund_deadline, +                                 >, +                                 dcd->wire_deadline)) +  { +    GNUNET_break_op (0); +    *ec = TALER_EC_EXCHANGE_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE; +    return NULL; +  } +  key_state = TALER_EXCHANGE_get_keys (exchange); +  dh = GNUNET_new (struct TALER_EXCHANGE_BatchDepositHandle); +  dh->auditor_chance = AUDITOR_CHANCE; +  dh->exchange = exchange; +  dh->cb = cb; +  dh->cb_cls = cb_cls; +  dh->cdds = GNUNET_memdup (cdds, +                            num_cdds +                            * sizeof (*cdds)); +  dh->num_cdds = num_cdds; +  dh->dcd = *dcd; +  if (NULL != dcd->extension_details) +    TALER_deposit_extension_hash (dcd->extension_details, +                                  &dh->h_extensions); +  TALER_merchant_wire_signature_hash (dcd->merchant_payto_uri, +                                      &dcd->wire_salt, +                                      &dh->h_wire); +  deposits = json_array (); +  GNUNET_assert (NULL != deposits); +  for (unsigned int i = 0; i<num_cdds; i++) +  { +    const struct TALER_EXCHANGE_CoinDepositDetail *cdd = &cdds[i]; +    const struct TALER_EXCHANGE_DenomPublicKey *dki; + +    dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state, +                                                       &cdd->h_denom_pub); +    if (NULL == dki) +    { +      *ec = TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN; +      GNUNET_break_op (0); +      return NULL; +    } +    if (0 > +        TALER_amount_subtract (&amount_without_fee, +                               &cdd->amount, +                               &dki->fees.deposit)) +    { +      *ec = TALER_EC_EXCHANGE_DEPOSIT_FEE_ABOVE_AMOUNT; +      GNUNET_break_op (0); +      GNUNET_free (dh->cdds); +      GNUNET_free (dh); +      return NULL; +    } + +    if (GNUNET_OK != +        TALER_EXCHANGE_verify_deposit_signature_ (dcd, +                                                  &dh->h_extensions, +                                                  &dh->h_wire, +                                                  cdd, +                                                  dki)) +    { +      *ec = TALER_EC_EXCHANGE_DEPOSIT_COIN_SIGNATURE_INVALID; +      GNUNET_break_op (0); +      GNUNET_free (dh->cdds); +      GNUNET_free (dh); +      return NULL; +    } +    GNUNET_assert ( +      0 == +      json_array_append_new ( +        deposits, +        GNUNET_JSON_PACK ( +          TALER_JSON_pack_amount ("contribution", +                                  &cdd->amount), +          GNUNET_JSON_pack_allow_null ( +            GNUNET_JSON_pack_data_auto ("h_age_commitment", +                                        &cdd->h_age_commitment)), +          GNUNET_JSON_pack_data_auto ("denom_pub_hash", +                                      &cdd->h_denom_pub), +          TALER_JSON_pack_denom_sig ("ub_sig", +                                     &cdd->denom_sig), +          GNUNET_JSON_pack_data_auto ("coin_sig", +                                      &cdd->coin_sig) +          ))); +  } +  dh->url = TEAH_path_to_url (exchange, +                              "/batch-deposit"); +  if (NULL == dh->url) +  { +    GNUNET_break (0); +    *ec = TALER_EC_GENERIC_ALLOCATION_FAILURE; +    GNUNET_free (dh->url); +    GNUNET_free (dh->cdds); +    GNUNET_free (dh); +    return NULL; +  } + +  deposit_obj = GNUNET_JSON_PACK ( +    GNUNET_JSON_pack_array_steal ("coins", +                                  deposits), +    GNUNET_JSON_pack_string ("merchant_payto_uri", +                             dcd->merchant_payto_uri), +    GNUNET_JSON_pack_data_auto ("wire_salt", +                                &dcd->wire_salt), +    GNUNET_JSON_pack_data_auto ("h_contract_terms", +                                &dcd->h_contract_terms), +    GNUNET_JSON_pack_timestamp ("timestamp", +                                dcd->timestamp), +    GNUNET_JSON_pack_data_auto ("merchant_pub", +                                &dcd->merchant_pub), +    GNUNET_JSON_pack_allow_null ( +      GNUNET_JSON_pack_timestamp ("refund_deadline", +                                  dcd->refund_deadline)), +    GNUNET_JSON_pack_timestamp ("wire_transfer_deadline", +                                dcd->wire_deadline)); +  GNUNET_assert (NULL != deposit_obj); +  eh = TALER_EXCHANGE_curl_easy_get_ (dh->url); +  if ( (NULL == eh) || +       (GNUNET_OK != +        TALER_curl_easy_post (&dh->ctx, +                              eh, +                              deposit_obj)) ) +  { +    *ec = TALER_EC_GENERIC_CURL_ALLOCATION_FAILURE; +    GNUNET_break (0); +    if (NULL != eh) +      curl_easy_cleanup (eh); +    json_decref (deposit_obj); +    GNUNET_free (dh->cdds); +    GNUNET_free (dh->url); +    GNUNET_free (dh); +    return NULL; +  } +  json_decref (deposit_obj); +  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, +              "URL for deposit: `%s'\n", +              dh->url); +  ctx = TEAH_handle_to_context (exchange); +  dh->job = GNUNET_CURL_job_add2 (ctx, +                                  eh, +                                  dh->ctx.headers, +                                  &handle_deposit_finished, +                                  dh); +  return dh; +} + + +void +TALER_EXCHANGE_batch_deposit_force_dc (struct +                                       TALER_EXCHANGE_BatchDepositHandle * +                                       deposit) +{ +  deposit->auditor_chance = 1; +} + + +void +TALER_EXCHANGE_batch_deposit_cancel (struct +                                     TALER_EXCHANGE_BatchDepositHandle *deposit) +{ +  if (NULL != deposit->job) +  { +    GNUNET_CURL_job_cancel (deposit->job); +    deposit->job = NULL; +  } +  GNUNET_free (deposit->url); +  GNUNET_free (deposit->cdds); +  GNUNET_free (deposit->exchange_sigs); +  TALER_curl_easy_post_finished (&deposit->ctx); +  GNUNET_free (deposit); +} + + +/* end of exchange_api_batch_deposit.c */ diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c index 26ddb3c0..739b215f 100644 --- a/src/lib/exchange_api_common.c +++ b/src/lib/exchange_api_common.c @@ -1946,4 +1946,66 @@ TALER_EXCHANGE_get_min_denomination_ (  } +enum GNUNET_GenericReturnValue +TALER_EXCHANGE_verify_deposit_signature_ ( +  const struct TALER_EXCHANGE_DepositContractDetail *dcd, +  const struct TALER_ExtensionContractHashP *ech, +  const struct TALER_MerchantWireHashP *h_wire, +  const struct TALER_EXCHANGE_CoinDepositDetail *cdd, +  const struct TALER_EXCHANGE_DenomPublicKey *dki) +{ +  if (GNUNET_OK != +      TALER_wallet_deposit_verify (&cdd->amount, +                                   &dki->fees.deposit, +                                   h_wire, +                                   &dcd->h_contract_terms, +                                   &cdd->h_age_commitment, +                                   ech, +                                   &cdd->h_denom_pub, +                                   dcd->timestamp, +                                   &dcd->merchant_pub, +                                   dcd->refund_deadline, +                                   &cdd->coin_pub, +                                   &cdd->coin_sig)) +  { +    GNUNET_break_op (0); +    TALER_LOG_WARNING ("Invalid coin signature on /deposit request!\n"); +    TALER_LOG_DEBUG ("... amount_with_fee was %s\n", +                     TALER_amount2s (&cdd->amount)); +    TALER_LOG_DEBUG ("... deposit_fee was %s\n", +                     TALER_amount2s (&dki->fees.deposit)); +    return GNUNET_SYSERR; +  } + +  /* check coin signature */ +  { +    struct TALER_CoinPublicInfo coin_info = { +      .coin_pub = cdd->coin_pub, +      .denom_pub_hash = cdd->h_denom_pub, +      .denom_sig = cdd->denom_sig, +      .h_age_commitment = cdd->h_age_commitment, +    }; + +    if (GNUNET_YES != +        TALER_test_coin_valid (&coin_info, +                               &dki->key)) +    { +      GNUNET_break_op (0); +      TALER_LOG_WARNING ("Invalid coin passed for /deposit\n"); +      return GNUNET_SYSERR; +    } +  } + +  /* Check coin does make a contribution */ +  if (0 < TALER_amount_cmp (&dki->fees.deposit, +                            &cdd->amount)) +  { +    GNUNET_break_op (0); +    TALER_LOG_WARNING ("Deposit amount smaller than fee\n"); +    return GNUNET_SYSERR; +  } +  return GNUNET_OK; +} + +  /* end of exchange_api_common.c */ diff --git a/src/lib/exchange_api_common.h b/src/lib/exchange_api_common.h index f4737ca9..a75ed3ed 100644 --- a/src/lib/exchange_api_common.h +++ b/src/lib/exchange_api_common.h @@ -198,4 +198,24 @@ TALER_EXCHANGE_get_min_denomination_ (    const struct TALER_EXCHANGE_Keys *keys,    struct TALER_Amount *min); + +/** + * Verify signature information about the deposit. + * + * @param dcd contract details + * @param ech hashed contract (passed to avoid recomputation) + * @param h_wire hashed wire details (passed to avoid recomputation) + * @param cdd coin-specific details + * @param dki denomination of the coin + * @return #GNUNET_OK if signatures are OK, #GNUNET_SYSERR if not + */ +enum GNUNET_GenericReturnValue +TALER_EXCHANGE_verify_deposit_signature_ ( +  const struct TALER_EXCHANGE_DepositContractDetail *dcd, +  const struct TALER_ExtensionContractHashP *ech, +  const struct TALER_MerchantWireHashP *h_wire, +  const struct TALER_EXCHANGE_CoinDepositDetail *cdd, +  const struct TALER_EXCHANGE_DenomPublicKey *dki); + +  #endif diff --git a/src/lib/exchange_api_deposit.c b/src/lib/exchange_api_deposit.c index 7e824617..32964341 100644 --- a/src/lib/exchange_api_deposit.c +++ b/src/lib/exchange_api_deposit.c @@ -378,77 +378,6 @@ handle_deposit_finished (void *cls,  } -/** - * Verify signature information about the deposit. - * - * @param dcd contract details - * @param ech hashed contract (passed to avoid recomputation) - * @param h_wire hashed wire details (passed to avoid recomputation) - * @param cdd coin-specific details - * @param dki denomination of the coin - * @return #GNUNET_OK if signatures are OK, #GNUNET_SYSERR if not - */ -static enum GNUNET_GenericReturnValue -verify_signatures (const struct TALER_EXCHANGE_DepositContractDetail *dcd, -                   const struct TALER_ExtensionContractHashP *ech, -                   const struct TALER_MerchantWireHashP *h_wire, -                   const struct TALER_EXCHANGE_CoinDepositDetail *cdd, -                   const struct TALER_EXCHANGE_DenomPublicKey *dki) -{ -  if (GNUNET_OK != -      TALER_wallet_deposit_verify (&cdd->amount, -                                   &dki->fees.deposit, -                                   h_wire, -                                   &dcd->h_contract_terms, -                                   &cdd->h_age_commitment, -                                   ech, -                                   &cdd->h_denom_pub, -                                   dcd->timestamp, -                                   &dcd->merchant_pub, -                                   dcd->refund_deadline, -                                   &cdd->coin_pub, -                                   &cdd->coin_sig)) -  { -    GNUNET_break_op (0); -    TALER_LOG_WARNING ("Invalid coin signature on /deposit request!\n"); -    TALER_LOG_DEBUG ("... amount_with_fee was %s\n", -                     TALER_amount2s (&cdd->amount)); -    TALER_LOG_DEBUG ("... deposit_fee was %s\n", -                     TALER_amount2s (&dki->fees.deposit)); -    return GNUNET_SYSERR; -  } - -  /* check coin signature */ -  { -    struct TALER_CoinPublicInfo coin_info = { -      .coin_pub = cdd->coin_pub, -      .denom_pub_hash = cdd->h_denom_pub, -      .denom_sig = cdd->denom_sig, -      .h_age_commitment = cdd->h_age_commitment, -    }; - -    if (GNUNET_YES != -        TALER_test_coin_valid (&coin_info, -                               &dki->key)) -    { -      GNUNET_break_op (0); -      TALER_LOG_WARNING ("Invalid coin passed for /deposit\n"); -      return GNUNET_SYSERR; -    } -  } - -  /* Check coin does make a contribution */ -  if (0 < TALER_amount_cmp (&dki->fees.deposit, -                            &cdd->amount)) -  { -    GNUNET_break_op (0); -    TALER_LOG_WARNING ("Deposit amount smaller than fee\n"); -    return GNUNET_SYSERR; -  } -  return GNUNET_OK; -} - -  struct TALER_EXCHANGE_DepositHandle *  TALER_EXCHANGE_deposit (    struct TALER_EXCHANGE_Handle *exchange, @@ -526,11 +455,11 @@ TALER_EXCHANGE_deposit (                                        &dcd->wire_salt,                                        &dh->h_wire);    if (GNUNET_OK != -      verify_signatures (dcd, -                         &dh->h_extensions, -                         &dh->h_wire, -                         cdd, -                         dki)) +      TALER_EXCHANGE_verify_deposit_signature_ (dcd, +                                                &dh->h_extensions, +                                                &dh->h_wire, +                                                cdd, +                                                dki))    {      *ec = TALER_EC_EXCHANGE_DEPOSIT_COIN_SIGNATURE_INVALID;      GNUNET_break_op (0); diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c index 3cdc8ad2..488a419b 100644 --- a/src/lib/exchange_api_handle.c +++ b/src/lib/exchange_api_handle.c @@ -992,7 +992,7 @@ decode_keys_json (const json_t *resp_obj,                                                   check_sig,                                                   denom_key_obj,                                                   &key_data->master_pub, -                                                 check_sig ? &hash_xor: NULL)); +                                                 check_sig ? &hash_xor : NULL));            // Build the running xor of the SHA512-hash of the public keys            { diff --git a/src/lib/exchange_api_purse_create_with_deposit.c b/src/lib/exchange_api_purse_create_with_deposit.c index 3a5b7df5..ce0221aa 100644 --- a/src/lib/exchange_api_purse_create_with_deposit.c +++ b/src/lib/exchange_api_purse_create_with_deposit.c @@ -680,8 +680,8 @@ TALER_EXCHANGE_purse_create_with_deposit (      GNUNET_JSON_pack_allow_null (        TALER_JSON_pack_econtract ("econtract",                                   upload_contract -                                  ? &pch->econtract -                                  : NULL)), +                                 ? &pch->econtract +                                 : NULL)),      GNUNET_JSON_pack_data_auto ("purse_sig",                                  &pch->purse_sig),      GNUNET_JSON_pack_data_auto ("merge_pub", diff --git a/src/lib/exchange_api_purse_create_with_merge.c b/src/lib/exchange_api_purse_create_with_merge.c index 2b4f1cd2..f3c72d4f 100644 --- a/src/lib/exchange_api_purse_create_with_merge.c +++ b/src/lib/exchange_api_purse_create_with_merge.c @@ -478,8 +478,8 @@ TALER_EXCHANGE_purse_create_with_merge (      GNUNET_JSON_pack_allow_null (        TALER_JSON_pack_econtract ("econtract",                                   upload_contract -                                  ? &pcm->econtract -                                  : NULL)), +                                 ? &pcm->econtract +                                 : NULL)),      GNUNET_JSON_pack_allow_null (        pay_for_purse        ? TALER_JSON_pack_amount ("purse_fee", | 
