From a351bfc4b4ca15ce7fd998cf9691e85cf84dc426 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 17 Feb 2022 15:10:14 +0100 Subject: -fix CS nonce reuse check logic --- src/lib/Makefile.am | 3 +- src/lib/exchange_api_common.c | 21 ++- src/lib/exchange_api_csr.c | 322 -------------------------------- src/lib/exchange_api_csr_melt.c | 321 +++++++++++++++++++++++++++++++ src/lib/exchange_api_deposit.c | 8 +- src/lib/exchange_api_handle.c | 43 ++--- src/lib/exchange_api_melt.c | 36 ++-- src/lib/exchange_api_recoup.c | 2 +- src/lib/exchange_api_recoup_refresh.c | 2 +- src/lib/exchange_api_refresh_common.c | 10 +- src/lib/exchange_api_refreshes_reveal.c | 9 + src/lib/exchange_api_withdraw.c | 42 ++--- src/lib/exchange_api_withdraw2.c | 2 +- 13 files changed, 415 insertions(+), 406 deletions(-) delete mode 100644 src/lib/exchange_api_csr.c create mode 100644 src/lib/exchange_api_csr_melt.c (limited to 'src/lib') diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index fe2a0b6b1..17ad7937d 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -24,7 +24,8 @@ libtalerexchange_la_SOURCES = \ exchange_api_auditor_add_denomination.c \ exchange_api_curl_defaults.c exchange_api_curl_defaults.h \ exchange_api_common.c \ - exchange_api_csr.c \ + exchange_api_csr_melt.c \ + exchange_api_csr_withdraw.c \ exchange_api_handle.c exchange_api_handle.h \ exchange_api_deposit.c \ exchange_api_deposits_get.c \ diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c index d03409244..4f3e878d4 100644 --- a/src/lib/exchange_api_common.c +++ b/src/lib/exchange_api_common.c @@ -171,10 +171,10 @@ TALER_EXCHANGE_parse_reserve_history ( &h_denom_pub); if ( (GNUNET_YES != TALER_amount_cmp_currency (&withdraw_fee, - &dki->fee_withdraw)) || + &dki->fees.withdraw)) || (0 != TALER_amount_cmp (&withdraw_fee, - &dki->fee_withdraw)) ) + &dki->fees.withdraw)) ) { GNUNET_break_op (0); GNUNET_JSON_parse_free (withdraw_spec); @@ -529,10 +529,10 @@ TALER_EXCHANGE_verify_coin_history ( /* check that deposit fee matches our expectations from /keys! */ if ( (GNUNET_YES != TALER_amount_cmp_currency (&fee, - &dk->fee_deposit)) || + &dk->fees.deposit)) || (0 != TALER_amount_cmp (&fee, - &dk->fee_deposit)) ) + &dk->fees.deposit)) ) { GNUNET_break_op (0); return GNUNET_SYSERR; @@ -575,10 +575,10 @@ TALER_EXCHANGE_verify_coin_history ( /* check that melt fee matches our expectations from /keys! */ if ( (GNUNET_YES != TALER_amount_cmp_currency (&fee, - &dk->fee_refresh)) || + &dk->fees.refresh)) || (0 != TALER_amount_cmp (&fee, - &dk->fee_refresh)) ) + &dk->fees.refresh)) ) { GNUNET_break_op (0); return GNUNET_SYSERR; @@ -669,10 +669,10 @@ TALER_EXCHANGE_verify_coin_history ( { if ( (GNUNET_YES != TALER_amount_cmp_currency (&refund_fee, - &dk->fee_refund)) || + &dk->fees.refund)) || (0 != TALER_amount_cmp (&refund_fee, - &dk->fee_refund)) ) + &dk->fees.refund)) ) { GNUNET_break_op (0); return GNUNET_SYSERR; @@ -863,6 +863,11 @@ TALER_EXCHANGE_verify_coin_history ( } add = GNUNET_NO; } + else if (0 == strcasecmp (type, + "LOCK_NONCE")) + { + GNUNET_break (0); // FIXME: implement! + } else { /* signature not supported, new version on server? */ diff --git a/src/lib/exchange_api_csr.c b/src/lib/exchange_api_csr.c deleted file mode 100644 index 220dfba11..000000000 --- a/src/lib/exchange_api_csr.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - 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 - -*/ -/** - * @file lib/exchange_api_csr.c - * @brief Implementation of /csr requests (get R in exchange used for Clause Schnorr withdraw and refresh) - * @author Lucien Heuzeveldt - * @author Gian Demarmels - */ -#include "platform.h" -#include -#include /* just for HTTP status codes */ -#include -#include -#include -#include "taler_exchange_service.h" -#include "taler_json_lib.h" -#include "exchange_api_handle.h" -#include "taler_signatures.h" -#include "exchange_api_curl_defaults.h" - - -/** - * @brief A Clause Schnorr R Handle - */ -struct TALER_EXCHANGE_CsRHandle -{ - /** - * The connection to exchange this request handle will use - */ - struct TALER_EXCHANGE_Handle *exchange; - - /** - * Function to call with the result. - */ - TALER_EXCHANGE_CsRCallback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * The url for this request. - */ - char *url; - - /** - * Handle for the request. - */ - struct GNUNET_CURL_Job *job; - - /** - * Context for #TEH_curl_easy_post(). Keeps the data that must - * persist for Curl to make the upload. - */ - struct TALER_CURL_PostContext post_ctx; -}; - - -/** - * We got a 200 OK response for the /reserves/$RESERVE_PUB/withdraw operation. - * Extract the coin's signature and return it to the caller. The signature we - * get from the exchange is for the blinded value. Thus, we first must - * unblind it and then should verify its validity against our coin's hash. - * - * If everything checks out, we return the unblinded signature - * to the application via the callback. - * - * @param csrh operation handle - * @param arr reply from the exchange - * @param hr http response details - * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors - */ -static enum GNUNET_GenericReturnValue -csr_ok (struct TALER_EXCHANGE_CsRHandle *csrh, - json_t *arr, - struct TALER_EXCHANGE_HttpResponse *hr) -{ - unsigned int alen = json_array_size (arr); - struct TALER_ExchangeWithdrawValues alg_values[GNUNET_NZL (alen)]; - struct TALER_EXCHANGE_CsRResponse csrr = { - .hr = *hr, - .details.success.alg_values_len = alen, - .details.success.alg_values = alg_values - }; - - for (unsigned int i = 0; icb (csrh->cb_cls, - &csrr); - return GNUNET_OK; -} - - -/** - * Function called when we're done processing the HTTP /csr request. - * - * @param cls the `struct TALER_EXCHANGE_CsRHandle` - * @param response_code HTTP response code, 0 on error - * @param response parsed JSON result, NULL on error - */ -static void -handle_csr_finished (void *cls, - long response_code, - const void *response) -{ - struct TALER_EXCHANGE_CsRHandle *csrh = cls; - const json_t *j = response; - struct TALER_EXCHANGE_HttpResponse hr = { - .reply = j, - .http_status = (unsigned int) response_code - }; - struct TALER_EXCHANGE_CsRResponse csrr = { - .hr = hr - }; - - csrh->job = NULL; - switch (response_code) - { - case 0: - csrr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - break; - case MHD_HTTP_OK: - { - json_t *arr; - - arr = json_object_get (j, - "ewvs"); - if ( (NULL == arr) || - (0 == json_array_size (arr)) || - (GNUNET_OK != - csr_ok (csrh, - arr, - &hr)) ) - { - GNUNET_break_op (0); - csrr.hr.http_status = 0; - csrr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - } - TALER_EXCHANGE_csr_cancel (csrh); - return; - 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 */ - csrr.hr.ec = TALER_JSON_get_error_code (j); - csrr.hr.hint = TALER_JSON_get_error_hint (j); - break; - case MHD_HTTP_NOT_FOUND: - /* Nothing really to verify, the exchange basically just says - that it doesn't know the /csr endpoint or denomination. - Can happen if the exchange doesn't support Clause Schnorr. - We should simply pass the JSON reply to the application. */ - csrr.hr.ec = TALER_JSON_get_error_code (j); - csrr.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 */ - csrr.hr.ec = TALER_JSON_get_error_code (j); - csrr.hr.hint = TALER_JSON_get_error_hint (j); - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - csrr.hr.ec = TALER_JSON_get_error_code (j); - csrr.hr.hint = TALER_JSON_get_error_hint (j); - break; - default: - /* unexpected response code */ - GNUNET_break_op (0); - csrr.hr.ec = TALER_JSON_get_error_code (j); - csrr.hr.hint = TALER_JSON_get_error_hint (j); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d for CS R request\n", - (unsigned int) response_code, - (int) hr.ec); - break; - } - csrh->cb (csrh->cb_cls, - &csrr); - csrh->cb = NULL; - TALER_EXCHANGE_csr_cancel (csrh); -} - - -struct TALER_EXCHANGE_CsRHandle * -TALER_EXCHANGE_csr (struct TALER_EXCHANGE_Handle *exchange, - unsigned int nks_len, - struct TALER_EXCHANGE_NonceKey *nks, - TALER_EXCHANGE_CsRCallback res_cb, - void *res_cb_cls) -{ - struct TALER_EXCHANGE_CsRHandle *csrh; - json_t *csr_arr; - - if (0 == nks_len) - { - GNUNET_break (0); - return NULL; - } - for (unsigned int i = 0; ikey.cipher) - { - GNUNET_break (0); - return NULL; - } - - csrh = GNUNET_new (struct TALER_EXCHANGE_CsRHandle); - csrh->exchange = exchange; - csrh->cb = res_cb; - csrh->cb_cls = res_cb_cls; - - csr_arr = json_array (); - GNUNET_assert (NULL != csr_arr); - for (unsigned int i = 0; inonce, - sizeof(struct TALER_CsNonce)), - GNUNET_JSON_pack_data_varsize ("denom_pub_hash", - &nk->pk->h_key, - sizeof(struct TALER_DenominationHash))); - GNUNET_assert (NULL != csr_obj); - GNUNET_assert (0 == - json_array_append_new (csr_arr, - csr_obj)); - } - csrh->url = TEAH_path_to_url (exchange, - "/csr"); - if (NULL == csrh->url) - { - json_decref (csr_arr); - GNUNET_free (csrh); - return NULL; - } - { - CURL *eh; - struct GNUNET_CURL_Context *ctx; - json_t *req; - - req = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_array_steal ("nks", - csr_arr)); - ctx = TEAH_handle_to_context (exchange); - eh = TALER_EXCHANGE_curl_easy_get_ (csrh->url); - if ( (NULL == eh) || - (GNUNET_OK != - TALER_curl_easy_post (&csrh->post_ctx, - eh, - req)) ) - { - GNUNET_break (0); - if (NULL != eh) - curl_easy_cleanup (eh); - json_decref (req); - GNUNET_free (csrh->url); - GNUNET_free (csrh); - return NULL; - } - json_decref (req); - csrh->job = GNUNET_CURL_job_add2 (ctx, - eh, - csrh->post_ctx.headers, - &handle_csr_finished, - csrh); - } - return csrh; -} - - -void -TALER_EXCHANGE_csr_cancel (struct TALER_EXCHANGE_CsRHandle *csrh) -{ - if (NULL != csrh->job) - { - GNUNET_CURL_job_cancel (csrh->job); - csrh->job = NULL; - } - GNUNET_free (csrh->url); - TALER_curl_easy_post_finished (&csrh->post_ctx); - GNUNET_free (csrh); -} diff --git a/src/lib/exchange_api_csr_melt.c b/src/lib/exchange_api_csr_melt.c new file mode 100644 index 000000000..9de8cd8d9 --- /dev/null +++ b/src/lib/exchange_api_csr_melt.c @@ -0,0 +1,321 @@ +/* + 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 + +*/ +/** + * @file lib/exchange_api_csr_melt.c + * @brief Implementation of /csr-melt requests (get R in exchange used for Clause Schnorr refresh) + * @author Lucien Heuzeveldt + * @author Gian Demarmels + */ +#include "platform.h" +#include +#include /* just for HTTP status codes */ +#include +#include +#include +#include "taler_exchange_service.h" +#include "taler_json_lib.h" +#include "exchange_api_handle.h" +#include "taler_signatures.h" +#include "exchange_api_curl_defaults.h" + + +/** + * @brief A Clause Schnorr R Handle + */ +struct TALER_EXCHANGE_CsRMeltHandle +{ + /** + * The connection to exchange this request handle will use + */ + struct TALER_EXCHANGE_Handle *exchange; + + /** + * Function to call with the result. + */ + TALER_EXCHANGE_CsRMeltCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + + /** + * The url for this request. + */ + char *url; + + /** + * Handle for the request. + */ + struct GNUNET_CURL_Job *job; + + /** + * Context for #TEH_curl_easy_post(). Keeps the data that must + * persist for Curl to make the upload. + */ + struct TALER_CURL_PostContext post_ctx; +}; + + +/** + * We got a 200 OK response for the /reserves/$RESERVE_PUB/withdraw operation. + * Extract the coin's signature and return it to the caller. The signature we + * get from the exchange is for the blinded value. Thus, we first must + * unblind it and then should verify its validity against our coin's hash. + * + * If everything checks out, we return the unblinded signature + * to the application via the callback. + * + * @param csrh operation handle + * @param arr reply from the exchange + * @param hr http response details + * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors + */ +static enum GNUNET_GenericReturnValue +csr_ok (struct TALER_EXCHANGE_CsRMeltHandle *csrh, + const json_t *arr, + struct TALER_EXCHANGE_HttpResponse *hr) +{ + unsigned int alen = json_array_size (arr); + struct TALER_ExchangeWithdrawValues alg_values[GNUNET_NZL (alen)]; + struct TALER_EXCHANGE_CsRMeltResponse csrr = { + .hr = *hr, + .details.success.alg_values_len = alen, + .details.success.alg_values = alg_values + }; + + for (unsigned int i = 0; icb (csrh->cb_cls, + &csrr); + return GNUNET_OK; +} + + +/** + * Function called when we're done processing the HTTP /csr request. + * + * @param cls the `struct TALER_EXCHANGE_CsRMeltHandle` + * @param response_code HTTP response code, 0 on error + * @param response parsed JSON result, NULL on error + */ +static void +handle_csr_finished (void *cls, + long response_code, + const void *response) +{ + struct TALER_EXCHANGE_CsRMeltHandle *csrh = cls; + const json_t *j = response; + struct TALER_EXCHANGE_HttpResponse hr = { + .reply = j, + .http_status = (unsigned int) response_code + }; + struct TALER_EXCHANGE_CsRMeltResponse csrr = { + .hr = hr + }; + + csrh->job = NULL; + switch (response_code) + { + case 0: + csrr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + break; + case MHD_HTTP_OK: + { + json_t *arr; + + arr = json_object_get (j, + "ewvs"); + if ( (NULL == arr) || + (0 == json_array_size (arr)) || + (GNUNET_OK != + csr_ok (csrh, + arr, + &hr)) ) + { + GNUNET_break_op (0); + csrr.hr.http_status = 0; + csrr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + break; + } + } + TALER_EXCHANGE_csr_melt_cancel (csrh); + return; + 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 */ + csrr.hr.ec = TALER_JSON_get_error_code (j); + csrr.hr.hint = TALER_JSON_get_error_hint (j); + break; + case MHD_HTTP_NOT_FOUND: + /* Nothing really to verify, the exchange basically just says + that it doesn't know the /csr endpoint or denomination. + Can happen if the exchange doesn't support Clause Schnorr. + We should simply pass the JSON reply to the application. */ + csrr.hr.ec = TALER_JSON_get_error_code (j); + csrr.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 */ + csrr.hr.ec = TALER_JSON_get_error_code (j); + csrr.hr.hint = TALER_JSON_get_error_hint (j); + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + csrr.hr.ec = TALER_JSON_get_error_code (j); + csrr.hr.hint = TALER_JSON_get_error_hint (j); + break; + default: + /* unexpected response code */ + GNUNET_break_op (0); + csrr.hr.ec = TALER_JSON_get_error_code (j); + csrr.hr.hint = TALER_JSON_get_error_hint (j); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u/%d for CS R request\n", + (unsigned int) response_code, + (int) hr.ec); + break; + } + csrh->cb (csrh->cb_cls, + &csrr); + csrh->cb = NULL; + TALER_EXCHANGE_csr_melt_cancel (csrh); +} + + +struct TALER_EXCHANGE_CsRMeltHandle * +TALER_EXCHANGE_csr_melt (struct TALER_EXCHANGE_Handle *exchange, + const struct TALER_RefreshMasterSecretP *rms, + unsigned int nks_len, + struct TALER_EXCHANGE_NonceKey *nks, + TALER_EXCHANGE_CsRMeltCallback res_cb, + void *res_cb_cls) +{ + struct TALER_EXCHANGE_CsRMeltHandle *csrh; + json_t *csr_arr; + + if (0 == nks_len) + { + GNUNET_break (0); + return NULL; + } + for (unsigned int i = 0; ikey.cipher) + { + GNUNET_break (0); + return NULL; + } + csrh = GNUNET_new (struct TALER_EXCHANGE_CsRMeltHandle); + csrh->exchange = exchange; + csrh->cb = res_cb; + csrh->cb_cls = res_cb_cls; + csr_arr = json_array (); + GNUNET_assert (NULL != csr_arr); + for (unsigned int i = 0; icnc_num), + GNUNET_JSON_pack_data_auto ("denom_pub_hash", + &nk->pk->h_key)); + GNUNET_assert (NULL != csr_obj); + GNUNET_assert (0 == + json_array_append_new (csr_arr, + csr_obj)); + } + csrh->url = TEAH_path_to_url (exchange, + "/csr-melt"); + if (NULL == csrh->url) + { + json_decref (csr_arr); + GNUNET_free (csrh); + return NULL; + } + { + CURL *eh; + struct GNUNET_CURL_Context *ctx; + json_t *req; + + req = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_auto ("rms", + rms), + GNUNET_JSON_pack_array_steal ("nks", + csr_arr)); + ctx = TEAH_handle_to_context (exchange); + eh = TALER_EXCHANGE_curl_easy_get_ (csrh->url); + if ( (NULL == eh) || + (GNUNET_OK != + TALER_curl_easy_post (&csrh->post_ctx, + eh, + req)) ) + { + GNUNET_break (0); + if (NULL != eh) + curl_easy_cleanup (eh); + json_decref (req); + GNUNET_free (csrh->url); + GNUNET_free (csrh); + return NULL; + } + json_decref (req); + csrh->job = GNUNET_CURL_job_add2 (ctx, + eh, + csrh->post_ctx.headers, + &handle_csr_finished, + csrh); + } + return csrh; +} + + +void +TALER_EXCHANGE_csr_melt_cancel (struct TALER_EXCHANGE_CsRMeltHandle *csrh) +{ + if (NULL != csrh->job) + { + GNUNET_CURL_job_cancel (csrh->job); + csrh->job = NULL; + } + GNUNET_free (csrh->url); + TALER_curl_easy_post_finished (&csrh->post_ctx); + GNUNET_free (csrh); +} diff --git a/src/lib/exchange_api_deposit.c b/src/lib/exchange_api_deposit.c index 2bfaaf6ce..5a819461c 100644 --- a/src/lib/exchange_api_deposit.c +++ b/src/lib/exchange_api_deposit.c @@ -491,7 +491,7 @@ verify_signatures (const struct TALER_EXCHANGE_DenomPublicKey *dki, { if (GNUNET_OK != TALER_wallet_deposit_verify (amount, - &dki->fee_deposit, + &dki->fees.deposit, h_wire, h_contract_terms, h_age_commitment, @@ -508,7 +508,7 @@ verify_signatures (const struct TALER_EXCHANGE_DenomPublicKey *dki, TALER_LOG_DEBUG ("... amount_with_fee was %s\n", TALER_amount2s (amount)); TALER_LOG_DEBUG ("... deposit_fee was %s\n", - TALER_amount2s (&dki->fee_deposit)); + TALER_amount2s (&dki->fees.deposit)); return GNUNET_SYSERR; } @@ -536,7 +536,7 @@ verify_signatures (const struct TALER_EXCHANGE_DenomPublicKey *dki, } /* Check coin does make a contribution */ - if (0 < TALER_amount_cmp (&dki->fee_deposit, + if (0 < TALER_amount_cmp (&dki->fees.deposit, amount)) { GNUNET_break_op (0); @@ -628,7 +628,7 @@ TALER_EXCHANGE_deposit ( if (0 > TALER_amount_subtract (&amount_without_fee, amount, - &dki->fee_deposit)) + &dki->fees.deposit)) { *ec = TALER_EC_EXCHANGE_DEPOSIT_FEE_ABOVE_AMOUNT; GNUNET_break_op (0); diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c index 3243f5e95..ee5f44a00 100644 --- a/src/lib/exchange_api_handle.c +++ b/src/lib/exchange_api_handle.c @@ -305,6 +305,7 @@ parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key, /** * Parse a exchange's denomination key encoded in JSON. * + * @param currency expected currency of all fees * @param[out] denom_key where to return the result * @param check_sigs should we check signatures? * @param[in] denom_key_obj json to parse @@ -314,7 +315,8 @@ parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key, * invalid or the json malformed. */ static enum GNUNET_GenericReturnValue -parse_json_denomkey (struct TALER_EXCHANGE_DenomPublicKey *denom_key, +parse_json_denomkey (const char *currency, + struct TALER_EXCHANGE_DenomPublicKey *denom_key, int check_sigs, json_t *denom_key_obj, struct TALER_MasterPublicKeyP *master_key, @@ -331,16 +333,12 @@ parse_json_denomkey (struct TALER_EXCHANGE_DenomPublicKey *denom_key, &denom_key->valid_from), GNUNET_JSON_spec_timestamp ("stamp_expire_legal", &denom_key->expire_legal), - TALER_JSON_spec_amount_any ("value", - &denom_key->value), - TALER_JSON_spec_amount_any ("fee_withdraw", - &denom_key->fee_withdraw), - TALER_JSON_spec_amount_any ("fee_deposit", - &denom_key->fee_deposit), - TALER_JSON_spec_amount_any ("fee_refresh", - &denom_key->fee_refresh), - TALER_JSON_spec_amount_any ("fee_refund", - &denom_key->fee_refund), + TALER_JSON_spec_amount ("value", + currency, + &denom_key->value), + TALER_JSON_SPEC_DENOM_FEES ("fee", + currency, + &denom_key->fees), TALER_JSON_spec_denom_pub ("denom_pub", &denom_key->key), GNUNET_JSON_spec_end () @@ -372,10 +370,7 @@ parse_json_denomkey (struct TALER_EXCHANGE_DenomPublicKey *denom_key, denom_key->expire_deposit, denom_key->expire_legal, &denom_key->value, - &denom_key->fee_withdraw, - &denom_key->fee_deposit, - &denom_key->fee_refresh, - &denom_key->fee_refund, + &denom_key->fees, master_key, &denom_key->master_sig)); return GNUNET_OK; @@ -492,10 +487,7 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor, dk->expire_deposit, dk->expire_legal, &dk->value, - &dk->fee_withdraw, - &dk->fee_deposit, - &dk->fee_refresh, - &dk->fee_refund, + &dk->fees, &auditor->auditor_pub, &auditor_sig)) { @@ -883,7 +875,8 @@ decode_keys_json (const json_t *resp_obj, 0, sizeof (dk)); EXITIF (GNUNET_SYSERR == - parse_json_denomkey (&dk, + parse_json_denomkey (key_data->currency, + &dk, check_sig, denom_key_obj, &key_data->master_pub, @@ -1728,14 +1721,8 @@ TALER_EXCHANGE_serialize_data (struct TALER_EXCHANGE_Handle *exchange) dk->expire_legal), TALER_JSON_pack_amount ("value", &dk->value), - TALER_JSON_pack_amount ("fee_withdraw", - &dk->fee_withdraw), - TALER_JSON_pack_amount ("fee_deposit", - &dk->fee_deposit), - TALER_JSON_pack_amount ("fee_refresh", - &dk->fee_refresh), - TALER_JSON_pack_amount ("fee_refund", - &dk->fee_refund), + TALER_JSON_PACK_DENOM_FEES ("fee", + &dk->fees), GNUNET_JSON_pack_data_auto ("master_sig", &dk->master_sig), TALER_JSON_pack_denom_pub ("denom_pub", diff --git a/src/lib/exchange_api_melt.c b/src/lib/exchange_api_melt.c index 18596d891..71e6f55f0 100644 --- a/src/lib/exchange_api_melt.c +++ b/src/lib/exchange_api_melt.c @@ -94,7 +94,7 @@ struct TALER_EXCHANGE_MeltHandle /** * Handle for the preflight request, or NULL. */ - struct TALER_EXCHANGE_CsRHandle *csr; + struct TALER_EXCHANGE_CsRMeltHandle *csr; /** * Public key of the coin being melted. @@ -111,6 +111,10 @@ struct TALER_EXCHANGE_MeltHandle */ uint32_t noreveal_index; + /** + * True if we need to include @e rms in our melt request. + */ + bool send_rms; }; @@ -488,7 +492,13 @@ start_melt (struct TALER_EXCHANGE_MeltHandle *mh) TALER_JSON_pack_amount ("value_with_fee", &mh->md.melted_coin.melt_amount_with_fee), GNUNET_JSON_pack_data_auto ("rc", - &mh->md.rc)); + &mh->md.rc), + GNUNET_JSON_pack_allow_null ( + mh->send_rms + ? GNUNET_JSON_pack_data_auto ("rms", + &mh->rms) + : GNUNET_JSON_pack_string ("rms", + NULL))); { char pub_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2]; char *end; @@ -571,7 +581,7 @@ fail_mh (struct TALER_EXCHANGE_MeltHandle *mh, */ static void csr_cb (void *cls, - const struct TALER_EXCHANGE_CsRResponse *csrr) + const struct TALER_EXCHANGE_CsRMeltResponse *csrr) { struct TALER_EXCHANGE_MeltHandle *mh = cls; unsigned int nks_off = 0; @@ -583,7 +593,7 @@ csr_cb (void *cls, .hr = csrr->hr }; - mr.hr.hint = "/csr failed"; + mr.hr.hint = "/csr-melt failed"; mh->melt_cb (mh->melt_cb_cls, &mr); TALER_EXCHANGE_melt_cancel (mh); @@ -612,6 +622,7 @@ csr_cb (void *cls, break; } } + mh->send_rms = true; if (GNUNET_OK != start_melt (mh)) { @@ -668,20 +679,19 @@ TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange, case TALER_DENOMINATION_CS: wv->cipher = TALER_DENOMINATION_CS; nks[nks_off].pk = fresh_pk; - TALER_cs_refresh_nonce_derive (rms, - i, - &nks[nks_off].nonce); + nks[nks_off].cnc_num = nks_off; nks_off++; break; } } if (0 != nks_off) { - mh->csr = TALER_EXCHANGE_csr (exchange, - nks_off, - nks, - &csr_cb, - mh); + mh->csr = TALER_EXCHANGE_csr_melt (exchange, + rms, + nks_off, + nks, + &csr_cb, + mh); if (NULL == mh->csr) { GNUNET_break (0); @@ -711,7 +721,7 @@ TALER_EXCHANGE_melt_cancel (struct TALER_EXCHANGE_MeltHandle *mh) } if (NULL != mh->csr) { - TALER_EXCHANGE_csr_cancel (mh->csr); + TALER_EXCHANGE_csr_melt_cancel (mh->csr); mh->csr = NULL; } TALER_EXCHANGE_free_melt_data_ (&mh->md); /* does not free 'md' itself */ diff --git a/src/lib/exchange_api_recoup.c b/src/lib/exchange_api_recoup.c index 9b7201cd0..c94296c74 100644 --- a/src/lib/exchange_api_recoup.c +++ b/src/lib/exchange_api_recoup.c @@ -178,7 +178,7 @@ handle_recoup_finished (void *cls, "history"); if (GNUNET_OK != TALER_EXCHANGE_verify_coin_history (dki, - dki->fee_deposit.currency, + dki->fees.deposit.currency, &ph->coin_pub, history, &h_denom_pub, diff --git a/src/lib/exchange_api_recoup_refresh.c b/src/lib/exchange_api_recoup_refresh.c index 02e994155..0fff3a23b 100644 --- a/src/lib/exchange_api_recoup_refresh.c +++ b/src/lib/exchange_api_recoup_refresh.c @@ -192,7 +192,7 @@ handle_recoup_refresh_finished (void *cls, "history"); if (GNUNET_OK != TALER_EXCHANGE_verify_coin_history (dki, - dki->fee_deposit.currency, + dki->fees.deposit.currency, &ph->coin_pub, history, &h_denom_pub, diff --git a/src/lib/exchange_api_refresh_common.c b/src/lib/exchange_api_refresh_common.c index 89ee1e178..3cd47a6ff 100644 --- a/src/lib/exchange_api_refresh_common.c +++ b/src/lib/exchange_api_refresh_common.c @@ -64,6 +64,7 @@ TALER_EXCHANGE_get_melt_data_ ( struct TALER_Amount total; struct TALER_CoinSpendPublicKeyP coin_pub; struct TALER_CsNonce nonces[rd->fresh_pks_len]; + bool uses_cs = false; GNUNET_CRYPTO_eddsa_key_get_public (&rd->melt_priv.eddsa_priv, &coin_pub.eddsa_pub); @@ -74,7 +75,7 @@ TALER_EXCHANGE_get_melt_data_ ( md->num_fresh_coins = rd->fresh_pks_len; md->melted_coin.coin_priv = rd->melt_priv; md->melted_coin.melt_amount_with_fee = rd->melt_amount; - md->melted_coin.fee_melt = rd->melt_pk.fee_refresh; + md->melted_coin.fee_melt = rd->melt_pk.fees.refresh; md->melted_coin.original_value = rd->melt_pk.value; md->melted_coin.expire_deposit = rd->melt_pk.expire_deposit; GNUNET_assert (GNUNET_OK == @@ -98,6 +99,7 @@ TALER_EXCHANGE_get_melt_data_ ( } if (TALER_DENOMINATION_CS == alg_values[j].cipher) { + uses_cs = true; TALER_cs_refresh_nonce_derive ( rms, j, @@ -112,7 +114,7 @@ TALER_EXCHANGE_get_melt_data_ ( (0 > TALER_amount_add (&total, &total, - &rd->fresh_pks[j].fee_withdraw)) ) + &rd->fresh_pks[j].fees.withdraw)) ) { GNUNET_break (0); TALER_EXCHANGE_free_melt_data_ (md); @@ -139,6 +141,7 @@ TALER_EXCHANGE_get_melt_data_ ( TALER_planchet_secret_to_transfer_priv ( rms, + &rd->melt_priv, i, &md->transfer_priv[i]); GNUNET_CRYPTO_ecdhe_key_get_public ( @@ -199,6 +202,9 @@ TALER_EXCHANGE_get_melt_data_ ( } TALER_refresh_get_commitment (&md->rc, TALER_CNC_KAPPA, + uses_cs + ? rms + : NULL, rd->fresh_pks_len, rce, &coin_pub, diff --git a/src/lib/exchange_api_refreshes_reveal.c b/src/lib/exchange_api_refreshes_reveal.c index 8d04c279a..e87cae2ef 100644 --- a/src/lib/exchange_api_refreshes_reveal.c +++ b/src/lib/exchange_api_refreshes_reveal.c @@ -333,6 +333,7 @@ TALER_EXCHANGE_refreshes_reveal ( struct GNUNET_CURL_Context *ctx; struct MeltData md; char arg_str[sizeof (struct TALER_RefreshCommitmentP) * 2 + 32]; + bool send_rms = false; GNUNET_assert (num_coins == rd->fresh_pks_len); if (noreveal_index >= TALER_CNC_KAPPA) @@ -369,6 +370,8 @@ TALER_EXCHANGE_refreshes_reveal ( const struct TALER_RefreshCoinData *rcd = &md.rcd[noreveal_index][i]; struct TALER_DenominationHash denom_hash; + if (TALER_DENOMINATION_CS == md.fcds[i].fresh_pk.cipher) + send_rms = true; TALER_denom_pub_hash (&md.fcds[i].fresh_pk, &denom_hash); GNUNET_assert (0 == @@ -421,6 +424,12 @@ TALER_EXCHANGE_refreshes_reveal ( reveal_obj = GNUNET_JSON_PACK ( GNUNET_JSON_pack_data_auto ("transfer_pub", &md.transfer_pub[noreveal_index]), + GNUNET_JSON_pack_allow_null ( + send_rms + ? GNUNET_JSON_pack_data_auto ("rms", + rms) + : GNUNET_JSON_pack_string ("rms", + NULL)), GNUNET_JSON_pack_array_steal ("transfer_privs", transfer_privs), GNUNET_JSON_pack_array_steal ("link_sigs", diff --git a/src/lib/exchange_api_withdraw.c b/src/lib/exchange_api_withdraw.c index efc8a99c2..01b6e8bab 100644 --- a/src/lib/exchange_api_withdraw.c +++ b/src/lib/exchange_api_withdraw.c @@ -106,7 +106,7 @@ struct TALER_EXCHANGE_WithdrawHandle /** * Handler for the CS R request (only used for TALER_DENOMINATION_CS denominations) */ - struct TALER_EXCHANGE_CsRHandle *csrh; + struct TALER_EXCHANGE_CsRWithdrawHandle *csrh; }; @@ -192,11 +192,12 @@ handle_reserve_withdraw_finished ( * Function called when stage 1 of CS withdraw is finished (request r_pub's) * * @param cls the `struct TALER_EXCHANGE_WithdrawHandle` - * @param csrr replies from the /csr request + * @param csrr replies from the /csr-withdraw request */ static void -withdraw_cs_stage_two_callback (void *cls, - const struct TALER_EXCHANGE_CsRResponse *csrr) +withdraw_cs_stage_two_callback ( + void *cls, + const struct TALER_EXCHANGE_CsRWithdrawResponse *csrr) { struct TALER_EXCHANGE_WithdrawHandle *wh = cls; struct TALER_EXCHANGE_WithdrawResponse wr = { @@ -208,13 +209,7 @@ withdraw_cs_stage_two_callback (void *cls, switch (csrr->hr.http_status) { case MHD_HTTP_OK: - if (1 != csrr->details.success.alg_values_len) - { - GNUNET_break (0); - wr.hr.http_status = 0; - break; - } - wh->alg_values = csrr->details.success.alg_values[0]; + wh->alg_values = csrr->details.success.alg_values; TALER_planchet_setup_coin_priv (&wh->ps, &wh->alg_values, &wh->priv); @@ -306,22 +301,19 @@ TALER_EXCHANGE_withdraw ( } case TALER_DENOMINATION_CS: { - struct TALER_EXCHANGE_NonceKey nk = { - .pk = pk, - }; - - TALER_cs_withdraw_nonce_derive (ps, - &nk.nonce); + TALER_cs_withdraw_nonce_derive ( + ps, + &wh->pd.blinded_planchet.details.cs_blinded_planchet.nonce); /* Note that we only initialize the first half of the blinded_planchet here; the other part - will be done after the /csr request! */ + will be done after the /csr-withdraw request! */ wh->pd.blinded_planchet.cipher = TALER_DENOMINATION_CS; - wh->pd.blinded_planchet.details.cs_blinded_planchet.nonce = nk.nonce; - wh->csrh = TALER_EXCHANGE_csr (exchange, - 1, /* "array" length */ - &nk, - &withdraw_cs_stage_two_callback, - wh); + wh->csrh = TALER_EXCHANGE_csr_withdraw ( + exchange, + pk, + &wh->pd.blinded_planchet.details.cs_blinded_planchet.nonce, + &withdraw_cs_stage_two_callback, + wh); break; } default: @@ -339,7 +331,7 @@ TALER_EXCHANGE_withdraw_cancel (struct TALER_EXCHANGE_WithdrawHandle *wh) TALER_blinded_planchet_free (&wh->pd.blinded_planchet); if (NULL != wh->csrh) { - TALER_EXCHANGE_csr_cancel (wh->csrh); + TALER_EXCHANGE_csr_withdraw_cancel (wh->csrh); wh->csrh = NULL; } if (NULL != wh->wh2) diff --git a/src/lib/exchange_api_withdraw2.c b/src/lib/exchange_api_withdraw2.c index c0643b9af..2441a1417 100644 --- a/src/lib/exchange_api_withdraw2.c +++ b/src/lib/exchange_api_withdraw2.c @@ -403,7 +403,7 @@ TALER_EXCHANGE_withdraw2 ( if (0 > TALER_amount_add (&wh->requested_amount, &dk->value, - &dk->fee_withdraw)) + &dk->fees.withdraw)) { /* Overflow here? Very strange, our CPU must be fried... */ GNUNET_break (0); -- cgit v1.2.3