LCOV - code coverage report
Current view: top level - lib - exchange_api_melt.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 0 226 0.0 %
Date: 2022-08-25 06:15:09 Functions: 0 7 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2015-2022 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU General Public License as published by the Free Software
       7             :   Foundation; either version 3, or (at your option) any later version.
       8             : 
       9             :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10             :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11             :   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU General Public License along with
      14             :   TALER; see the file COPYING.  If not, see
      15             :   <http://www.gnu.org/licenses/>
      16             : */
      17             : /**
      18             :  * @file lib/exchange_api_melt.c
      19             :  * @brief Implementation of the /coins/$COIN_PUB/melt request
      20             :  * @author Christian Grothoff
      21             :  */
      22             : #include "platform.h"
      23             : #include <jansson.h>
      24             : #include <microhttpd.h> /* just for HTTP status codes */
      25             : #include <gnunet/gnunet_util_lib.h>
      26             : #include <gnunet/gnunet_json_lib.h>
      27             : #include <gnunet/gnunet_curl_lib.h>
      28             : #include "taler_json_lib.h"
      29             : #include "taler_exchange_service.h"
      30             : #include "exchange_api_common.h"
      31             : #include "exchange_api_handle.h"
      32             : #include "taler_signatures.h"
      33             : #include "exchange_api_curl_defaults.h"
      34             : #include "exchange_api_refresh_common.h"
      35             : 
      36             : 
      37             : /**
      38             :  * @brief A /coins/$COIN_PUB/melt Handle
      39             :  */
      40             : struct TALER_EXCHANGE_MeltHandle
      41             : {
      42             : 
      43             :   /**
      44             :    * The connection to exchange this request handle will use
      45             :    */
      46             :   struct TALER_EXCHANGE_Handle *exchange;
      47             : 
      48             :   /**
      49             :    * The url for this request.
      50             :    */
      51             :   char *url;
      52             : 
      53             :   /**
      54             :    * Context for #TEH_curl_easy_post(). Keeps the data that must
      55             :    * persist for Curl to make the upload.
      56             :    */
      57             :   struct TALER_CURL_PostContext ctx;
      58             : 
      59             :   /**
      60             :    * Handle for the request.
      61             :    */
      62             :   struct GNUNET_CURL_Job *job;
      63             : 
      64             :   /**
      65             :    * Function to call with refresh melt failure results.
      66             :    */
      67             :   TALER_EXCHANGE_MeltCallback melt_cb;
      68             : 
      69             :   /**
      70             :    * Closure for @e result_cb and @e melt_failure_cb.
      71             :    */
      72             :   void *melt_cb_cls;
      73             : 
      74             :   /**
      75             :    * Actual information about the melt operation.
      76             :    */
      77             :   struct MeltData md;
      78             : 
      79             :   /**
      80             :    * The secret the entire melt operation is seeded from.
      81             :    */
      82             :   struct TALER_RefreshMasterSecretP rms;
      83             : 
      84             :   /**
      85             :    * Details about the characteristics of the requested melt operation.
      86             :    */
      87             :   const struct TALER_EXCHANGE_RefreshData *rd;
      88             : 
      89             :   /**
      90             :    * Array of `num_fresh_coins` per-coin values
      91             :    * returned from melt operation.
      92             :    */
      93             :   struct TALER_EXCHANGE_MeltBlindingDetail *mbds;
      94             : 
      95             :   /**
      96             :    * Handle for the preflight request, or NULL.
      97             :    */
      98             :   struct TALER_EXCHANGE_CsRMeltHandle *csr;
      99             : 
     100             :   /**
     101             :    * Public key of the coin being melted.
     102             :    */
     103             :   struct TALER_CoinSpendPublicKeyP coin_pub;
     104             : 
     105             :   /**
     106             :    * Signature affirming the melt.
     107             :    */
     108             :   struct TALER_CoinSpendSignatureP coin_sig;
     109             : 
     110             :   /**
     111             :    * @brief Public information about the coin's denomination key
     112             :    */
     113             :   const struct TALER_EXCHANGE_DenomPublicKey *dki;
     114             : 
     115             :   /**
     116             :    * Gamma value chosen by the exchange during melt.
     117             :    */
     118             :   uint32_t noreveal_index;
     119             : 
     120             :   /**
     121             :    * True if we need to include @e rms in our melt request.
     122             :    */
     123             :   bool send_rms;
     124             : };
     125             : 
     126             : 
     127             : /**
     128             :  * Verify that the signature on the "200 OK" response
     129             :  * from the exchange is valid.
     130             :  *
     131             :  * @param[in,out] mh melt handle
     132             :  * @param json json reply with the signature
     133             :  * @param[out] exchange_pub public key of the exchange used for the signature
     134             :  * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
     135             :  */
     136             : static enum GNUNET_GenericReturnValue
     137           0 : verify_melt_signature_ok (struct TALER_EXCHANGE_MeltHandle *mh,
     138             :                           const json_t *json,
     139             :                           struct TALER_ExchangePublicKeyP *exchange_pub)
     140             : {
     141             :   struct TALER_ExchangeSignatureP exchange_sig;
     142             :   const struct TALER_EXCHANGE_Keys *key_state;
     143             :   struct GNUNET_JSON_Specification spec[] = {
     144           0 :     GNUNET_JSON_spec_fixed_auto ("exchange_sig",
     145             :                                  &exchange_sig),
     146           0 :     GNUNET_JSON_spec_fixed_auto ("exchange_pub",
     147             :                                  exchange_pub),
     148           0 :     GNUNET_JSON_spec_uint32 ("noreveal_index",
     149             :                              &mh->noreveal_index),
     150           0 :     GNUNET_JSON_spec_end ()
     151             :   };
     152             : 
     153           0 :   if (GNUNET_OK !=
     154           0 :       GNUNET_JSON_parse (json,
     155             :                          spec,
     156             :                          NULL, NULL))
     157             :   {
     158           0 :     GNUNET_break_op (0);
     159           0 :     return GNUNET_SYSERR;
     160             :   }
     161             :   /* check that exchange signing key is permitted */
     162           0 :   key_state = TALER_EXCHANGE_get_keys (mh->exchange);
     163           0 :   if (GNUNET_OK !=
     164           0 :       TALER_EXCHANGE_test_signing_key (key_state,
     165             :                                        exchange_pub))
     166             :   {
     167           0 :     GNUNET_break_op (0);
     168           0 :     return GNUNET_SYSERR;
     169             :   }
     170             : 
     171             :   /* check that noreveal index is in permitted range */
     172           0 :   if (TALER_CNC_KAPPA <= mh->noreveal_index)
     173             :   {
     174           0 :     GNUNET_break_op (0);
     175           0 :     return GNUNET_SYSERR;
     176             :   }
     177             : 
     178           0 :   if (GNUNET_OK !=
     179           0 :       TALER_exchange_online_melt_confirmation_verify (
     180           0 :         &mh->md.rc,
     181             :         mh->noreveal_index,
     182             :         exchange_pub,
     183             :         &exchange_sig))
     184             :   {
     185           0 :     GNUNET_break_op (0);
     186           0 :     return GNUNET_SYSERR;
     187             :   }
     188           0 :   return GNUNET_OK;
     189             : }
     190             : 
     191             : 
     192             : /**
     193             :  * Function called when we're done processing the
     194             :  * HTTP /coins/$COIN_PUB/melt request.
     195             :  *
     196             :  * @param cls the `struct TALER_EXCHANGE_MeltHandle`
     197             :  * @param response_code HTTP response code, 0 on error
     198             :  * @param response parsed JSON result, NULL on error
     199             :  */
     200             : static void
     201           0 : handle_melt_finished (void *cls,
     202             :                       long response_code,
     203             :                       const void *response)
     204             : {
     205           0 :   struct TALER_EXCHANGE_MeltHandle *mh = cls;
     206           0 :   const json_t *j = response;
     207           0 :   struct TALER_EXCHANGE_MeltResponse mr = {
     208             :     .hr.reply = j,
     209           0 :     .hr.http_status = (unsigned int) response_code
     210             :   };
     211             :   const struct TALER_EXCHANGE_Keys *keys;
     212             : 
     213           0 :   mh->job = NULL;
     214           0 :   keys = TALER_EXCHANGE_get_keys (mh->exchange);
     215           0 :   switch (response_code)
     216             :   {
     217           0 :   case 0:
     218           0 :     mr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     219           0 :     break;
     220           0 :   case MHD_HTTP_OK:
     221           0 :     if (GNUNET_OK !=
     222           0 :         verify_melt_signature_ok (mh,
     223             :                                   j,
     224             :                                   &mr.details.success.sign_key))
     225             :     {
     226           0 :       GNUNET_break_op (0);
     227           0 :       mr.hr.http_status = 0;
     228           0 :       mr.hr.ec = TALER_EC_EXCHANGE_MELT_INVALID_SIGNATURE_BY_EXCHANGE;
     229           0 :       break;
     230             :     }
     231           0 :     mr.details.success.noreveal_index = mh->noreveal_index;
     232           0 :     mr.details.success.num_mbds = mh->rd->fresh_pks_len;
     233           0 :     mr.details.success.mbds = mh->mbds;
     234           0 :     mh->melt_cb (mh->melt_cb_cls,
     235             :                  &mr);
     236           0 :     mh->melt_cb = NULL;
     237           0 :     break;
     238           0 :   case MHD_HTTP_BAD_REQUEST:
     239             :     /* This should never happen, either us or the exchange is buggy
     240             :        (or API version conflict); just pass JSON reply to the application */
     241           0 :     mr.hr.ec = TALER_JSON_get_error_code (j);
     242           0 :     mr.hr.hint = TALER_JSON_get_error_hint (j);
     243           0 :     break;
     244           0 :   case MHD_HTTP_CONFLICT:
     245           0 :     mr.hr.ec = TALER_JSON_get_error_code (j);
     246           0 :     mr.hr.hint = TALER_JSON_get_error_hint (j);
     247           0 :     if (GNUNET_OK !=
     248           0 :         TALER_EXCHANGE_check_coin_conflict_ (
     249             :           keys,
     250             :           j,
     251             :           mh->dki,
     252           0 :           &mh->coin_pub,
     253           0 :           &mh->coin_sig,
     254           0 :           &mh->md.melted_coin.melt_amount_with_fee))
     255             :     {
     256           0 :       GNUNET_break_op (0);
     257           0 :       mr.hr.http_status = 0;
     258           0 :       mr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     259           0 :       break;
     260             :     }
     261           0 :     break;
     262           0 :   case MHD_HTTP_FORBIDDEN:
     263             :     /* Nothing really to verify, exchange says one of the signatures is
     264             :        invalid; assuming we checked them, this should never happen, we
     265             :        should pass the JSON reply to the application */
     266           0 :     mr.hr.ec = TALER_JSON_get_error_code (j);
     267           0 :     mr.hr.hint = TALER_JSON_get_error_hint (j);
     268           0 :     break;
     269           0 :   case MHD_HTTP_NOT_FOUND:
     270             :     /* Nothing really to verify, this should never
     271             :        happen, we should pass the JSON reply to the application */
     272           0 :     mr.hr.ec = TALER_JSON_get_error_code (j);
     273           0 :     mr.hr.hint = TALER_JSON_get_error_hint (j);
     274           0 :     break;
     275           0 :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     276             :     /* Server had an internal issue; we should retry, but this API
     277             :        leaves this to the application */
     278           0 :     mr.hr.ec = TALER_JSON_get_error_code (j);
     279           0 :     mr.hr.hint = TALER_JSON_get_error_hint (j);
     280           0 :     break;
     281           0 :   default:
     282             :     /* unexpected response code */
     283           0 :     mr.hr.ec = TALER_JSON_get_error_code (j);
     284           0 :     mr.hr.hint = TALER_JSON_get_error_hint (j);
     285           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     286             :                 "Unexpected response code %u/%d for exchange melt\n",
     287             :                 (unsigned int) response_code,
     288             :                 mr.hr.ec);
     289           0 :     GNUNET_break_op (0);
     290           0 :     break;
     291             :   }
     292           0 :   if (NULL != mh->melt_cb)
     293           0 :     mh->melt_cb (mh->melt_cb_cls,
     294             :                  &mr);
     295           0 :   TALER_EXCHANGE_melt_cancel (mh);
     296           0 : }
     297             : 
     298             : 
     299             : /**
     300             :  * Start the actual melt operation, now that we have
     301             :  * the exchange's input values.
     302             :  *
     303             :  * @param[in,out] mh melt operation to run
     304             :  * @return #GNUNET_OK if we could start the operation
     305             :  */
     306             : static enum GNUNET_GenericReturnValue
     307           0 : start_melt (struct TALER_EXCHANGE_MeltHandle *mh)
     308           0 : {
     309             :   const struct TALER_EXCHANGE_Keys *key_state;
     310             :   json_t *melt_obj;
     311             :   CURL *eh;
     312             :   struct GNUNET_CURL_Context *ctx;
     313             :   char arg_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2 + 32];
     314             :   struct TALER_DenominationHashP h_denom_pub;
     315           0 :   struct TALER_ExchangeWithdrawValues alg_values[mh->rd->fresh_pks_len];
     316             : 
     317           0 :   for (unsigned int i = 0; i<mh->rd->fresh_pks_len; i++)
     318           0 :     alg_values[i] = mh->mbds[i].alg_value;
     319           0 :   if (GNUNET_OK !=
     320           0 :       TALER_EXCHANGE_get_melt_data_ (&mh->rms,
     321             :                                      mh->rd,
     322             :                                      alg_values,
     323             :                                      &mh->md))
     324             :   {
     325           0 :     GNUNET_break (0);
     326           0 :     return GNUNET_SYSERR;
     327             :   }
     328           0 :   TALER_denom_pub_hash (&mh->md.melted_coin.pub_key,
     329             :                         &h_denom_pub);
     330           0 :   TALER_wallet_melt_sign (&mh->md.melted_coin.melt_amount_with_fee,
     331           0 :                           &mh->md.melted_coin.fee_melt,
     332           0 :                           &mh->md.rc,
     333             :                           &h_denom_pub,
     334             :                           mh->md.melted_coin.h_age_commitment,
     335           0 :                           &mh->md.melted_coin.coin_priv,
     336             :                           &mh->coin_sig);
     337           0 :   GNUNET_CRYPTO_eddsa_key_get_public (&mh->md.melted_coin.coin_priv.eddsa_priv,
     338             :                                       &mh->coin_pub.eddsa_pub);
     339           0 :   melt_obj = GNUNET_JSON_PACK (
     340             :     GNUNET_JSON_pack_data_auto ("denom_pub_hash",
     341             :                                 &h_denom_pub),
     342             :     TALER_JSON_pack_denom_sig ("denom_sig",
     343             :                                &mh->md.melted_coin.sig),
     344             :     GNUNET_JSON_pack_data_auto ("confirm_sig",
     345             :                                 &mh->coin_sig),
     346             :     TALER_JSON_pack_amount ("value_with_fee",
     347             :                             &mh->md.melted_coin.melt_amount_with_fee),
     348             :     GNUNET_JSON_pack_data_auto ("rc",
     349             :                                 &mh->md.rc),
     350             :     GNUNET_JSON_pack_allow_null (
     351             :       mh->md.melted_coin.h_age_commitment
     352             :       ? GNUNET_JSON_pack_data_auto ("age_commitment_hash",
     353             :                                     mh->md.melted_coin.h_age_commitment)
     354             :       : GNUNET_JSON_pack_string ("age_commitment_hash",
     355             :                                  NULL)),
     356             :     GNUNET_JSON_pack_allow_null (
     357             :       mh->send_rms
     358             :       ? GNUNET_JSON_pack_data_auto ("rms",
     359             :                                     &mh->rms)
     360             :       : GNUNET_JSON_pack_string ("rms",
     361             :                                  NULL)));
     362             :   {
     363             :     char pub_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2];
     364             :     char *end;
     365             : 
     366           0 :     end = GNUNET_STRINGS_data_to_string (
     367           0 :       &mh->coin_pub,
     368             :       sizeof (struct TALER_CoinSpendPublicKeyP),
     369             :       pub_str,
     370             :       sizeof (pub_str));
     371           0 :     *end = '\0';
     372           0 :     GNUNET_snprintf (arg_str,
     373             :                      sizeof (arg_str),
     374             :                      "/coins/%s/melt",
     375             :                      pub_str);
     376             :   }
     377             : 
     378           0 :   ctx = TEAH_handle_to_context (mh->exchange);
     379           0 :   key_state = TALER_EXCHANGE_get_keys (mh->exchange);
     380           0 :   mh->dki = TALER_EXCHANGE_get_denomination_key (key_state,
     381           0 :                                                  &mh->md.melted_coin.pub_key);
     382             : 
     383             :   /* and now we can at last begin the actual request handling */
     384             : 
     385           0 :   mh->url = TEAH_path_to_url (mh->exchange,
     386             :                               arg_str);
     387           0 :   if (NULL == mh->url)
     388             :   {
     389           0 :     json_decref (melt_obj);
     390           0 :     return GNUNET_SYSERR;
     391             :   }
     392           0 :   eh = TALER_EXCHANGE_curl_easy_get_ (mh->url);
     393           0 :   if ( (NULL == eh) ||
     394             :        (GNUNET_OK !=
     395           0 :         TALER_curl_easy_post (&mh->ctx,
     396             :                               eh,
     397             :                               melt_obj)) )
     398             :   {
     399           0 :     GNUNET_break (0);
     400           0 :     if (NULL != eh)
     401           0 :       curl_easy_cleanup (eh);
     402           0 :     json_decref (melt_obj);
     403           0 :     return GNUNET_SYSERR;
     404             :   }
     405           0 :   json_decref (melt_obj);
     406           0 :   mh->job = GNUNET_CURL_job_add2 (ctx,
     407             :                                   eh,
     408           0 :                                   mh->ctx.headers,
     409             :                                   &handle_melt_finished,
     410             :                                   mh);
     411           0 :   return GNUNET_OK;
     412             : }
     413             : 
     414             : 
     415             : /**
     416             :  * The melt request @a mh failed, return an error to
     417             :  * the application and cancel the operation.
     418             :  *
     419             :  * @param[in] mh melt request that failed
     420             :  * @param ec error code to fail with
     421             :  */
     422             : static void
     423           0 : fail_mh (struct TALER_EXCHANGE_MeltHandle *mh,
     424             :          enum TALER_ErrorCode ec)
     425             : {
     426           0 :   struct TALER_EXCHANGE_MeltResponse mr = {
     427             :     .hr.ec = ec
     428             :   };
     429             : 
     430           0 :   mh->melt_cb (mh->melt_cb_cls,
     431             :                &mr);
     432           0 :   TALER_EXCHANGE_melt_cancel (mh);
     433           0 : }
     434             : 
     435             : 
     436             : /**
     437             :  * Callbacks of this type are used to serve the result of submitting a
     438             :  * CS R request to a exchange.
     439             :  *
     440             :  * @param cls closure with our `struct TALER_EXCHANGE_MeltHandle *`
     441             :  * @param csrr response details
     442             :  */
     443             : static void
     444           0 : csr_cb (void *cls,
     445             :         const struct TALER_EXCHANGE_CsRMeltResponse *csrr)
     446             : {
     447           0 :   struct TALER_EXCHANGE_MeltHandle *mh = cls;
     448           0 :   unsigned int nks_off = 0;
     449             : 
     450           0 :   mh->csr = NULL;
     451           0 :   if (MHD_HTTP_OK != csrr->hr.http_status)
     452             :   {
     453           0 :     struct TALER_EXCHANGE_MeltResponse mr = {
     454             :       .hr = csrr->hr
     455             :     };
     456             : 
     457           0 :     mr.hr.hint = "/csr-melt failed";
     458           0 :     mh->melt_cb (mh->melt_cb_cls,
     459             :                  &mr);
     460           0 :     TALER_EXCHANGE_melt_cancel (mh);
     461           0 :     return;
     462             :   }
     463           0 :   for (unsigned int i = 0; i<mh->rd->fresh_pks_len; i++)
     464             :   {
     465           0 :     const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk =
     466           0 :       &mh->rd->fresh_pks[i];
     467           0 :     struct TALER_ExchangeWithdrawValues *wv = &mh->mbds[i].alg_value;
     468             : 
     469           0 :     switch (fresh_pk->key.cipher)
     470             :     {
     471           0 :     case TALER_DENOMINATION_INVALID:
     472           0 :       GNUNET_break (0);
     473           0 :       fail_mh (mh,
     474             :                TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR);
     475           0 :       return;
     476           0 :     case TALER_DENOMINATION_RSA:
     477           0 :       GNUNET_assert (TALER_DENOMINATION_RSA == wv->cipher);
     478           0 :       break;
     479           0 :     case TALER_DENOMINATION_CS:
     480           0 :       GNUNET_assert (TALER_DENOMINATION_CS == wv->cipher);
     481           0 :       *wv = csrr->details.success.alg_values[nks_off];
     482           0 :       nks_off++;
     483           0 :       break;
     484             :     }
     485           0 :   }
     486           0 :   mh->send_rms = true;
     487           0 :   if (GNUNET_OK !=
     488           0 :       start_melt (mh))
     489             :   {
     490           0 :     GNUNET_break (0);
     491           0 :     fail_mh (mh,
     492             :              TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR);
     493           0 :     return;
     494             :   }
     495             : }
     496             : 
     497             : 
     498             : struct TALER_EXCHANGE_MeltHandle *
     499           0 : TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange,
     500             :                      const struct TALER_RefreshMasterSecretP *rms,
     501             :                      const struct TALER_EXCHANGE_RefreshData *rd,
     502             :                      TALER_EXCHANGE_MeltCallback melt_cb,
     503             :                      void *melt_cb_cls)
     504           0 : {
     505           0 :   struct TALER_EXCHANGE_NonceKey nks[GNUNET_NZL (rd->fresh_pks_len)];
     506           0 :   unsigned int nks_off = 0;
     507             :   struct TALER_EXCHANGE_MeltHandle *mh;
     508             : 
     509           0 :   if (0 == rd->fresh_pks_len)
     510             :   {
     511           0 :     GNUNET_break (0);
     512           0 :     return NULL;
     513             :   }
     514           0 :   GNUNET_assert (GNUNET_YES ==
     515             :                  TEAH_handle_is_ready (exchange));
     516           0 :   mh = GNUNET_new (struct TALER_EXCHANGE_MeltHandle);
     517           0 :   mh->noreveal_index = TALER_CNC_KAPPA; /* invalid value */
     518           0 :   mh->exchange = exchange;
     519           0 :   mh->rd = rd;
     520           0 :   mh->rms = *rms;
     521           0 :   mh->melt_cb = melt_cb;
     522           0 :   mh->melt_cb_cls = melt_cb_cls;
     523           0 :   mh->mbds = GNUNET_new_array (rd->fresh_pks_len,
     524             :                                struct TALER_EXCHANGE_MeltBlindingDetail);
     525           0 :   for (unsigned int i = 0; i<rd->fresh_pks_len; i++)
     526             :   {
     527           0 :     const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk = &rd->fresh_pks[i];
     528           0 :     struct TALER_ExchangeWithdrawValues *wv = &mh->mbds[i].alg_value;
     529             : 
     530           0 :     switch (fresh_pk->key.cipher)
     531             :     {
     532           0 :     case TALER_DENOMINATION_INVALID:
     533           0 :       GNUNET_break (0);
     534           0 :       GNUNET_free (mh->mbds);
     535           0 :       GNUNET_free (mh);
     536           0 :       return NULL;
     537           0 :     case TALER_DENOMINATION_RSA:
     538           0 :       wv->cipher = TALER_DENOMINATION_RSA;
     539           0 :       break;
     540           0 :     case TALER_DENOMINATION_CS:
     541           0 :       wv->cipher = TALER_DENOMINATION_CS;
     542           0 :       nks[nks_off].pk = fresh_pk;
     543           0 :       nks[nks_off].cnc_num = nks_off;
     544           0 :       nks_off++;
     545           0 :       break;
     546             :     }
     547           0 :   }
     548           0 :   if (0 != nks_off)
     549             :   {
     550           0 :     mh->csr = TALER_EXCHANGE_csr_melt (exchange,
     551             :                                        rms,
     552             :                                        nks_off,
     553             :                                        nks,
     554             :                                        &csr_cb,
     555             :                                        mh);
     556           0 :     if (NULL == mh->csr)
     557             :     {
     558           0 :       GNUNET_break (0);
     559           0 :       TALER_EXCHANGE_melt_cancel (mh);
     560           0 :       return NULL;
     561             :     }
     562           0 :     return mh;
     563             :   }
     564           0 :   if (GNUNET_OK !=
     565           0 :       start_melt (mh))
     566             :   {
     567           0 :     GNUNET_break (0);
     568           0 :     TALER_EXCHANGE_melt_cancel (mh);
     569           0 :     return NULL;
     570             :   }
     571           0 :   return mh;
     572             : }
     573             : 
     574             : 
     575             : void
     576           0 : TALER_EXCHANGE_melt_cancel (struct TALER_EXCHANGE_MeltHandle *mh)
     577             : {
     578           0 :   if (NULL != mh->job)
     579             :   {
     580           0 :     GNUNET_CURL_job_cancel (mh->job);
     581           0 :     mh->job = NULL;
     582             :   }
     583           0 :   if (NULL != mh->csr)
     584             :   {
     585           0 :     TALER_EXCHANGE_csr_melt_cancel (mh->csr);
     586           0 :     mh->csr = NULL;
     587             :   }
     588           0 :   TALER_EXCHANGE_free_melt_data_ (&mh->md); /* does not free 'md' itself */
     589           0 :   GNUNET_free (mh->mbds);
     590           0 :   GNUNET_free (mh->url);
     591           0 :   TALER_curl_easy_post_finished (&mh->ctx);
     592           0 :   GNUNET_free (mh);
     593           0 : }
     594             : 
     595             : 
     596             : /* end of exchange_api_melt.c */

Generated by: LCOV version 1.14