diff options
| -rw-r--r-- | src/auditor/taler-helper-auditor-coins.c | 53 | ||||
| -rw-r--r-- | src/auditor/taler-helper-auditor-reserves.c | 49 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_recoup.c | 45 | ||||
| -rw-r--r-- | src/exchangedb/exchange-0001.sql | 5 | ||||
| -rw-r--r-- | src/exchangedb/plugin_exchangedb_postgres.c | 4 | ||||
| -rw-r--r-- | src/exchangedb/test_exchangedb.c | 39 | ||||
| -rw-r--r-- | src/include/taler_crypto_lib.h | 57 | ||||
| -rw-r--r-- | src/include/taler_signatures.h | 11 | ||||
| -rw-r--r-- | src/lib/exchange_api_common.c | 46 | ||||
| -rw-r--r-- | src/lib/exchange_api_recoup.c | 30 | ||||
| -rw-r--r-- | src/testing/test_exchange_api.c | 2 | ||||
| -rw-r--r-- | src/testing/test_exchange_api_revocation.c | 20 | ||||
| -rw-r--r-- | src/util/wallet_signatures.c | 47 | 
13 files changed, 248 insertions, 160 deletions
| diff --git a/src/auditor/taler-helper-auditor-coins.c b/src/auditor/taler-helper-auditor-coins.c index 937613cc..393fc464 100644 --- a/src/auditor/taler-helper-auditor-coins.c +++ b/src/auditor/taler-helper-auditor-coins.c @@ -1983,38 +1983,29 @@ check_recoup (struct CoinContext *cc,      cc->qs = qs;      return GNUNET_SYSERR;    } +  if (GNUNET_OK != +      TALER_wallet_recoup_verify (&coin->denom_pub_hash, +                                  coin_blind, +                                  amount, +                                  &coin->coin_pub, +                                  coin_sig))    { -    struct TALER_RecoupRequestPS pr = { -      .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP), -      .purpose.size = htonl (sizeof (pr)), -      .coin_pub = coin->coin_pub, -      .coin_blind = *coin_blind, -      .h_denom_pub = coin->denom_pub_hash -    }; - -    if (GNUNET_OK != -        GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_RECOUP, -                                    &pr, -                                    &coin_sig->eddsa_signature, -                                    &coin->coin_pub.eddsa_pub)) -    { -      TALER_ARL_report (report_bad_sig_losses, -                        GNUNET_JSON_PACK ( -                          GNUNET_JSON_pack_string ("operation", -                                                   operation), -                          GNUNET_JSON_pack_uint64 ("row", -                                                   rowid), -                          TALER_JSON_pack_amount ("loss", -                                                  amount), -                          GNUNET_JSON_pack_data_auto ("coin_pub", -                                                      &coin->coin_pub))); -      TALER_ARL_amount_add (&total_bad_sig_loss, -                            &total_bad_sig_loss, -                            amount); -      if (TALER_ARL_do_abort ()) -        return GNUNET_SYSERR; -      return GNUNET_OK; -    } +    TALER_ARL_report (report_bad_sig_losses, +                      GNUNET_JSON_PACK ( +                        GNUNET_JSON_pack_string ("operation", +                                                 operation), +                        GNUNET_JSON_pack_uint64 ("row", +                                                 rowid), +                        TALER_JSON_pack_amount ("loss", +                                                amount), +                        GNUNET_JSON_pack_data_auto ("coin_pub", +                                                    &coin->coin_pub))); +    TALER_ARL_amount_add (&total_bad_sig_loss, +                          &total_bad_sig_loss, +                          amount); +    if (TALER_ARL_do_abort ()) +      return GNUNET_SYSERR; +    return GNUNET_OK;    }    ds = get_denomination_summary (cc,                                   issue, diff --git a/src/auditor/taler-helper-auditor-reserves.c b/src/auditor/taler-helper-auditor-reserves.c index 2ce12020..b6b969fe 100644 --- a/src/auditor/taler-helper-auditor-reserves.c +++ b/src/auditor/taler-helper-auditor-reserves.c @@ -684,7 +684,7 @@ handle_reserve_out (void *cls,   * @param coin_blind blinding factor used to blind the coin   * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop   */ -static int +static enum GNUNET_GenericReturnValue  handle_recoup_by_reserve (    void *cls,    uint64_t rowid, @@ -711,35 +711,26 @@ handle_recoup_by_reserve (    ppr.last_reserve_recoup_serial_id = rowid + 1;    /* We know that denom_pub matches denom_pub_hash because this       is how the SQL statement joined the tables. */ +  if (GNUNET_OK != +      TALER_wallet_recoup_verify (&coin->denom_pub_hash, +                                  coin_blind, +                                  amount, +                                  &coin->coin_pub, +                                  coin_sig))    { -    struct TALER_RecoupRequestPS pr = { -      .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP), -      .purpose.size = htonl (sizeof (pr)), -      .h_denom_pub = coin->denom_pub_hash, -      .coin_pub = coin->coin_pub, -      .coin_blind = *coin_blind -    }; - -    if (GNUNET_OK != -        GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_RECOUP, -                                    &pr, -                                    &coin_sig->eddsa_signature, -                                    &coin->coin_pub.eddsa_pub)) -    { -      TALER_ARL_report (report_bad_sig_losses, -                        GNUNET_JSON_PACK ( -                          GNUNET_JSON_pack_string ("operation", -                                                   "recoup"), -                          GNUNET_JSON_pack_uint64 ("row", -                                                   rowid), -                          TALER_JSON_pack_amount ("loss", -                                                  amount), -                          GNUNET_JSON_pack_data_auto ("key_pub", -                                                      &coin->coin_pub))); -      TALER_ARL_amount_add (&total_bad_sig_loss, -                            &total_bad_sig_loss, -                            amount); -    } +    TALER_ARL_report (report_bad_sig_losses, +                      GNUNET_JSON_PACK ( +                        GNUNET_JSON_pack_string ("operation", +                                                 "recoup"), +                        GNUNET_JSON_pack_uint64 ("row", +                                                 rowid), +                        TALER_JSON_pack_amount ("loss", +                                                amount), +                        GNUNET_JSON_pack_data_auto ("key_pub", +                                                    &coin->coin_pub))); +    TALER_ARL_amount_add (&total_bad_sig_loss, +                          &total_bad_sig_loss, +                          amount);    }    /* check that the coin was eligible for recoup!*/ diff --git a/src/exchange/taler-exchange-httpd_recoup.c b/src/exchange/taler-exchange-httpd_recoup.c index ec67efc2..58495e53 100644 --- a/src/exchange/taler-exchange-httpd_recoup.c +++ b/src/exchange/taler-exchange-httpd_recoup.c @@ -87,6 +87,7 @@ struct RecoupContext     * Set by #recoup_transaction() to the amount that will be paid back     */    struct TALER_Amount amount; +  const struct TALER_Amount *requested_amount;    /**     * Set by #recoup_transaction to the timestamp when the recoup @@ -234,6 +235,15 @@ recoup_transaction (void *cls,    TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,                                            tl);    pc->now = GNUNET_TIME_timestamp_get (); +  if (0 != TALER_amount_cmp (&pc->amount, +                             pc->requested_amount)) +  { +    *mhd_ret = TALER_MHD_reply_with_error (connection, +                                           MHD_HTTP_CONFLICT, +                                           TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS, +                                           TALER_amount2s (&pc->amount)); +    return GNUNET_DB_STATUS_HARD_ERROR; +  }    /* add coin to list of wire transfers for recoup */    if (pc->refreshed) @@ -284,6 +294,7 @@ recoup_transaction (void *cls,   * @param coin information about the coin   * @param coin_bks blinding data of the coin (to be checked)   * @param coin_sig signature of the coin + * @param requested_amount requested amount to be recouped   * @param refreshed true if the coin was refreshed   * @return MHD result code   */ @@ -293,6 +304,7 @@ verify_and_execute_recoup (    const struct TALER_CoinPublicInfo *coin,    const union TALER_DenominationBlindingKeyP *coin_bks,    const struct TALER_CoinSpendSignatureP *coin_sig, +  const struct TALER_Amount *requested_amount,    bool refreshed)  {    struct RecoupContext pc; @@ -352,27 +364,18 @@ verify_and_execute_recoup (    }    /* check recoup request signature */ +  if (GNUNET_OK != +      TALER_wallet_recoup_verify (&coin->denom_pub_hash, +                                  coin_bks, +                                  requested_amount, +                                  &coin->coin_pub, +                                  coin_sig))    { -    struct TALER_RecoupRequestPS pr = { -      .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP), -      .purpose.size = htonl (sizeof (pr)), -      .coin_pub = coin->coin_pub, -      .h_denom_pub = coin->denom_pub_hash, -      .coin_blind = *coin_bks -    }; - -    if (GNUNET_OK != -        GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_RECOUP, -                                    &pr, -                                    &coin_sig->eddsa_signature, -                                    &coin->coin_pub.eddsa_pub)) -    { -      TALER_LOG_WARNING ("Invalid signature on recoup request\n"); -      return TALER_MHD_reply_with_error (connection, -                                         MHD_HTTP_FORBIDDEN, -                                         TALER_EC_EXCHANGE_RECOUP_SIGNATURE_INVALID, -                                         NULL); -    } +    GNUNET_break_op (0); +    return TALER_MHD_reply_with_error (connection, +                                       MHD_HTTP_FORBIDDEN, +                                       TALER_EC_EXCHANGE_RECOUP_SIGNATURE_INVALID, +                                       NULL);    }    { @@ -404,6 +407,7 @@ verify_and_execute_recoup (    pc.coin_bks = coin_bks;    pc.coin = coin;    pc.refreshed = refreshed; +  pc.requested_amount = requested_amount;    {      MHD_RESULT mhd_ret = MHD_NO; @@ -552,6 +556,7 @@ TEH_handler_recoup (struct MHD_Connection *connection,                                       &coin,                                       &coin_bks,                                       &coin_sig, +                                     &amount,                                       refreshed);      GNUNET_JSON_parse_free (spec);      return res; diff --git a/src/exchangedb/exchange-0001.sql b/src/exchangedb/exchange-0001.sql index 1725b70e..a267fe13 100644 --- a/src/exchangedb/exchange-0001.sql +++ b/src/exchangedb/exchange-0001.sql @@ -697,8 +697,6 @@ CREATE INDEX IF NOT EXISTS revolving_work_shards_index  -- Stored procedures -DROP FUNCTION IF EXISTS exchange_do_withdraw(bigint,integer,bytea,bytea,bytea,bytea,bytea,bigint,bigint) ; -  CREATE OR REPLACE FUNCTION exchange_do_withdraw(    IN amount_val INT8,    IN amount_frac INT4, @@ -857,9 +855,6 @@ COMMENT ON FUNCTION exchange_do_withdraw(INT8, INT4, BYTEA, BYTEA, BYTEA, BYTEA, -DROP FUNCTION IF EXISTS exchange_do_withdraw_limit_check(bigint,bigint,bigint,int) ; - -  CREATE OR REPLACE FUNCTION exchange_do_withdraw_limit_check(    IN ruuid INT8,    IN start_time INT8, diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 23307bf8..99ebd7c7 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -3246,8 +3246,8 @@ postgres_get_denomination_info (                                                   rs);    if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)      return qs; -  issue->properties.purpose.size = htonl (sizeof (struct -                                                  TALER_DenominationKeyValidityPS)); +  issue->properties.purpose.size +    = htonl (sizeof (struct TALER_DenominationKeyValidityPS));    issue->properties.purpose.purpose = htonl (      TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY);    issue->properties.denom_hash = *denom_pub_hash; diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c index a8a9f3e1..65689d87 100644 --- a/src/exchangedb/test_exchangedb.c +++ b/src/exchangedb/test_exchangedb.c @@ -238,23 +238,26 @@ create_denom_key_pair (unsigned int size,            sizeof (struct TALER_EXCHANGEDB_DenominationKey));    dki.denom_pub = dkp->pub;    dki.issue.properties.start = GNUNET_TIME_timestamp_hton (now); -  dki.issue.properties.expire_withdraw = GNUNET_TIME_timestamp_hton -                                           (GNUNET_TIME_absolute_to_timestamp -                                             (GNUNET_TIME_absolute_add ( -                                               now.abs_time, -                                               GNUNET_TIME_UNIT_HOURS))); -  dki.issue.properties.expire_deposit = GNUNET_TIME_timestamp_hton ( -    GNUNET_TIME_absolute_to_timestamp -      (GNUNET_TIME_absolute_add -        (now.abs_time, -        GNUNET_TIME_relative_multiply ( -          GNUNET_TIME_UNIT_HOURS, 2)))); -  dki.issue.properties.expire_legal = GNUNET_TIME_timestamp_hton ( -    GNUNET_TIME_absolute_to_timestamp -      (GNUNET_TIME_absolute_add -        (now.abs_time, -        GNUNET_TIME_relative_multiply ( -          GNUNET_TIME_UNIT_HOURS, 3)))); +  dki.issue.properties.expire_withdraw +    = GNUNET_TIME_timestamp_hton +        (GNUNET_TIME_absolute_to_timestamp +          (GNUNET_TIME_absolute_add ( +            now.abs_time, +            GNUNET_TIME_UNIT_HOURS))); +  dki.issue.properties.expire_deposit +    = GNUNET_TIME_timestamp_hton ( +        GNUNET_TIME_absolute_to_timestamp +          (GNUNET_TIME_absolute_add +            (now.abs_time, +            GNUNET_TIME_relative_multiply ( +              GNUNET_TIME_UNIT_HOURS, 2)))); +  dki.issue.properties.expire_legal +    = GNUNET_TIME_timestamp_hton ( +        GNUNET_TIME_absolute_to_timestamp +          (GNUNET_TIME_absolute_add +            (now.abs_time, +            GNUNET_TIME_relative_multiply ( +              GNUNET_TIME_UNIT_HOURS, 3))));    TALER_amount_hton (&dki.issue.properties.value, value);    TALER_amount_hton (&dki.issue.properties.fee_withdraw, fee_withdraw);    TALER_amount_hton (&dki.issue.properties.fee_deposit, fee_deposit); @@ -276,6 +279,8 @@ create_denom_key_pair (unsigned int size,      destroy_denom_key_pair (dkp);      return NULL;    } +  memset (&issue2, 0, sizeof (issue2)); +  plugin->commit (plugin->cls);    if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=        plugin->get_denomination_info (plugin->cls,                                       &dki.issue.properties.denom_hash, diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h index 0a59ab9e..5292cd09 100644 --- a/src/include/taler_crypto_lib.h +++ b/src/include/taler_crypto_lib.h @@ -1738,6 +1738,63 @@ TALER_wallet_link_verify (    const struct TALER_CoinSpendPublicKeyP *old_coin_pub,    const struct TALER_CoinSpendSignatureP *coin_sig); + +/** + * Sign link data. + * + * @param h_denom_pub hash of the denomiantion public key of the new coin + * @param transfer_pub transfer public key + * @param coin_ev coin envelope + * @param coin_ev_size number of bytes in @a coin_ev + * @param old_coin_priv private key to sign with + * @param[out] coin_sig resulting signature + */ +void +TALER_wallet_link_sign (const struct TALER_DenominationHash *h_denom_pub, +                        const struct TALER_TransferPublicKeyP *transfer_pub, +                        const void *coin_ev, +                        size_t coin_ev_size, +                        const struct TALER_CoinSpendPrivateKeyP *old_coin_priv, +                        struct TALER_CoinSpendSignatureP *coin_sig); + + +/** + * Verify recoup signature. + * + * @param h_denom_pub hash of the denomiantion public key of the coin + * @param coin_bks blinding factor used when withdrawing the coin + * @param requested_amount amount that is left to be recouped + * @param coin_pub coin key of the coin to be recouped + * @param coin_sig resulting signature + * @return #GNUNET_OK if the signature is valid + */ +enum GNUNET_GenericReturnValue +TALER_wallet_recoup_verify ( +  const struct TALER_DenominationHash *h_denom_pub, +  const union TALER_DenominationBlindingKeyP *coin_bks, +  const struct TALER_Amount *requested_amount, +  const struct TALER_CoinSpendPublicKeyP *coin_pub, +  const struct TALER_CoinSpendSignatureP *coin_sig); + + +/** + * Create recoup signature. + * + * @param h_denom_pub hash of the denomiantion public key of the coin + * @param coin_bks blinding factor used when withdrawing the coin + * @param requested_amount amount that is left to be recouped + * @param coin_priv coin key of the coin to be recouped + * @param coin_sig resulting signature + */ +void +TALER_wallet_recoup_sign ( +  const struct TALER_DenominationHash *h_denom_pub, +  const union TALER_DenominationBlindingKeyP *coin_bks, +  const struct TALER_Amount *requested_amount, +  const struct TALER_CoinSpendPrivateKeyP *coin_priv, +  struct TALER_CoinSpendSignatureP *coin_sig); + +  /* ********************* offline signing ************************** */ diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h index 87a004e3..643aa80d 100644 --- a/src/include/taler_signatures.h +++ b/src/include/taler_signatures.h @@ -1497,11 +1497,6 @@ struct TALER_RecoupRequestPS    struct GNUNET_CRYPTO_EccSignaturePurpose purpose;    /** -   * Public key of the coin to be refunded. -   */ -  struct TALER_CoinSpendPublicKeyP coin_pub; - -  /**     * Hash of the (revoked) denomination public key of the coin.     */    struct TALER_DenominationHash h_denom_pub; @@ -1510,6 +1505,12 @@ struct TALER_RecoupRequestPS     * Blinding factor that was used to withdraw the coin.     */    union TALER_DenominationBlindingKeyP coin_blind; + +  /** +   * How much of the coin's value will be recouped? +   */ +  struct TALER_AmountNBO recoup_amount; +  }; diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c index b14714ac..93b992e6 100644 --- a/src/lib/exchange_api_common.c +++ b/src/lib/exchange_api_common.c @@ -688,17 +688,16 @@ TALER_EXCHANGE_verify_coin_history (          .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP),          .coin_pub = *coin_pub        }; -      struct TALER_RecoupRequestPS rr = { -        .purpose.size = htonl (sizeof (pc)), -        .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP), -        .coin_pub = *coin_pub -      }; +      union TALER_DenominationBlindingKeyP coin_bks; +      struct TALER_Amount recoup_amount;        struct TALER_ExchangePublicKeyP exchange_pub;        struct TALER_ExchangeSignatureP exchange_sig;        struct TALER_CoinSpendSignatureP coin_sig;        struct GNUNET_JSON_Specification spec[] = {          TALER_JSON_spec_amount_any_nbo ("amount",                                          &pc.recoup_amount), +        TALER_JSON_spec_amount_any ("amount", +                                    &recoup_amount),          GNUNET_JSON_spec_fixed_auto ("exchange_sig",                                       &exchange_sig),          GNUNET_JSON_spec_fixed_auto ("exchange_pub", @@ -708,9 +707,9 @@ TALER_EXCHANGE_verify_coin_history (          GNUNET_JSON_spec_fixed_auto ("coin_sig",                                       &coin_sig),          GNUNET_JSON_spec_fixed_auto ("coin_blind", -                                     &rr.coin_blind), +                                     &coin_bks),          GNUNET_JSON_spec_fixed_auto ("h_denom_pub", -                                     &rr.h_denom_pub), +                                     h_denom_pub),          GNUNET_JSON_spec_timestamp_nbo ("timestamp",                                          &pc.timestamp),          GNUNET_JSON_spec_end () @@ -736,15 +735,15 @@ TALER_EXCHANGE_verify_coin_history (          return GNUNET_SYSERR;        }        if (GNUNET_OK != -          GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_RECOUP, -                                      &rr, -                                      &coin_sig.eddsa_signature, -                                      &coin_pub->eddsa_pub)) +          TALER_wallet_recoup_verify (h_denom_pub, +                                      &coin_bks, +                                      &recoup_amount, +                                      coin_pub, +                                      &coin_sig))        {          GNUNET_break_op (0);          return GNUNET_SYSERR;        } -      *h_denom_pub = rr.h_denom_pub;        add = GNUNET_YES;      }      else if (0 == strcasecmp (type, @@ -758,17 +757,16 @@ TALER_EXCHANGE_verify_coin_history (            TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH),          .coin_pub = *coin_pub        }; -      struct TALER_RecoupRequestPS rr = { -        .purpose.size = htonl (sizeof (pc)), -        .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP), -        .coin_pub = *coin_pub -      }; +      union TALER_DenominationBlindingKeyP coin_bks; +      struct TALER_Amount recoup_amount;        struct TALER_ExchangePublicKeyP exchange_pub;        struct TALER_ExchangeSignatureP exchange_sig;        struct TALER_CoinSpendSignatureP coin_sig;        struct GNUNET_JSON_Specification spec[] = {          TALER_JSON_spec_amount_any_nbo ("amount",                                          &pc.recoup_amount), +        TALER_JSON_spec_amount_any ("amount", +                                    &recoup_amount),          GNUNET_JSON_spec_fixed_auto ("exchange_sig",                                       &exchange_sig),          GNUNET_JSON_spec_fixed_auto ("exchange_pub", @@ -778,9 +776,9 @@ TALER_EXCHANGE_verify_coin_history (          GNUNET_JSON_spec_fixed_auto ("old_coin_pub",                                       &pc.old_coin_pub),          GNUNET_JSON_spec_fixed_auto ("coin_blind", -                                     &rr.coin_blind), +                                     &coin_bks),          GNUNET_JSON_spec_fixed_auto ("h_denom_pub", -                                     &rr.h_denom_pub), +                                     h_denom_pub),          GNUNET_JSON_spec_timestamp_nbo ("timestamp",                                          &pc.timestamp),          GNUNET_JSON_spec_end () @@ -807,15 +805,15 @@ TALER_EXCHANGE_verify_coin_history (          return GNUNET_SYSERR;        }        if (GNUNET_OK != -          GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_RECOUP, -                                      &rr, -                                      &coin_sig.eddsa_signature, -                                      &coin_pub->eddsa_pub)) +          TALER_wallet_recoup_verify (h_denom_pub, +                                      &coin_bks, +                                      &recoup_amount, +                                      coin_pub, +                                      &coin_sig))        {          GNUNET_break_op (0);          return GNUNET_SYSERR;        } -      *h_denom_pub = rr.h_denom_pub;        add = GNUNET_YES;      }      else if (0 == strcasecmp (type, diff --git a/src/lib/exchange_api_recoup.c b/src/lib/exchange_api_recoup.c index 92b59f4b..05012926 100644 --- a/src/lib/exchange_api_recoup.c +++ b/src/lib/exchange_api_recoup.c @@ -95,7 +95,7 @@ struct TALER_EXCHANGE_RecoupHandle   * @return #GNUNET_OK if the signature is valid and we called the callback;   *         #GNUNET_SYSERR if not (callback must still be called)   */ -static int +static enum GNUNET_GenericReturnValue  process_recoup_response (const struct TALER_EXCHANGE_RecoupHandle *ph,                           const json_t *json)  { @@ -312,8 +312,8 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,  {    struct TALER_EXCHANGE_RecoupHandle *ph;    struct GNUNET_CURL_Context *ctx; -  struct TALER_RecoupRequestPS pr;    struct TALER_CoinSpendSignatureP coin_sig; +  struct TALER_CoinSpendPublicKeyP coin_pub;    struct TALER_DenominationHash h_denom_pub;    json_t *recoup_obj;    CURL *eh; @@ -321,17 +321,15 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,    GNUNET_assert (GNUNET_YES ==                   TEAH_handle_is_ready (exchange)); -  pr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP); -  pr.purpose.size = htonl (sizeof (struct TALER_RecoupRequestPS));    GNUNET_CRYPTO_eddsa_key_get_public (&ps->coin_priv.eddsa_priv, -                                      &pr.coin_pub.eddsa_pub); +                                      &coin_pub.eddsa_pub);    TALER_denom_pub_hash (&pk->key,                          &h_denom_pub); -  pr.h_denom_pub = pk->h_key; -  pr.coin_blind = ps->blinding_key; -  GNUNET_CRYPTO_eddsa_sign (&ps->coin_priv.eddsa_priv, -                            &pr, -                            &coin_sig.eddsa_signature); +  TALER_wallet_recoup_sign (&h_denom_pub, +                            &ps->blinding_key, +                            amount, +                            &ps->coin_priv, +                            &coin_sig);    recoup_obj = GNUNET_JSON_PACK (      GNUNET_JSON_pack_data_auto ("denom_pub_hash",                                  &h_denom_pub), @@ -349,11 +347,11 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,      char pub_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2];      char *end; -    end = GNUNET_STRINGS_data_to_string (&pr.coin_pub, -                                         sizeof (struct -                                                 TALER_CoinSpendPublicKeyP), -                                         pub_str, -                                         sizeof (pub_str)); +    end = GNUNET_STRINGS_data_to_string ( +      &coin_pub, +      sizeof (struct TALER_CoinSpendPublicKeyP), +      pub_str, +      sizeof (pub_str));      *end = '\0';      GNUNET_snprintf (arg_str,                       sizeof (arg_str), @@ -362,7 +360,7 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,    }    ph = GNUNET_new (struct TALER_EXCHANGE_RecoupHandle); -  ph->coin_pub = pr.coin_pub; +  ph->coin_pub = coin_pub;    ph->exchange = exchange;    ph->pk = *pk;    memset (&ph->pk.key, diff --git a/src/testing/test_exchange_api.c b/src/testing/test_exchange_api.c index 3e1df384..6dced3e3 100644 --- a/src/testing/test_exchange_api.c +++ b/src/testing/test_exchange_api.c @@ -855,7 +855,7 @@ run (void *cls,                                MHD_HTTP_OK,                                "recoup-withdraw-coin-2a",                                NULL, -                              NULL), +                              "EUR:0.5"),      TALER_TESTING_cmd_deposit ("recoup-deposit-revoked",                                 "recoup-withdraw-coin-2b",                                 0, diff --git a/src/testing/test_exchange_api_revocation.c b/src/testing/test_exchange_api_revocation.c index 9b66e20b..1a334a71 100644 --- a/src/testing/test_exchange_api_revocation.c +++ b/src/testing/test_exchange_api_revocation.c @@ -139,7 +139,7 @@ run (void *cls,                                MHD_HTTP_GONE,                                "refresh-reveal-1#0",                                "refresh-melt-1", -                              NULL), +                              "EUR:0.1"),      /* Make refreshed coin invalid */      TALER_TESTING_cmd_revoke ("revoke-2-EUR:5",                                MHD_HTTP_OK, @@ -155,44 +155,44 @@ run (void *cls,                                MHD_HTTP_CONFLICT,                                "withdraw-revocation-coin-2",                                NULL, -                              NULL), +                              "EUR:0.1"),      /* Refund coin to original coin */      TALER_TESTING_cmd_recoup ("recoup-1a",                                MHD_HTTP_OK,                                "refresh-reveal-1#0",                                "refresh-melt-1", -                              NULL), +                              "EUR:1"),      TALER_TESTING_cmd_recoup ("recoup-1b",                                MHD_HTTP_OK,                                "refresh-reveal-1#1",                                "refresh-melt-1", -                              NULL), +                              "EUR:1"),      TALER_TESTING_cmd_recoup ("recoup-1c",                                MHD_HTTP_OK,                                "refresh-reveal-1#2",                                "refresh-melt-1", -                              NULL), +                              "EUR:1"),      /* Repeat recoup to test idempotency */      TALER_TESTING_cmd_recoup ("recoup-1c",                                MHD_HTTP_OK,                                "refresh-reveal-1#2",                                "refresh-melt-1", -                              NULL), +                              "EUR:1"),      TALER_TESTING_cmd_recoup ("recoup-1c",                                MHD_HTTP_OK,                                "refresh-reveal-1#2",                                "refresh-melt-1", -                              NULL), +                              "EUR:1"),      TALER_TESTING_cmd_recoup ("recoup-1c",                                MHD_HTTP_OK,                                "refresh-reveal-1#2",                                "refresh-melt-1", -                              NULL), +                              "EUR:1"),      TALER_TESTING_cmd_recoup ("recoup-1c",                                MHD_HTTP_OK,                                "refresh-reveal-1#2",                                "refresh-melt-1", -                              NULL), +                              "EUR:1"),      /* Now we have EUR:3.83 EUR back after 3x EUR:1 in recoups */      /* Melt original coin AGAIN, but only create one 0.1 EUR coin;         This costs EUR:0.03 in refresh and EUR:01 in withdraw fees, @@ -223,7 +223,7 @@ run (void *cls,                                MHD_HTTP_OK,                                "refresh-reveal-2",                                "refresh-melt-2", -                              NULL), +                              "EUR:0.1"),      /* Due to recoup, original coin is now at EUR:3.79 */      /* Refund original (now zombie) coin to reserve */      TALER_TESTING_cmd_recoup ("recoup-3", diff --git a/src/util/wallet_signatures.c b/src/util/wallet_signatures.c index b895de14..81ce9cc5 100644 --- a/src/util/wallet_signatures.c +++ b/src/util/wallet_signatures.c @@ -155,4 +155,51 @@ TALER_wallet_link_verify (  } +enum GNUNET_GenericReturnValue +TALER_wallet_recoup_verify ( +  const struct TALER_DenominationHash *h_denom_pub, +  const union TALER_DenominationBlindingKeyP *coin_bks, +  const struct TALER_Amount *requested_amount, +  const struct TALER_CoinSpendPublicKeyP *coin_pub, +  const struct TALER_CoinSpendSignatureP *coin_sig) +{ +  struct TALER_RecoupRequestPS pr = { +    .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP), +    .purpose.size = htonl (sizeof (pr)), +    .h_denom_pub = *h_denom_pub, +    .coin_blind = *coin_bks +  }; + +  TALER_amount_hton (&pr.recoup_amount, +                     requested_amount); +  return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_RECOUP, +                                     &pr, +                                     &coin_sig->eddsa_signature, +                                     &coin_pub->eddsa_pub); +} + + +void +TALER_wallet_recoup_sign ( +  const struct TALER_DenominationHash *h_denom_pub, +  const union TALER_DenominationBlindingKeyP *coin_bks, +  const struct TALER_Amount *requested_amount, +  const struct TALER_CoinSpendPrivateKeyP *coin_priv, +  struct TALER_CoinSpendSignatureP *coin_sig) +{ +  struct TALER_RecoupRequestPS pr = { +    .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_RECOUP), +    .purpose.size = htonl (sizeof (struct TALER_RecoupRequestPS)), +    .h_denom_pub = *h_denom_pub, +    .coin_blind = *coin_bks +  }; + +  TALER_amount_hton (&pr.recoup_amount, +                     requested_amount); +  GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv, +                            &pr, +                            &coin_sig->eddsa_signature); +} + +  /* end of wallet_signatures.c */ | 
