diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/exchange/taler-exchange-httpd_batch-withdraw.c | 1 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_reserves_history.c | 2 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_reserves_open.c | 1 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_responses.c | 11 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_responses.h | 2 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_withdraw.c | 1 | ||||
| -rw-r--r-- | src/lib/exchange_api_common.h | 10 | ||||
| -rw-r--r-- | src/lib/exchange_api_reserves_open.c | 129 | 
8 files changed, 134 insertions, 23 deletions
| diff --git a/src/exchange/taler-exchange-httpd_batch-withdraw.c b/src/exchange/taler-exchange-httpd_batch-withdraw.c index cf238204..541d6572 100644 --- a/src/exchange/taler-exchange-httpd_batch-withdraw.c +++ b/src/exchange/taler-exchange-httpd_batch-withdraw.c @@ -240,6 +240,7 @@ batch_withdraw_transaction (void *cls,      TEH_plugin->rollback (TEH_plugin->cls);      *mhd_ret = TEH_RESPONSE_reply_reserve_insufficient_balance (        connection, +      TALER_EC_EXCHANGE_WITHDRAW_INSUFFICIENT_FUNDS,        &wc->batch_total,        wc->reserve_pub);      return GNUNET_DB_STATUS_HARD_ERROR; diff --git a/src/exchange/taler-exchange-httpd_reserves_history.c b/src/exchange/taler-exchange-httpd_reserves_history.c index aa3f8ab5..ffdc6eaa 100644 --- a/src/exchange/taler-exchange-httpd_reserves_history.c +++ b/src/exchange/taler-exchange-httpd_reserves_history.c @@ -159,7 +159,7 @@ reserve_history_transaction (void *cls,      {        return TALER_MHD_reply_with_error (connection,                                           MHD_HTTP_CONFLICT, -                                         TALER_EC_EXCHANGE_WITHDRAW_HISTORY_ERROR_INSUFFICIENT_FUNDS, +                                         TALER_EC_EXCHANGE_GET_RESERVE_HISTORY_ERROR_INSUFFICIENT_BALANCE,                                           NULL);      }      if (idempotent) diff --git a/src/exchange/taler-exchange-httpd_reserves_open.c b/src/exchange/taler-exchange-httpd_reserves_open.c index ced291d7..6909c862 100644 --- a/src/exchange/taler-exchange-httpd_reserves_open.c +++ b/src/exchange/taler-exchange-httpd_reserves_open.c @@ -288,6 +288,7 @@ reserve_open_transaction (void *cls,      *mhd_ret        = TEH_RESPONSE_reply_reserve_insufficient_balance (            connection, +          TALER_EC_EXCHANGE_RESERVES_OPEN_INSUFFICIENT_FUNDS,            &rsc->reserve_payment,            rsc->reserve_pub);      return GNUNET_DB_STATUS_HARD_ERROR; diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c index ca110ad4..4120405f 100644 --- a/src/exchange/taler-exchange-httpd_responses.c +++ b/src/exchange/taler-exchange-httpd_responses.c @@ -1000,8 +1000,9 @@ TEH_RESPONSE_compile_reserve_history (   * @return MHD result code   */  static MHD_RESULT -reply_withdraw_insufficient_funds ( +reply_reserve_insufficient_funds (    struct MHD_Connection *connection, +  enum TALER_ErrorCode ec,    const struct TALER_Amount *ebalance,    const struct TALER_Amount *withdraw_amount,    const struct TALER_EXCHANGEDB_ReserveHistory *rh) @@ -1012,12 +1013,12 @@ reply_withdraw_insufficient_funds (    if (NULL == json_history)      return TALER_MHD_reply_with_error (connection,                                         MHD_HTTP_INTERNAL_SERVER_ERROR, -                                       TALER_EC_EXCHANGE_WITHDRAW_HISTORY_ERROR_INSUFFICIENT_FUNDS, +                                       TALER_EC_EXCHANGE_RESERVE_HISTORY_ERROR_INSUFFICIENT_FUNDS,                                         NULL);    return TALER_MHD_REPLY_JSON_PACK (      connection,      MHD_HTTP_CONFLICT, -    TALER_JSON_pack_ec (TALER_EC_EXCHANGE_WITHDRAW_INSUFFICIENT_FUNDS), +    TALER_JSON_pack_ec (ec),      TALER_JSON_pack_amount ("balance",                              ebalance),      TALER_JSON_pack_amount ("requested_amount", @@ -1030,6 +1031,7 @@ reply_withdraw_insufficient_funds (  MHD_RESULT  TEH_RESPONSE_reply_reserve_insufficient_balance (    struct MHD_Connection *connection, +  enum TALER_ErrorCode ec,    const struct TALER_Amount *balance_required,    const struct TALER_ReservePublicKeyP *reserve_pub)  { @@ -1063,8 +1065,9 @@ TEH_RESPONSE_reply_reserve_insufficient_balance (                                         TALER_EC_GENERIC_DB_FETCH_FAILED,                                         "reserve history");    } -  mhd_ret = reply_withdraw_insufficient_funds ( +  mhd_ret = reply_reserve_insufficient_funds (      connection, +    ec,      &balance,      balance_required,      rh); diff --git a/src/exchange/taler-exchange-httpd_responses.h b/src/exchange/taler-exchange-httpd_responses.h index 3eebf027..ba6577b2 100644 --- a/src/exchange/taler-exchange-httpd_responses.h +++ b/src/exchange/taler-exchange-httpd_responses.h @@ -63,6 +63,7 @@ TEH_RESPONSE_reply_unknown_denom_pub_hash (   * an insufficient balance for the given operation.   *   * @param connection connection to the client + * @param ec specific error code to return with the reserve history   * @param balance_required the balance required for the operation   * @param reserve_pub the reserve with insufficient balance   * @return MHD result code @@ -70,6 +71,7 @@ TEH_RESPONSE_reply_unknown_denom_pub_hash (  MHD_RESULT  TEH_RESPONSE_reply_reserve_insufficient_balance (    struct MHD_Connection *connection, +  enum TALER_ErrorCode ec,    const struct TALER_Amount *balance_required,    const struct TALER_ReservePublicKeyP *reserve_pub); diff --git a/src/exchange/taler-exchange-httpd_withdraw.c b/src/exchange/taler-exchange-httpd_withdraw.c index 57020ee8..27b17672 100644 --- a/src/exchange/taler-exchange-httpd_withdraw.c +++ b/src/exchange/taler-exchange-httpd_withdraw.c @@ -217,6 +217,7 @@ withdraw_transaction (void *cls,      TEH_plugin->rollback (TEH_plugin->cls);      *mhd_ret = TEH_RESPONSE_reply_reserve_insufficient_balance (        connection, +      TALER_EC_EXCHANGE_WITHDRAW_INSUFFICIENT_FUNDS,        &wc->collectable.amount_with_fee,        &wc->collectable.reserve_pub);      return GNUNET_DB_STATUS_HARD_ERROR; diff --git a/src/lib/exchange_api_common.h b/src/lib/exchange_api_common.h index 80c36daf..1b9ddce3 100644 --- a/src/lib/exchange_api_common.h +++ b/src/lib/exchange_api_common.h @@ -129,12 +129,10 @@ TALER_EXCHANGE_check_coin_amount_conflict_ (  /** - * Verify that @a proof contains a coin history - * that demonstrates that @a coin_pub was previously - * used with a denomination key that is different - * from @a ch_denom_pub.  Note that the coin history - * MUST have been checked before using - * #TALER_EXCHANGE_check_coin_amount_conflict_(). + * Verify that @a proof contains a coin history that demonstrates that @a + * coin_pub was previously used with a denomination key that is different from + * @a ch_denom_pub.  Note that the coin history MUST have been checked before + * using #TALER_EXCHANGE_check_coin_amount_conflict_().   *   * @param proof a proof to check   * @param ch_denom_pub hash of the conflicting denomination diff --git a/src/lib/exchange_api_reserves_open.c b/src/lib/exchange_api_reserves_open.c index 64d259ba..2b7ef0d9 100644 --- a/src/lib/exchange_api_reserves_open.c +++ b/src/lib/exchange_api_reserves_open.c @@ -27,12 +27,40 @@  #include <gnunet/gnunet_curl_lib.h>  #include "taler_exchange_service.h"  #include "taler_json_lib.h" +#include "exchange_api_common.h"  #include "exchange_api_handle.h"  #include "taler_signatures.h"  #include "exchange_api_curl_defaults.h"  /** + * Information we keep per coin to validate the reply. + */ +struct CoinData +{ +  /** +   * Public key of the coin. +   */ +  struct TALER_CoinSpendPublicKeyP coin_pub; + +  /** +   * Signature by the coin. +   */ +  struct TALER_CoinSpendSignatureP coin_sig; + +  /** +   * The hash of the denomination's public key +   */ +  struct TALER_DenominationHashP h_denom_pub; + +  /** +   * How much did this coin contribute. +   */ +  struct TALER_Amount contribution; +}; + + +/**   * @brief A /reserves/$RID/open Handle   */  struct TALER_EXCHANGE_ReservesOpenHandle @@ -70,6 +98,16 @@ struct TALER_EXCHANGE_ReservesOpenHandle    void *cb_cls;    /** +   * Information we keep per coin to validate the reply. +   */ +  struct CoinData *coins; + +  /** +   * Length of the @e coins array. +   */ +  unsigned int num_coins; + +  /**     * Public key of the reserve we are querying.     */    struct TALER_ReservePublicKeyP reserve_pub; @@ -282,12 +320,74 @@ handle_reserves_open_finished (void *cls,      rs.hr.hint = TALER_JSON_get_error_hint (j);      break;    case MHD_HTTP_CONFLICT: -    // FIXME: not yet specified (#7428), but needed in -    // case of double-spending or insufficient -    // reserve balance! -    rs.hr.ec = TALER_JSON_get_error_code (j); -    rs.hr.hint = TALER_JSON_get_error_hint (j); -    break; +    { +      const struct TALER_EXCHANGE_Keys *keys; +      const struct CoinData *cd = NULL; +      struct TALER_CoinSpendPublicKeyP coin_pub; +      const struct TALER_EXCHANGE_DenomPublicKey *dk; +      struct GNUNET_JSON_Specification spec[] = { +        GNUNET_JSON_spec_fixed_auto ("coin_pub", +                                     &coin_pub), +        GNUNET_JSON_spec_end () +      }; + +      keys = TALER_EXCHANGE_get_keys (roh->exchange); +      GNUNET_assert (NULL != keys); +      if (GNUNET_OK != +          GNUNET_JSON_parse (j, +                             spec, +                             NULL, +                             NULL)) +      { +        GNUNET_break_op (0); +        rs.hr.http_status = 0; +        rs.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; +        break; +      } +      for (unsigned int i = 0; i<roh->num_coins; i++) +      { +        const struct CoinData *cdi = &roh->coins[i]; + +        if (0 == GNUNET_memcmp (&coin_pub, +                                &cdi->coin_pub)) +        { +          cd = cdi; +          break; +        } +      } +      if (NULL == cd) +      { +        GNUNET_break_op (0); +        rs.hr.http_status = 0; +        rs.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; +        break; +      } +      dk = TALER_EXCHANGE_get_denomination_key_by_hash (keys, +                                                        &cd->h_denom_pub); +      if (NULL == dk) +      { +        GNUNET_break_op (0); +        rs.hr.http_status = 0; +        rs.hr.ec = TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR; +        break; +      } +      if (GNUNET_OK != +          TALER_EXCHANGE_check_coin_conflict_ (keys, +                                               j, +                                               dk, +                                               &coin_pub, +                                               &cd->coin_sig, +                                               &cd->contribution)) +      { +        GNUNET_break_op (0); +        rs.hr.http_status = 0; +        rs.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; +        break; +      } +      rs.hr.ec = TALER_JSON_get_error_code (j); +      rs.hr.hint = TALER_JSON_get_error_hint (j); +      break; +    }    case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:      if (GNUNET_OK !=          handle_reserves_open_kyc (roh, @@ -402,18 +502,21 @@ TALER_EXCHANGE_reserves_open (                                    min_purses,                                    reserve_priv,                                    &roh->reserve_sig); +  roh->coins = GNUNET_new_array (coin_payments_length, +                                 struct CoinData);    cpa = json_array ();    GNUNET_assert (NULL != cpa);    for (unsigned int i = 0; i<coin_payments_length; i++)    {      const struct TALER_EXCHANGE_PurseDeposit *pd = &coin_payments[i]; -    struct TALER_CoinSpendSignatureP coin_sig; -    struct TALER_CoinSpendPublicKeyP coin_pub;      const struct TALER_AgeCommitmentProof *acp = pd->age_commitment_proof;      struct TALER_AgeCommitmentHash ahac;      struct TALER_AgeCommitmentHash *achp = NULL; +    struct CoinData *cd = &roh->coins[i];      json_t *cp; +    cd->contribution = pd->amount; +    cd->h_denom_pub = pd->h_denom_pub;      if (NULL != acp)      {        TALER_age_commitment_hash (&acp->commitment, @@ -423,9 +526,9 @@ TALER_EXCHANGE_reserves_open (      TALER_wallet_reserve_open_deposit_sign (&pd->amount,                                              &roh->reserve_sig,                                              &pd->coin_priv, -                                            &coin_sig); +                                            &cd->coin_sig);      GNUNET_CRYPTO_eddsa_key_get_public (&pd->coin_priv.eddsa_priv, -                                        &coin_pub.eddsa_pub); +                                        &cd->coin_pub.eddsa_pub);      cp = GNUNET_JSON_PACK (        GNUNET_JSON_pack_allow_null ( @@ -438,9 +541,9 @@ TALER_EXCHANGE_reserves_open (        TALER_JSON_pack_denom_sig ("ub_sig",                                   &pd->denom_sig),        GNUNET_JSON_pack_data_auto ("coin_pub", -                                  &coin_pub), +                                  &cd->coin_pub),        GNUNET_JSON_pack_data_auto ("coin_sig", -                                  &coin_sig)); +                                  &cd->coin_sig));      GNUNET_assert (0 ==                     json_array_append_new (cpa,                                            cp)); @@ -468,6 +571,7 @@ TALER_EXCHANGE_reserves_open (        GNUNET_break (0);        curl_easy_cleanup (eh);        json_decref (open_obj); +      GNUNET_free (roh->coins);        GNUNET_free (roh->url);        GNUNET_free (roh);        return NULL; @@ -494,6 +598,7 @@ TALER_EXCHANGE_reserves_open_cancel (      roh->job = NULL;    }    TALER_curl_easy_post_finished (&roh->post_ctx); +  GNUNET_free (roh->coins);    GNUNET_free (roh->url);    GNUNET_free (roh);  } | 
