diff options
Diffstat (limited to 'src/lib/exchange_api_melt.c')
-rw-r--r-- | src/lib/exchange_api_melt.c | 296 |
1 files changed, 78 insertions, 218 deletions
diff --git a/src/lib/exchange_api_melt.c b/src/lib/exchange_api_melt.c index 80c759704..c2f8cefb7 100644 --- a/src/lib/exchange_api_melt.c +++ b/src/lib/exchange_api_melt.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2015-2022 Taler Systems SA + Copyright (C) 2015-2023 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 @@ -27,6 +27,7 @@ #include <gnunet/gnunet_curl_lib.h> #include "taler_json_lib.h" #include "taler_exchange_service.h" +#include "exchange_api_common.h" #include "exchange_api_handle.h" #include "taler_signatures.h" #include "exchange_api_curl_defaults.h" @@ -40,9 +41,9 @@ struct TALER_EXCHANGE_MeltHandle { /** - * The connection to exchange this request handle will use + * The keys of the this request handle will use */ - struct TALER_EXCHANGE_Handle *exchange; + struct TALER_EXCHANGE_Keys *keys; /** * The url for this request. @@ -50,6 +51,16 @@ struct TALER_EXCHANGE_MeltHandle char *url; /** + * The exchange base url. + */ + char *exchange_url; + + /** + * Curl context. + */ + struct GNUNET_CURL_Context *cctx; + + /** * Context for #TEH_curl_easy_post(). Keeps the data that must * persist for Curl to make the upload. */ @@ -102,6 +113,11 @@ struct TALER_EXCHANGE_MeltHandle struct TALER_CoinSpendPublicKeyP coin_pub; /** + * Signature affirming the melt. + */ + struct TALER_CoinSpendSignatureP coin_sig; + + /** * @brief Public information about the coin's denomination key */ const struct TALER_EXCHANGE_DenomPublicKey *dki; @@ -153,7 +169,7 @@ verify_melt_signature_ok (struct TALER_EXCHANGE_MeltHandle *mh, return GNUNET_SYSERR; } /* check that exchange signing key is permitted */ - key_state = TALER_EXCHANGE_get_keys (mh->exchange); + key_state = mh->keys; if (GNUNET_OK != TALER_EXCHANGE_test_signing_key (key_state, exchange_pub)) @@ -184,143 +200,6 @@ verify_melt_signature_ok (struct TALER_EXCHANGE_MeltHandle *mh, /** - * Verify that the signatures on the "409 CONFLICT" response from the - * exchange demonstrating customer denomination key differences - * resulting from coin private key reuse are valid. - * - * @param mh melt handle - * @param json json reply with the signature(s) and transaction history - * @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not - */ -static enum GNUNET_GenericReturnValue -verify_melt_signature_denom_conflict (struct TALER_EXCHANGE_MeltHandle *mh, - const json_t *json) - -{ - json_t *history; - struct TALER_Amount total; - struct TALER_DenominationHashP h_denom_pub; - - memset (&h_denom_pub, - 0, - sizeof (h_denom_pub)); - history = json_object_get (json, - "history"); - if (GNUNET_OK != - TALER_EXCHANGE_verify_coin_history (mh->dki, - mh->dki->value.currency, - &mh->coin_pub, - history, - &h_denom_pub, - &total)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (0 != GNUNET_memcmp (&mh->dki->h_key, - &h_denom_pub)) - return GNUNET_OK; /* indeed, proof with different denomination key provided */ - /* invalid proof provided */ - return GNUNET_SYSERR; -} - - -/** - * Verify that the signatures on the "409 CONFLICT" response from the - * exchange demonstrating customer double-spending are valid. - * - * @param mh melt handle - * @param json json reply with the signature(s) and transaction history - * @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not - */ -static enum GNUNET_GenericReturnValue -verify_melt_signature_spend_conflict (struct TALER_EXCHANGE_MeltHandle *mh, - const json_t *json) -{ - json_t *history; - struct TALER_Amount total; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_json ("history", - &history), - GNUNET_JSON_spec_end () - }; - const struct MeltedCoin *mc; - enum TALER_ErrorCode ec; - struct TALER_DenominationHashP h_denom_pub; - - /* parse JSON reply */ - if (GNUNET_OK != - GNUNET_JSON_parse (json, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - /* Find out which coin was deemed problematic by the exchange */ - mc = &mh->md.melted_coin; - /* verify coin history */ - memset (&h_denom_pub, - 0, - sizeof (h_denom_pub)); - history = json_object_get (json, - "history"); - if (GNUNET_OK != - TALER_EXCHANGE_verify_coin_history (mh->dki, - mc->original_value.currency, - &mh->coin_pub, - history, - &h_denom_pub, - &total)) - { - GNUNET_break_op (0); - json_decref (history); - return GNUNET_SYSERR; - } - json_decref (history); - - ec = TALER_JSON_get_error_code (json); - switch (ec) - { - case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS: - /* check if melt operation was really too expensive given history */ - if (0 > - TALER_amount_add (&total, - &total, - &mc->melt_amount_with_fee)) - { - /* clearly not OK if our transaction would have caused - the overflow... */ - return GNUNET_OK; - } - - if (0 >= TALER_amount_cmp (&total, - &mc->original_value)) - { - /* transaction should have still fit */ - GNUNET_break (0); - return GNUNET_SYSERR; - } - - /* everything OK, valid proof of double-spending was provided */ - return GNUNET_OK; - case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY: - if (0 != GNUNET_memcmp (&mh->dki->h_key, - &h_denom_pub)) - return GNUNET_OK; /* indeed, proof with different denomination key provided */ - /* invalid proof provided */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - default: - /* unexpected error code */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } -} - - -/** * Function called when we're done processing the * HTTP /coins/$COIN_PUB/melt request. * @@ -350,16 +229,16 @@ handle_melt_finished (void *cls, if (GNUNET_OK != verify_melt_signature_ok (mh, j, - &mr.details.success.sign_key)) + &mr.details.ok.sign_key)) { GNUNET_break_op (0); mr.hr.http_status = 0; mr.hr.ec = TALER_EC_EXCHANGE_MELT_INVALID_SIGNATURE_BY_EXCHANGE; break; } - mr.details.success.noreveal_index = mh->noreveal_index; - mr.details.success.num_mbds = mh->rd->fresh_pks_len; - mr.details.success.mbds = mh->mbds; + mr.details.ok.noreveal_index = mh->noreveal_index; + mr.details.ok.num_mbds = mh->rd->fresh_pks_len; + mr.details.ok.mbds = mh->mbds; mh->melt_cb (mh->melt_cb_cls, &mr); mh->melt_cb = NULL; @@ -372,38 +251,7 @@ handle_melt_finished (void *cls, break; case MHD_HTTP_CONFLICT: mr.hr.ec = TALER_JSON_get_error_code (j); - switch (mr.hr.ec) - { - case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS: - /* Double spending; check signatures on transaction history */ - if (GNUNET_OK != - verify_melt_signature_spend_conflict (mh, - j)) - { - GNUNET_break_op (0); - mr.hr.http_status = 0; - mr.hr.ec = TALER_EC_EXCHANGE_MELT_INVALID_SIGNATURE_BY_EXCHANGE; - mr.hr.hint = TALER_JSON_get_error_hint (j); - } - break; - case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY: - if (GNUNET_OK != - verify_melt_signature_denom_conflict (mh, - j)) - { - GNUNET_break_op (0); - mr.hr.http_status = 0; - mr.hr.ec = TALER_EC_EXCHANGE_MELT_INVALID_SIGNATURE_BY_EXCHANGE; - mr.hr.hint = TALER_JSON_get_error_hint (j); - } - break; - default: - GNUNET_break_op (0); - mr.hr.http_status = 0; - mr.hr.ec = TALER_EC_EXCHANGE_MELT_INVALID_SIGNATURE_BY_EXCHANGE; - mr.hr.hint = TALER_JSON_get_error_hint (j); - break; - } + mr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_FORBIDDEN: /* Nothing really to verify, exchange says one of the signatures is @@ -455,14 +303,18 @@ start_melt (struct TALER_EXCHANGE_MeltHandle *mh) const struct TALER_EXCHANGE_Keys *key_state; json_t *melt_obj; CURL *eh; - struct GNUNET_CURL_Context *ctx; - struct TALER_CoinSpendSignatureP confirm_sig; char arg_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2 + 32]; struct TALER_DenominationHashP h_denom_pub; struct TALER_ExchangeWithdrawValues alg_values[mh->rd->fresh_pks_len]; for (unsigned int i = 0; i<mh->rd->fresh_pks_len; i++) - alg_values[i] = mh->mbds[i].alg_value; + { + if (GNUNET_CRYPTO_BSA_RSA == + mh->rd->fresh_pks[i].key.bsign_pub_key->cipher) + alg_values[i] = *TALER_denom_ewv_rsa_singleton (); + else + alg_values[i] = mh->mbds[i].alg_value; + } if (GNUNET_OK != TALER_EXCHANGE_get_melt_data_ (&mh->rms, mh->rd, @@ -474,13 +326,14 @@ start_melt (struct TALER_EXCHANGE_MeltHandle *mh) } TALER_denom_pub_hash (&mh->md.melted_coin.pub_key, &h_denom_pub); - TALER_wallet_melt_sign (&mh->md.melted_coin.melt_amount_with_fee, - &mh->md.melted_coin.fee_melt, - &mh->md.rc, - &h_denom_pub, - mh->md.melted_coin.h_age_commitment, - &mh->md.melted_coin.coin_priv, - &confirm_sig); + TALER_wallet_melt_sign ( + &mh->md.melted_coin.melt_amount_with_fee, + &mh->md.melted_coin.fee_melt, + &mh->md.rc, + &h_denom_pub, + mh->md.melted_coin.h_age_commitment, + &mh->md.melted_coin.coin_priv, + &mh->coin_sig); GNUNET_CRYPTO_eddsa_key_get_public (&mh->md.melted_coin.coin_priv.eddsa_priv, &mh->coin_pub.eddsa_pub); melt_obj = GNUNET_JSON_PACK ( @@ -489,13 +342,13 @@ start_melt (struct TALER_EXCHANGE_MeltHandle *mh) TALER_JSON_pack_denom_sig ("denom_sig", &mh->md.melted_coin.sig), GNUNET_JSON_pack_data_auto ("confirm_sig", - &confirm_sig), + &mh->coin_sig), TALER_JSON_pack_amount ("value_with_fee", &mh->md.melted_coin.melt_amount_with_fee), GNUNET_JSON_pack_data_auto ("rc", &mh->md.rc), GNUNET_JSON_pack_allow_null ( - mh->md.melted_coin.h_age_commitment + (NULL != mh->md.melted_coin.h_age_commitment) ? GNUNET_JSON_pack_data_auto ("age_commitment_hash", mh->md.melted_coin.h_age_commitment) : GNUNET_JSON_pack_string ("age_commitment_hash", @@ -518,19 +371,19 @@ start_melt (struct TALER_EXCHANGE_MeltHandle *mh) *end = '\0'; GNUNET_snprintf (arg_str, sizeof (arg_str), - "/coins/%s/melt", + "coins/%s/melt", pub_str); } - ctx = TEAH_handle_to_context (mh->exchange); - key_state = TALER_EXCHANGE_get_keys (mh->exchange); + key_state = mh->keys; mh->dki = TALER_EXCHANGE_get_denomination_key (key_state, &mh->md.melted_coin.pub_key); /* and now we can at last begin the actual request handling */ - mh->url = TEAH_path_to_url (mh->exchange, - arg_str); + mh->url = TALER_url_join (mh->exchange_url, + arg_str, + NULL); if (NULL == mh->url) { json_decref (melt_obj); @@ -550,7 +403,7 @@ start_melt (struct TALER_EXCHANGE_MeltHandle *mh) return GNUNET_SYSERR; } json_decref (melt_obj); - mh->job = GNUNET_CURL_job_add2 (ctx, + mh->job = GNUNET_CURL_job_add2 (mh->cctx, eh, mh->ctx.headers, &handle_melt_finished, @@ -564,6 +417,7 @@ start_melt (struct TALER_EXCHANGE_MeltHandle *mh) * the application and cancel the operation. * * @param[in] mh melt request that failed + * @param ec error code to fail with */ static void fail_mh (struct TALER_EXCHANGE_MeltHandle *mh, @@ -612,19 +466,18 @@ csr_cb (void *cls, &mh->rd->fresh_pks[i]; struct TALER_ExchangeWithdrawValues *wv = &mh->mbds[i].alg_value; - switch (fresh_pk->key.cipher) + switch (fresh_pk->key.bsign_pub_key->cipher) { - case TALER_DENOMINATION_INVALID: + case GNUNET_CRYPTO_BSA_INVALID: GNUNET_break (0); fail_mh (mh, TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR); return; - case TALER_DENOMINATION_RSA: - GNUNET_assert (TALER_DENOMINATION_RSA == wv->cipher); + case GNUNET_CRYPTO_BSA_RSA: break; - case TALER_DENOMINATION_CS: - GNUNET_assert (TALER_DENOMINATION_CS == wv->cipher); - *wv = csrr->details.success.alg_values[nks_off]; + case GNUNET_CRYPTO_BSA_CS: + TALER_denom_ewv_copy (wv, + &csrr->details.ok.alg_values[nks_off]); nks_off++; break; } @@ -642,11 +495,14 @@ csr_cb (void *cls, struct TALER_EXCHANGE_MeltHandle * -TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange, - const struct TALER_RefreshMasterSecretP *rms, - const struct TALER_EXCHANGE_RefreshData *rd, - TALER_EXCHANGE_MeltCallback melt_cb, - void *melt_cb_cls) +TALER_EXCHANGE_melt ( + struct GNUNET_CURL_Context *ctx, + const char *url, + struct TALER_EXCHANGE_Keys *keys, + const struct TALER_RefreshMasterSecretP *rms, + const struct TALER_EXCHANGE_RefreshData *rd, + TALER_EXCHANGE_MeltCallback melt_cb, + void *melt_cb_cls) { struct TALER_EXCHANGE_NonceKey nks[GNUNET_NZL (rd->fresh_pks_len)]; unsigned int nks_off = 0; @@ -657,11 +513,10 @@ TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange, GNUNET_break (0); return NULL; } - GNUNET_assert (GNUNET_YES == - TEAH_handle_is_ready (exchange)); mh = GNUNET_new (struct TALER_EXCHANGE_MeltHandle); mh->noreveal_index = TALER_CNC_KAPPA; /* invalid value */ - mh->exchange = exchange; + mh->cctx = ctx; + mh->exchange_url = GNUNET_strdup (url); mh->rd = rd; mh->rms = *rms; mh->melt_cb = melt_cb; @@ -671,29 +526,30 @@ TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange, for (unsigned int i = 0; i<rd->fresh_pks_len; i++) { const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk = &rd->fresh_pks[i]; - struct TALER_ExchangeWithdrawValues *wv = &mh->mbds[i].alg_value; - switch (fresh_pk->key.cipher) + switch (fresh_pk->key.bsign_pub_key->cipher) { - case TALER_DENOMINATION_INVALID: + case GNUNET_CRYPTO_BSA_INVALID: GNUNET_break (0); GNUNET_free (mh->mbds); GNUNET_free (mh); return NULL; - case TALER_DENOMINATION_RSA: - wv->cipher = TALER_DENOMINATION_RSA; + case GNUNET_CRYPTO_BSA_RSA: + TALER_denom_ewv_copy (&mh->mbds[i].alg_value, + TALER_denom_ewv_rsa_singleton ()); break; - case TALER_DENOMINATION_CS: - wv->cipher = TALER_DENOMINATION_CS; + case GNUNET_CRYPTO_BSA_CS: nks[nks_off].pk = fresh_pk; nks[nks_off].cnc_num = nks_off; nks_off++; break; } } + mh->keys = TALER_EXCHANGE_keys_incref (keys); if (0 != nks_off) { - mh->csr = TALER_EXCHANGE_csr_melt (exchange, + mh->csr = TALER_EXCHANGE_csr_melt (ctx, + url, rms, nks_off, nks, @@ -721,6 +577,8 @@ TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange, void TALER_EXCHANGE_melt_cancel (struct TALER_EXCHANGE_MeltHandle *mh) { + for (unsigned int i = 0; i<mh->rd->fresh_pks_len; i++) + TALER_denom_ewv_free (&mh->mbds[i].alg_value); if (NULL != mh->job) { GNUNET_CURL_job_cancel (mh->job); @@ -734,7 +592,9 @@ TALER_EXCHANGE_melt_cancel (struct TALER_EXCHANGE_MeltHandle *mh) TALER_EXCHANGE_free_melt_data_ (&mh->md); /* does not free 'md' itself */ GNUNET_free (mh->mbds); GNUNET_free (mh->url); + GNUNET_free (mh->exchange_url); TALER_curl_easy_post_finished (&mh->ctx); + TALER_EXCHANGE_keys_decref (mh->keys); GNUNET_free (mh); } |