diff options
| -rw-r--r-- | src/exchange/taler-exchange-httpd_deposit.c | 136 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_keystate.c | 3 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_payback.c | 149 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_refresh_melt.c | 331 | 
4 files changed, 312 insertions, 307 deletions
| diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c index 38cc4307..0e4e0b26 100644 --- a/src/exchange/taler-exchange-httpd_deposit.c +++ b/src/exchange/taler-exchange-httpd_deposit.c @@ -256,7 +256,6 @@ verify_and_execute_deposit (struct MHD_Connection *connection,    int mhd_ret;    struct TALER_Amount amount_without_fee;    struct DepositContext dc; -  struct TEH_KS_StateHandle *mks;    const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;    enum TALER_ErrorCode ec;    unsigned int hc; @@ -288,32 +287,35 @@ verify_and_execute_deposit (struct MHD_Connection *connection,    }    /* check denomination */ -  mks = TEH_KS_acquire (GNUNET_TIME_absolute_get ()); -  if (NULL == mks) -  { -    TALER_LOG_ERROR ("Lacking keys to operate\n"); -    return TALER_MHD_reply_with_error (connection, -                                       MHD_HTTP_INTERNAL_SERVER_ERROR, -                                       TALER_EC_EXCHANGE_BAD_CONFIGURATION, -                                       "no keys"); -  } -  dki = TEH_KS_denomination_key_lookup_by_hash (mks, -                                                &deposit->coin.denom_pub_hash, -                                                TEH_KS_DKU_DEPOSIT, -                                                &ec, -                                                &hc); -  if (NULL == dki)    { +    struct TEH_KS_StateHandle *mks; + +    mks = TEH_KS_acquire (GNUNET_TIME_absolute_get ()); +    if (NULL == mks) +    { +      TALER_LOG_ERROR ("Lacking keys to operate\n"); +      return TALER_MHD_reply_with_error (connection, +                                         MHD_HTTP_INTERNAL_SERVER_ERROR, +                                         TALER_EC_EXCHANGE_BAD_CONFIGURATION, +                                         "no keys"); +    } +    dki = TEH_KS_denomination_key_lookup_by_hash (mks, +                                                  &deposit->coin.denom_pub_hash, +                                                  TEH_KS_DKU_DEPOSIT, +                                                  &ec, +                                                  &hc); +    if (NULL == dki) +    { +      TEH_KS_release (mks); +      return TALER_MHD_reply_with_error (connection, +                                         hc, +                                         ec, +                                         "Could not find denomination key used in deposit"); +    } +    TALER_amount_ntoh (&dc.value, +                       &dki->issue.properties.value);      TEH_KS_release (mks); -    return TALER_MHD_reply_with_error (connection, -                                       hc, -                                       ec, -                                       "Could not find denomination key used in deposit");    } -  TALER_amount_ntoh (&dc.value, -                     &dki->issue.properties.value); -  TEH_KS_release (mks); -    /* execute transaction */    dc.deposit = deposit;    if (GNUNET_OK != @@ -406,7 +408,6 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,    unsigned int hc;    struct TALER_EXCHANGEDB_Deposit deposit;    struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; -  struct TEH_KS_StateHandle *key_state;    struct GNUNET_HashCode my_h_wire;    struct GNUNET_JSON_Specification spec[] = {      GNUNET_JSON_spec_json ("wire", &wire), @@ -503,50 +504,53 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,    }    /* check denomination exists and is valid */ -  key_state = TEH_KS_acquire (GNUNET_TIME_absolute_get ()); -  if (NULL == key_state) -  { -    TALER_LOG_ERROR ("Lacking keys to operate\n"); -    GNUNET_JSON_parse_free (spec); -    return TALER_MHD_reply_with_error (connection, -                                       MHD_HTTP_INTERNAL_SERVER_ERROR, -                                       TALER_EC_EXCHANGE_BAD_CONFIGURATION, -                                       "no keys"); -  } -  dki = TEH_KS_denomination_key_lookup_by_hash (key_state, -                                                &deposit.coin.denom_pub_hash, -                                                TEH_KS_DKU_DEPOSIT, -                                                &ec, -                                                &hc); -  if (NULL == dki)    { +    struct TEH_KS_StateHandle *key_state; + +    key_state = TEH_KS_acquire (GNUNET_TIME_absolute_get ()); +    if (NULL == key_state) +    { +      TALER_LOG_ERROR ("Lacking keys to operate\n"); +      GNUNET_JSON_parse_free (spec); +      return TALER_MHD_reply_with_error (connection, +                                         MHD_HTTP_INTERNAL_SERVER_ERROR, +                                         TALER_EC_EXCHANGE_BAD_CONFIGURATION, +                                         "no keys"); +    } +    dki = TEH_KS_denomination_key_lookup_by_hash (key_state, +                                                  &deposit.coin.denom_pub_hash, +                                                  TEH_KS_DKU_DEPOSIT, +                                                  &ec, +                                                  &hc); +    if (NULL == dki) +    { +      TEH_KS_release (key_state); +      TALER_LOG_WARNING ("Unknown denomination key in /deposit request\n"); +      GNUNET_JSON_parse_free (spec); +      return TALER_MHD_reply_with_error (connection, +                                         hc, +                                         ec, +                                         "Could not find denomination key used in deposit"); +    } +    TALER_amount_ntoh (&deposit.deposit_fee, +                       &dki->issue.properties.fee_deposit); +    /* check coin signature */ +    if (GNUNET_YES != +        TALER_test_coin_valid (&deposit.coin, +                               &dki->denom_pub)) +    { +      TALER_LOG_WARNING ("Invalid coin passed for /deposit\n"); +      TEH_KS_release (key_state); +      GNUNET_JSON_parse_free (spec); +      return TALER_MHD_reply_with_error (connection, +                                         MHD_HTTP_UNAUTHORIZED, +                                         TALER_EC_DEPOSIT_DENOMINATION_SIGNATURE_INVALID, +                                         "ub_sig"); +    } +    TALER_amount_ntoh (&deposit.deposit_fee, +                       &dki->issue.properties.fee_deposit);      TEH_KS_release (key_state); -    TALER_LOG_WARNING ("Unknown denomination key in /deposit request\n"); -    GNUNET_JSON_parse_free (spec); -    return TALER_MHD_reply_with_error (connection, -                                       hc, -                                       ec, -                                       "Could not find denomination key used in deposit"); -  } -  TALER_amount_ntoh (&deposit.deposit_fee, -                     &dki->issue.properties.fee_deposit); -  /* check coin signature */ -  if (GNUNET_YES != -      TALER_test_coin_valid (&deposit.coin, -                             &dki->denom_pub)) -  { -    TALER_LOG_WARNING ("Invalid coin passed for /deposit\n"); -    TEH_KS_release (key_state); -    GNUNET_JSON_parse_free (spec); -    return TALER_MHD_reply_with_error (connection, -                                       MHD_HTTP_UNAUTHORIZED, -                                       TALER_EC_DEPOSIT_DENOMINATION_SIGNATURE_INVALID, -                                       "ub_sig");    } -  TALER_amount_ntoh (&deposit.deposit_fee, -                     &dki->issue.properties.fee_deposit); -  TEH_KS_release (key_state); -    if (0 < TALER_amount_cmp (&deposit.deposit_fee,                              &deposit.amount_with_fee))    { diff --git a/src/exchange/taler-exchange-httpd_keystate.c b/src/exchange/taler-exchange-httpd_keystate.c index 8b40144d..60b7cb2c 100644 --- a/src/exchange/taler-exchange-httpd_keystate.c +++ b/src/exchange/taler-exchange-httpd_keystate.c @@ -448,6 +448,7 @@ ks_release (struct TEH_KS_StateHandle *key_state)    key_state->refcnt--;    if (0 == key_state->refcnt)    { +    GNUNET_assert (key_state != internal_key_state);      if (NULL != key_state->denomkey_map)      {        GNUNET_CONTAINER_multihashmap_iterate (key_state->denomkey_map, @@ -476,7 +477,6 @@ ks_release (struct TEH_KS_StateHandle *key_state)      GNUNET_array_grow (key_state->krd_array,                         key_state->krd_array_length,                         0); -    GNUNET_assert (key_state != internal_key_state);      GNUNET_free (key_state);    }  } @@ -1261,6 +1261,7 @@ setup_general_response_headers (const struct TEH_KS_StateHandle *key_state,      m = GNUNET_TIME_relative_to_absolute (TEH_max_keys_caching);      m = GNUNET_TIME_absolute_min (m,                                    key_state->next_reload); +    m = GNUNET_TIME_UNIT_FOREVER_ABS;      get_date_string (m,                       dat);      // FIXME: setting 'm' to FOREVER here exposes diff --git a/src/exchange/taler-exchange-httpd_payback.c b/src/exchange/taler-exchange-httpd_payback.c index bfd0f413..1a6a67d5 100644 --- a/src/exchange/taler-exchange-httpd_payback.c +++ b/src/exchange/taler-exchange-httpd_payback.c @@ -420,7 +420,6 @@ verify_and_execute_payback (struct MHD_Connection *connection,                              int refreshed)  {    struct PaybackContext pc; -  struct TEH_KS_StateHandle *key_state;    const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;    struct TALER_PaybackRequestPS pr;    struct GNUNET_HashCode c_hash; @@ -430,86 +429,88 @@ verify_and_execute_payback (struct MHD_Connection *connection,    unsigned int hc;    /* check denomination exists and is in payback mode */ -  key_state = TEH_KS_acquire (GNUNET_TIME_absolute_get ()); -  if (NULL == key_state)    { -    TALER_LOG_ERROR ("Lacking keys to operate\n"); -    return TALER_MHD_reply_with_error (connection, -                                       MHD_HTTP_INTERNAL_SERVER_ERROR, -                                       TALER_EC_EXCHANGE_BAD_CONFIGURATION, -                                       "no keys"); -  } -  dki = TEH_KS_denomination_key_lookup_by_hash (key_state, -                                                &coin->denom_pub_hash, -                                                TEH_KS_DKU_PAYBACK, -                                                &ec, -                                                &hc); -  if (NULL == dki) -  { -    TEH_KS_release (key_state); -    TALER_LOG_WARNING ( -      "Denomination key in /payback request not in payback mode\n"); -    return TALER_MHD_reply_with_error (connection, -                                       hc, -                                       ec, -                                       "denomination not allowing payback"); -  } -  TALER_amount_ntoh (&pc.value, -                     &dki->issue.properties.value); +    struct TEH_KS_StateHandle *key_state; -  /* check denomination signature */ -  if (GNUNET_YES != -      TALER_test_coin_valid (coin, -                             &dki->denom_pub)) -  { -    TALER_LOG_WARNING ("Invalid coin passed for /payback\n"); -    TEH_KS_release (key_state); -    return TALER_MHD_reply_with_error (connection, -                                       MHD_HTTP_FORBIDDEN, -                                       TALER_EC_PAYBACK_DENOMINATION_SIGNATURE_INVALID, -                                       "denom_sig"); -  } +    key_state = TEH_KS_acquire (GNUNET_TIME_absolute_get ()); +    if (NULL == key_state) +    { +      TALER_LOG_ERROR ("Lacking keys to operate\n"); +      return TALER_MHD_reply_with_error (connection, +                                         MHD_HTTP_INTERNAL_SERVER_ERROR, +                                         TALER_EC_EXCHANGE_BAD_CONFIGURATION, +                                         "no keys"); +    } +    dki = TEH_KS_denomination_key_lookup_by_hash (key_state, +                                                  &coin->denom_pub_hash, +                                                  TEH_KS_DKU_PAYBACK, +                                                  &ec, +                                                  &hc); +    if (NULL == dki) +    { +      TEH_KS_release (key_state); +      TALER_LOG_WARNING ( +        "Denomination key in /payback request not in payback mode\n"); +      return TALER_MHD_reply_with_error (connection, +                                         hc, +                                         ec, +                                         "denomination not allowing payback"); +    } +    TALER_amount_ntoh (&pc.value, +                       &dki->issue.properties.value); -  /* check payback request signature */ -  pr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_PAYBACK); -  pr.purpose.size = htonl (sizeof (struct TALER_PaybackRequestPS)); -  pr.coin_pub = coin->coin_pub; -  pr.h_denom_pub = dki->issue.properties.denom_hash; -  pr.coin_blind = *coin_bks; +    /* check denomination signature */ +    if (GNUNET_YES != +        TALER_test_coin_valid (coin, +                               &dki->denom_pub)) +    { +      TALER_LOG_WARNING ("Invalid coin passed for /payback\n"); +      TEH_KS_release (key_state); +      return TALER_MHD_reply_with_error (connection, +                                         MHD_HTTP_FORBIDDEN, +                                         TALER_EC_PAYBACK_DENOMINATION_SIGNATURE_INVALID, +                                         "denom_sig"); +    } -  if (GNUNET_OK != -      GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_PAYBACK, -                                  &pr.purpose, -                                  &coin_sig->eddsa_signature, -                                  &coin->coin_pub.eddsa_pub)) -  { -    TALER_LOG_WARNING ("Invalid signature on /payback request\n"); -    TEH_KS_release (key_state); -    return TALER_MHD_reply_with_error (connection, -                                       MHD_HTTP_FORBIDDEN, -                                       TALER_EC_PAYBACK_SIGNATURE_INVALID, -                                       "coin_sig"); -  } +    /* check payback request signature */ +    pr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_PAYBACK); +    pr.purpose.size = htonl (sizeof (struct TALER_PaybackRequestPS)); +    pr.coin_pub = coin->coin_pub; +    pr.h_denom_pub = dki->issue.properties.denom_hash; +    pr.coin_blind = *coin_bks; -  GNUNET_CRYPTO_hash (&coin->coin_pub.eddsa_pub, -                      sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey), -                      &c_hash); -  if (GNUNET_YES != -      GNUNET_CRYPTO_rsa_blind (&c_hash, -                               &coin_bks->bks, -                               dki->denom_pub.rsa_public_key, -                               &coin_ev, -                               &coin_ev_size)) -  { -    GNUNET_break (0); +    if (GNUNET_OK != +        GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_PAYBACK, +                                    &pr.purpose, +                                    &coin_sig->eddsa_signature, +                                    &coin->coin_pub.eddsa_pub)) +    { +      TALER_LOG_WARNING ("Invalid signature on /payback request\n"); +      TEH_KS_release (key_state); +      return TALER_MHD_reply_with_error (connection, +                                         MHD_HTTP_FORBIDDEN, +                                         TALER_EC_PAYBACK_SIGNATURE_INVALID, +                                         "coin_sig"); +    } +    GNUNET_CRYPTO_hash (&coin->coin_pub.eddsa_pub, +                        sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey), +                        &c_hash); +    if (GNUNET_YES != +        GNUNET_CRYPTO_rsa_blind (&c_hash, +                                 &coin_bks->bks, +                                 dki->denom_pub.rsa_public_key, +                                 &coin_ev, +                                 &coin_ev_size)) +    { +      GNUNET_break (0); +      TEH_KS_release (key_state); +      return TALER_MHD_reply_with_error (connection, +                                         MHD_HTTP_INTERNAL_SERVER_ERROR, +                                         TALER_EC_PAYBACK_BLINDING_FAILED, +                                         "coin_bks"); +    }      TEH_KS_release (key_state); - -    return TALER_MHD_reply_with_error (connection, -                                       MHD_HTTP_INTERNAL_SERVER_ERROR, -                                       TALER_EC_PAYBACK_BLINDING_FAILED, -                                       "coin_bks");    } -  TEH_KS_release (key_state);    GNUNET_CRYPTO_hash (coin_ev,                        coin_ev_size,                        &pc.h_blind); diff --git a/src/exchange/taler-exchange-httpd_refresh_melt.c b/src/exchange/taler-exchange-httpd_refresh_melt.c index e0a4d836..e2d92c50 100644 --- a/src/exchange/taler-exchange-httpd_refresh_melt.c +++ b/src/exchange/taler-exchange-httpd_refresh_melt.c @@ -51,7 +51,7 @@ static int  reply_refresh_melt_insufficient_funds (struct MHD_Connection *connection,                                         const struct                                         TALER_CoinSpendPublicKeyP *coin_pub, -                                       struct TALER_Amount coin_value, +                                       const struct TALER_Amount *coin_value,                                         struct TALER_EXCHANGEDB_TransactionList *                                         tl,                                         const struct TALER_Amount *requested, @@ -77,7 +77,7 @@ reply_refresh_melt_insufficient_funds (struct MHD_Connection *connection,                                      "coin_pub",                                      GNUNET_JSON_from_data_auto (coin_pub),                                      "original_value", -                                    TALER_JSON_from_amount (&coin_value), +                                    TALER_JSON_from_amount (coin_value),                                      "residual_value",                                      TALER_JSON_from_amount (residual),                                      "requested_value", @@ -144,12 +144,17 @@ struct RefreshMeltContext    struct TALER_EXCHANGEDB_RefreshSession refresh_session;    /** -   * Information about the @e coin's denomination. +   * Information about the @e coin's value.     */ -  struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; +  struct TALER_Amount coin_value;    /** -   * Set to #GNUNET_YES if this @a dki was revoked and the operation +   * Information about the @e coin's refresh fee. +   */ +  struct TALER_Amount coin_refresh_fee; + +  /** +   * Set to #GNUNET_YES if this coin's denomination was revoked and the operation     * is thus only allowed for zombie coins where the transaction     * history includes a #TALER_EXCHANGEDB_TT_OLD_COIN_PAYBACK.     */ @@ -175,12 +180,9 @@ refresh_check_melt (struct MHD_Connection *connection,                      int *mhd_ret)  {    struct TALER_EXCHANGEDB_TransactionList *tl; -  struct TALER_Amount coin_value;    struct TALER_Amount spent;    enum GNUNET_DB_QueryStatus qs; -  TALER_amount_ntoh (&coin_value, -                     &rmc->dki->issue.properties.value);    /* Start with cost of this melt transaction */    spent = rmc->refresh_session.amount_with_fee; @@ -242,7 +244,7 @@ refresh_check_melt (struct MHD_Connection *connection,    /* Refuse to refresh when the coin's value is insufficient       for the cost of all transactions. */ -  if (TALER_amount_cmp (&coin_value, +  if (TALER_amount_cmp (&rmc->coin_value,                          &spent) < 0)    {      struct TALER_Amount coin_residual; @@ -254,7 +256,7 @@ refresh_check_melt (struct MHD_Connection *connection,      *mhd_ret = reply_refresh_melt_insufficient_funds (connection,                                                        &rmc->refresh_session.coin                                                        .coin_pub, -                                                      coin_value, +                                                      &rmc->coin_value,                                                        tl,                                                        &rmc->refresh_session.                                                        amount_with_fee, @@ -374,22 +376,6 @@ static int  handle_refresh_melt (struct MHD_Connection *connection,                       struct RefreshMeltContext *rmc)  { -  /* sanity-check that "total melt amount > melt fee" */ -  { -    struct TALER_Amount fee_refresh; - -    TALER_amount_ntoh (&fee_refresh, -                       &rmc->dki->issue.properties.fee_refresh); -    if (TALER_amount_cmp (&fee_refresh, -                          &rmc->refresh_session.amount_with_fee) > 0) -    { -      GNUNET_break_op (0); -      return TALER_MHD_reply_with_error (connection, -                                         MHD_HTTP_BAD_REQUEST, -                                         TALER_EC_REFRESH_MELT_FEES_EXCEED_CONTRIBUTION, -                                         "melt amount smaller than melting fee"); -    } -  }    /* verify signature of coin for melt operation */    { @@ -401,7 +387,8 @@ handle_refresh_melt (struct MHD_Connection *connection,      body.rc = rmc->refresh_session.rc;      TALER_amount_hton (&body.amount_with_fee,                         &rmc->refresh_session.amount_with_fee); -    body.melt_fee = rmc->dki->issue.properties.fee_refresh; +    TALER_amount_hton (&body.melt_fee, +                       &rmc->coin_refresh_fee);      body.coin_pub = rmc->refresh_session.coin.coin_pub;      if (GNUNET_OK != @@ -441,6 +428,155 @@ handle_refresh_melt (struct MHD_Connection *connection,  /** + * Check for information about the melted coin's denomination, + * extracting its validity status and fee structure. + * + * @param connection HTTP connection we are handling + * @param rmc parsed request information + * @return MHD status code + */ +static int +check_for_denomination_key (struct MHD_Connection *connection, +                            struct RefreshMeltContext *rmc) +{ +  struct TEH_KS_StateHandle *key_state; + +  key_state = TEH_KS_acquire (GNUNET_TIME_absolute_get ()); +  if (NULL == key_state) +  { +    TALER_LOG_ERROR ("Lacking keys to operate\n"); +    return TALER_MHD_reply_with_error (connection, +                                       MHD_HTTP_INTERNAL_SERVER_ERROR, +                                       TALER_EC_EXCHANGE_BAD_CONFIGURATION, +                                       "no keys"); +  } + +  { +    /* Baseline: check if deposits/refreshs are generally +       simply still allowed for this denomination */ +    struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; +    unsigned int hc; +    enum TALER_ErrorCode ec; + +    dki = TEH_KS_denomination_key_lookup_by_hash (key_state, +                                                  &rmc->refresh_session.coin. +                                                  denom_pub_hash, +                                                  TEH_KS_DKU_DEPOSIT, +                                                  &ec, +                                                  &hc); +    /* Consider case that denomination was revoked but +       this coin was already seen and thus refresh is OK. */ +    if (NULL == dki) +    { +      dki = TEH_KS_denomination_key_lookup_by_hash (key_state, +                                                    &rmc->refresh_session.coin. +                                                    denom_pub_hash, +                                                    TEH_KS_DKU_PAYBACK, +                                                    &ec, +                                                    &hc); +      if (NULL != dki) +      { +        struct GNUNET_HashCode denom_hash; +        enum GNUNET_DB_QueryStatus qs; + +        qs = TEH_plugin->get_coin_denomination (TEH_plugin->cls, +                                                NULL, +                                                &rmc->refresh_session.coin. +                                                coin_pub, +                                                &denom_hash); +        if (0 > qs) +        { +          TEH_KS_release (key_state); +          return TALER_MHD_reply_with_error (connection, +                                             MHD_HTTP_INTERNAL_SERVER_ERROR, +                                             TALER_EC_REFRESH_MELT_DB_FETCH_ERROR, +                                             "failed to find information about old coin"); +        } +        GNUNET_break (0 == +                      GNUNET_memcmp (&denom_hash, +                                     &rmc->refresh_session.coin.denom_pub_hash)); +        if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) +        { +          /* We never saw this coin before, so _this_ justification is not OK */ +          dki = NULL; +        } +      } +    } + +    /* Consider the case that the denomination expired for deposits, +       but /refresh/payback refilled the balance of the 'zombie' coin +       and we should thus allow the refresh during the legal period. */ +    if (NULL == dki) +    { +      dki = TEH_KS_denomination_key_lookup_by_hash (key_state, +                                                    &rmc->refresh_session.coin. +                                                    denom_pub_hash, +                                                    TEH_KS_DKU_ZOMBIE, +                                                    &ec, +                                                    &hc); +      if (NULL != dki) +        rmc->zombie_required = GNUNET_YES; +    } +    if (NULL == dki) +    { +      TEH_KS_release (key_state); +      TALER_LOG_WARNING ("Unknown denomination key in /refresh/melt request\n"); +      return TALER_MHD_reply_with_error (connection, +                                         hc, +                                         ec, +                                         "unknown denomination"); +    } +    TALER_amount_ntoh (&rmc->coin_refresh_fee, +                       &dki->issue.properties.fee_refresh); +    TALER_amount_ntoh (&rmc->coin_value, +                       &dki->issue.properties.value); +    if (GNUNET_OK != +        TALER_test_coin_valid (&rmc->refresh_session.coin, +                               &dki->denom_pub)) +    { +      GNUNET_break_op (0); +      TEH_KS_release (key_state); +      return TALER_MHD_reply_with_error (connection, +                                         MHD_HTTP_FORBIDDEN, +                                         TALER_EC_REFRESH_MELT_DENOMINATION_SIGNATURE_INVALID, +                                         "denom_sig"); +    } +  } +  TEH_KS_release (key_state); + +  /* run actual logic, now that the request was parsed */ +  /* make sure coin is 'known' in database */ +  { +    struct TEH_DB_KnowCoinContext kcc; +    int mhd_ret; + +    kcc.coin = &rmc->refresh_session.coin; +    kcc.connection = connection; +    if (GNUNET_OK != +        TEH_DB_run_transaction (connection, +                                "know coin for refresh-melt", +                                &mhd_ret, +                                &TEH_DB_know_coin_transaction, +                                &kcc)) +      return mhd_ret; +  } + +  /* sanity-check that "total melt amount > melt fee" */ +  if (TALER_amount_cmp (&rmc->coin_refresh_fee, +                        &rmc->refresh_session.amount_with_fee) > 0) +  { +    GNUNET_break_op (0); +    return TALER_MHD_reply_with_error (connection, +                                       MHD_HTTP_BAD_REQUEST, +                                       TALER_EC_REFRESH_MELT_FEES_EXCEED_CONTRIBUTION, +                                       "melt amount smaller than melting fee"); +  } +  return handle_refresh_melt (connection, +                              rmc); +} + + +/**   * Handle a "/refresh/melt" request.  Parses the request into the JSON   * components and then hands things of to #handle_refresh_melt_json()   * to validate the melted coins, the signature and execute the melt @@ -463,9 +599,6 @@ TEH_REFRESH_handler_refresh_melt (struct TEH_RequestHandler *rh,    json_t *root;    struct RefreshMeltContext rmc;    int res; -  unsigned int hc; -  enum TALER_ErrorCode ec; -  struct TEH_KS_StateHandle *key_state;    struct GNUNET_JSON_Specification spec[] = {      GNUNET_JSON_spec_fixed_auto ("coin_pub",                                   &rmc.refresh_session.coin.coin_pub), @@ -504,143 +637,9 @@ TEH_REFRESH_handler_refresh_melt (struct TEH_RequestHandler *rh,    if (GNUNET_OK != res)      return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; -  key_state = TEH_KS_acquire (GNUNET_TIME_absolute_get ()); -  if (NULL == key_state) -  { -    TALER_LOG_ERROR ("Lacking keys to operate\n"); -    res = TALER_MHD_reply_with_error (connection, -                                      MHD_HTTP_INTERNAL_SERVER_ERROR, -                                      TALER_EC_EXCHANGE_BAD_CONFIGURATION, -                                      "no keys"); -    goto cleanup; -  } - -  /* Baseline: check if deposits/refreshs are generally -     simply still allowed for this denomination */ -  rmc.dki = TEH_KS_denomination_key_lookup_by_hash (key_state, -                                                    &rmc.refresh_session.coin. -                                                    denom_pub_hash, -                                                    TEH_KS_DKU_DEPOSIT, -                                                    &ec, -                                                    &hc); -  /* Consider case that denomination was revoked but -     this coin was already seen and thus refresh is OK. */ -  if (NULL == rmc.dki) -  { -    struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; - -    dki = TEH_KS_denomination_key_lookup_by_hash (key_state, -                                                  &rmc.refresh_session.coin. -                                                  denom_pub_hash, -                                                  TEH_KS_DKU_PAYBACK, -                                                  &ec, -                                                  &hc); -    if (NULL != dki) -    { -      struct TALER_CoinPublicInfo coin_info; -      enum GNUNET_DB_QueryStatus qs; - -      qs = TEH_plugin->get_known_coin (TEH_plugin->cls, -                                       NULL, -                                       &rmc.refresh_session.coin.coin_pub, -                                       &coin_info); -      if (0 > qs) -      { -        GNUNET_break (0); -        res = TALER_MHD_reply_with_error (connection, -                                          MHD_HTTP_INTERNAL_SERVER_ERROR, -                                          TALER_EC_REFRESH_MELT_DB_FETCH_ERROR, -                                          "failed to find information about old coin"); -        goto cleanup; -      } -      if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) -      { -        /* Coin was known beforehand, so we should allow the refresh */ -        rmc.dki = dki; -        GNUNET_CRYPTO_rsa_signature_free (coin_info.denom_sig.rsa_signature); -      } -    } -  } - -  /* Consider the case that the denomination expired for deposits, -     but /refresh/payback refilled the balance of the 'zombie' coin -     and we should thus allow the refresh during the legal period. */ -  if (NULL == rmc.dki) -  { -    struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; - -    dki = TEH_KS_denomination_key_lookup_by_hash (key_state, -                                                  &rmc.refresh_session.coin. -                                                  denom_pub_hash, -                                                  TEH_KS_DKU_ZOMBIE, -                                                  &ec, -                                                  &hc); -    if (NULL != dki) -    { -      rmc.dki = dki; -      rmc.zombie_required = GNUNET_YES; -    } -  } - -  if (NULL == rmc.dki) -  { -    TALER_LOG_WARNING ("Unknown denomination key in /refresh/melt request\n"); -    res = TALER_MHD_reply_with_error (connection, -                                      hc, -                                      ec, -                                      "unknown denomination"); -    goto cleanup; -  } - -  if (GNUNET_OK != -      TALER_test_coin_valid (&rmc.refresh_session.coin, -                             &rmc.dki->denom_pub)) -  { -    GNUNET_break_op (0); -    GNUNET_JSON_parse_free (spec); -    TEH_KS_release (key_state); -    return TALER_MHD_reply_with_error (connection, -                                       MHD_HTTP_FORBIDDEN, -                                       TALER_EC_REFRESH_MELT_DENOMINATION_SIGNATURE_INVALID, -                                       "denom_sig"); -  } - -  /* run actual logic, now that the request was parsed */ - -  /* make sure coin is 'known' in database */ -  { -    struct TEH_DB_KnowCoinContext kcc; -    int mhd_ret; - -    kcc.coin = &rmc.refresh_session.coin; -    kcc.connection = connection; -    if (GNUNET_OK != -        TEH_DB_run_transaction (connection, -                                "know coin for refresh-melt", -                                &mhd_ret, -                                &TEH_DB_know_coin_transaction, -                                &kcc)) -      return mhd_ret; -  } - -  res = handle_refresh_melt (connection, -                             &rmc); - - -cleanup: -  if (NULL != key_state) -  { -    TEH_KS_release (key_state); -    key_state = NULL; -  } -  if (NULL != rmc.refresh_session.coin.denom_sig.rsa_signature) -  { -    GNUNET_CRYPTO_rsa_signature_free ( -      rmc.refresh_session.coin.denom_sig.rsa_signature); -    rmc.refresh_session.coin.denom_sig.rsa_signature = NULL; -  } +  res = check_for_denomination_key (connection, +                                    &rmc);    GNUNET_JSON_parse_free (spec); -    return res;  } | 
