LCOV - code coverage report
Current view: top level - lib - exchange_api_melt_v27.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 145 227 63.9 %
Date: 2025-06-22 12:09:43 Functions: 6 7 85.7 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2025 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_v27.c
      19             :  * @brief Implementation of the /melt request
      20             :  * @author Özgür Kesim
      21             :  */
      22             : #include "taler/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/taler_json_lib.h"
      29             : #include "taler/taler_exchange_service.h"
      30             : #include "exchange_api_common.h"
      31             : #include "exchange_api_handle.h"
      32             : #include "taler/taler_signatures.h"
      33             : #include "exchange_api_curl_defaults.h"
      34             : #include "exchange_api_refresh_common.h"
      35             : 
      36             : 
      37             : /**
      38             :  * @brief A /melt Handle
      39             :  */
      40             : struct TALER_EXCHANGE_MeltHandle_v27
      41             : {
      42             : 
      43             :   /**
      44             :    * The keys of the this request handle will use
      45             :    */
      46             :   struct TALER_EXCHANGE_Keys *keys;
      47             : 
      48             :   /**
      49             :    * The url for this request.
      50             :    */
      51             :   char *url;
      52             : 
      53             :   /**
      54             :    * The exchange base url.
      55             :    */
      56             :   char *exchange_url;
      57             : 
      58             :   /**
      59             :    * Curl context.
      60             :    */
      61             :   struct GNUNET_CURL_Context *cctx;
      62             : 
      63             :   /**
      64             :    * Context for #TEH_curl_easy_post(). Keeps the data that must
      65             :    * persist for Curl to make the upload.
      66             :    */
      67             :   struct TALER_CURL_PostContext ctx;
      68             : 
      69             :   /**
      70             :    * Handle for the request.
      71             :    */
      72             :   struct GNUNET_CURL_Job *job;
      73             : 
      74             :   /**
      75             :    * Function to call with refresh melt failure results.
      76             :    */
      77             :   TALER_EXCHANGE_MeltCallback_v27 melt_cb;
      78             : 
      79             :   /**
      80             :    * Closure for @e result_cb and @e melt_failure_cb.
      81             :    */
      82             :   void *melt_cb_cls;
      83             : 
      84             :   /**
      85             :    * Actual information about the melt operation.
      86             :    */
      87             :   struct MeltData_v27 md;
      88             : 
      89             :   /**
      90             :    * The secret the entire melt operation is seeded from.
      91             :    */
      92             :   struct TALER_RefreshMasterSecretP rms;
      93             : 
      94             :   /**
      95             :    * Details about the characteristics of the requested melt operation.
      96             :    */
      97             :   const struct TALER_EXCHANGE_MeltInput *rd;
      98             : 
      99             :   /**
     100             :    * True, if no blinding_seed is needed (no CS denominations involved)
     101             :    */
     102             :   bool no_blinding_seed;
     103             : 
     104             :   /**
     105             :    * If @e no_blinding_seed is false, the blinding seed for the intermediate
     106             :    * call to /blinding-prepare, in order to retrieve the R-values from the
     107             :    * exchange for the blind Clause-Schnorr signature.
     108             :    */
     109             :   struct TALER_BlindingMasterSeedP blinding_seed;
     110             : 
     111             :   /**
     112             :    * Array of `num_fresh_denom_pubs` per-coin values
     113             :    * returned from melt operation.
     114             :    */
     115             :   struct TALER_ExchangeBlindingValues *melt_blinding_values;
     116             : 
     117             :   /**
     118             :    * Handle for the preflight request, or NULL.
     119             :    */
     120             :   struct TALER_EXCHANGE_BlindingPrepareHandle *bpr;
     121             : 
     122             :   /**
     123             :    * Public key of the coin being melted.
     124             :    */
     125             :   struct TALER_CoinSpendPublicKeyP coin_pub;
     126             : 
     127             :   /**
     128             :    * Signature affirming the melt.
     129             :    */
     130             :   struct TALER_CoinSpendSignatureP coin_sig;
     131             : 
     132             :   /**
     133             :    * @brief Public information about the coin's denomination key
     134             :    */
     135             :   const struct TALER_EXCHANGE_DenomPublicKey *dki;
     136             : 
     137             :   /**
     138             :    * Gamma value chosen by the exchange during melt.
     139             :    */
     140             :   uint32_t noreveal_index;
     141             : 
     142             : };
     143             : 
     144             : 
     145             : /**
     146             :  * Verify that the signature on the "200 OK" response
     147             :  * from the exchange is valid.
     148             :  *
     149             :  * @param[in,out] mh melt handle
     150             :  * @param json json reply with the signature
     151             :  * @param[out] exchange_pub public key of the exchange used for the signature
     152             :  * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
     153             :  */
     154             : static enum GNUNET_GenericReturnValue
     155          16 : verify_melt_v27_signature_ok (struct TALER_EXCHANGE_MeltHandle_v27 *mh,
     156             :                               const json_t *json,
     157             :                               struct TALER_ExchangePublicKeyP *exchange_pub)
     158             : {
     159             :   struct TALER_ExchangeSignatureP exchange_sig;
     160             :   struct GNUNET_JSON_Specification spec[] = {
     161          16 :     GNUNET_JSON_spec_fixed_auto ("exchange_sig",
     162             :                                  &exchange_sig),
     163          16 :     GNUNET_JSON_spec_fixed_auto ("exchange_pub",
     164             :                                  exchange_pub),
     165          16 :     GNUNET_JSON_spec_uint32 ("noreveal_index",
     166             :                              &mh->noreveal_index),
     167          16 :     GNUNET_JSON_spec_end ()
     168             :   };
     169             : 
     170          16 :   if (GNUNET_OK !=
     171          16 :       GNUNET_JSON_parse (json,
     172             :                          spec,
     173             :                          NULL, NULL))
     174             :   {
     175           0 :     GNUNET_break_op (0);
     176           0 :     return GNUNET_SYSERR;
     177             :   }
     178             :   /* check that exchange signing key is permitted */
     179          16 :   if (GNUNET_OK !=
     180          16 :       TALER_EXCHANGE_test_signing_key (mh->keys,
     181             :                                        exchange_pub))
     182             :   {
     183           0 :     GNUNET_break_op (0);
     184           0 :     return GNUNET_SYSERR;
     185             :   }
     186             : 
     187             :   /* check that noreveal index is in permitted range */
     188          16 :   if (TALER_CNC_KAPPA <= mh->noreveal_index)
     189             :   {
     190           0 :     GNUNET_break_op (0);
     191           0 :     return GNUNET_SYSERR;
     192             :   }
     193             : 
     194          16 :   if (GNUNET_OK !=
     195          16 :       TALER_exchange_online_melt_confirmation_verify (
     196          16 :         &mh->md.rc,
     197             :         mh->noreveal_index,
     198             :         exchange_pub,
     199             :         &exchange_sig))
     200             :   {
     201           0 :     GNUNET_break_op (0);
     202           0 :     return GNUNET_SYSERR;
     203             :   }
     204          16 :   return GNUNET_OK;
     205             : }
     206             : 
     207             : 
     208             : /**
     209             :  * Function called when we're done processing the
     210             :  * HTTP /coins/$COIN_PUB/melt request.
     211             :  *
     212             :  * @param cls the `struct TALER_EXCHANGE_MeltHandle_v27`
     213             :  * @param response_code HTTP response code, 0 on error
     214             :  * @param response parsed JSON result, NULL on error
     215             :  */
     216             : static void
     217          30 : handle_melt_v27_finished (void *cls,
     218             :                           long response_code,
     219             :                           const void *response)
     220             : {
     221          30 :   struct TALER_EXCHANGE_MeltHandle_v27 *mh = cls;
     222          30 :   const json_t *j = response;
     223          30 :   struct TALER_EXCHANGE_MeltResponse_v27 mr = {
     224             :     .hr.reply = j,
     225          30 :     .hr.http_status = (unsigned int) response_code
     226             :   };
     227             : 
     228          30 :   mh->job = NULL;
     229          30 :   switch (response_code)
     230             :   {
     231           0 :   case 0:
     232           0 :     mr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     233           0 :     break;
     234          16 :   case MHD_HTTP_OK:
     235          16 :     if (GNUNET_OK !=
     236          16 :         verify_melt_v27_signature_ok (mh,
     237             :                                       j,
     238             :                                       &mr.details.ok.sign_key))
     239             :     {
     240           0 :       GNUNET_break_op (0);
     241           0 :       mr.hr.http_status = 0;
     242           0 :       mr.hr.ec = TALER_EC_EXCHANGE_MELT_INVALID_SIGNATURE_BY_EXCHANGE;
     243           0 :       break;
     244             :     }
     245          16 :     mr.details.ok.noreveal_index = mh->noreveal_index;
     246          16 :     mr.details.ok.num_melt_blinding_values = mh->rd->num_fresh_denom_pubs;
     247          16 :     mr.details.ok.melt_blinding_values = mh->melt_blinding_values;
     248          32 :     mr.details.ok.blinding_seed = mh->no_blinding_seed
     249             :                                                ? NULL
     250          16 :                                                : &mh->blinding_seed;
     251          16 :     mh->melt_cb (mh->melt_cb_cls,
     252             :                  &mr);
     253          16 :     mh->melt_cb = NULL;
     254          16 :     break;
     255           0 :   case MHD_HTTP_BAD_REQUEST:
     256             :     /* This should never happen, either us or the exchange is buggy
     257             :        (or API version conflict); just pass JSON reply to the application */
     258           0 :     mr.hr.ec = TALER_JSON_get_error_code (j);
     259           0 :     mr.hr.hint = TALER_JSON_get_error_hint (j);
     260           0 :     break;
     261          14 :   case MHD_HTTP_CONFLICT:
     262          14 :     mr.hr.ec = TALER_JSON_get_error_code (j);
     263          14 :     mr.hr.hint = TALER_JSON_get_error_hint (j);
     264          14 :     break;
     265           0 :   case MHD_HTTP_FORBIDDEN:
     266             :     /* Nothing really to verify, exchange says one of the signatures is
     267             :        invalid; assuming we checked them, this should never happen, we
     268             :        should pass the JSON reply to the application */
     269           0 :     mr.hr.ec = TALER_JSON_get_error_code (j);
     270           0 :     mr.hr.hint = TALER_JSON_get_error_hint (j);
     271           0 :     break;
     272           0 :   case MHD_HTTP_NOT_FOUND:
     273             :     /* Nothing really to verify, this should never
     274             :        happen, we should pass the JSON reply to the application */
     275           0 :     mr.hr.ec = TALER_JSON_get_error_code (j);
     276           0 :     mr.hr.hint = TALER_JSON_get_error_hint (j);
     277           0 :     break;
     278           0 :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     279             :     /* Server had an internal issue; we should retry, but this API
     280             :        leaves this to the application */
     281           0 :     mr.hr.ec = TALER_JSON_get_error_code (j);
     282           0 :     mr.hr.hint = TALER_JSON_get_error_hint (j);
     283           0 :     break;
     284           0 :   default:
     285             :     /* unexpected response code */
     286           0 :     mr.hr.ec = TALER_JSON_get_error_code (j);
     287           0 :     mr.hr.hint = TALER_JSON_get_error_hint (j);
     288           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     289             :                 "Unexpected response code %u/%d for exchange melt\n",
     290             :                 (unsigned int) response_code,
     291             :                 mr.hr.ec);
     292           0 :     GNUNET_break_op (0);
     293           0 :     break;
     294             :   }
     295          30 :   if (NULL != mh->melt_cb)
     296          14 :     mh->melt_cb (mh->melt_cb_cls,
     297             :                  &mr);
     298          30 :   TALER_EXCHANGE_melt_v27_cancel (mh);
     299          30 : }
     300             : 
     301             : 
     302             : /**
     303             :  * Start the actual melt operation, now that we have
     304             :  * the exchange's input values.
     305             :  *
     306             :  * @param[in,out] mh melt operation to run
     307             :  * @return #GNUNET_OK if we could start the operation
     308             :  */
     309             : static enum GNUNET_GenericReturnValue
     310          30 : start_melt (struct TALER_EXCHANGE_MeltHandle_v27 *mh)
     311             : {
     312             :   json_t *j_request_body;
     313             :   json_t *j_coin_evs;
     314             :   CURL *eh;
     315             :   struct TALER_DenominationHashP h_denom_pub;
     316             : 
     317          30 :   if (GNUNET_OK !=
     318          30 :       TALER_EXCHANGE_get_melt_data_v27 (&mh->rms,
     319             :                                         mh->rd,
     320          30 :                                         mh->no_blinding_seed
     321             :                                         ? NULL
     322             :                                         : &mh->blinding_seed,
     323          30 :                                         mh->melt_blinding_values,
     324             :                                         &mh->md))
     325             :   {
     326           0 :     GNUNET_break (0);
     327           0 :     return GNUNET_SYSERR;
     328             :   }
     329          30 :   TALER_denom_pub_hash (&mh->md.melted_coin.pub_key,
     330             :                         &h_denom_pub);
     331          30 :   TALER_wallet_melt_sign (
     332          30 :     &mh->md.melted_coin.melt_amount_with_fee,
     333          30 :     &mh->md.melted_coin.fee_melt,
     334          30 :     &mh->md.rc,
     335             :     &h_denom_pub,
     336             :     mh->md.melted_coin.h_age_commitment,
     337          30 :     &mh->md.melted_coin.coin_priv,
     338             :     &mh->coin_sig);
     339          30 :   GNUNET_CRYPTO_eddsa_key_get_public (
     340          30 :     &mh->md.melted_coin.coin_priv.eddsa_priv,
     341             :     &mh->coin_pub.eddsa_pub);
     342          60 :   mh->dki = TALER_EXCHANGE_get_denomination_key (mh->keys,
     343          30 :                                                  &mh->md.melted_coin.pub_key);
     344          30 :   j_request_body = GNUNET_JSON_PACK (
     345             :     GNUNET_JSON_pack_data_auto ("old_coin_pub",
     346             :                                 &mh->coin_pub),
     347             :     GNUNET_JSON_pack_data_auto ("old_denom_pub_h",
     348             :                                 &h_denom_pub),
     349             :     TALER_JSON_pack_denom_sig ("old_denom_sig",
     350             :                                &mh->md.melted_coin.sig),
     351             :     GNUNET_JSON_pack_data_auto ("confirm_sig",
     352             :                                 &mh->coin_sig),
     353             :     TALER_JSON_pack_amount ("value_with_fee",
     354             :                             &mh->md.melted_coin.melt_amount_with_fee),
     355             :     GNUNET_JSON_pack_allow_null (
     356             :       (NULL != mh->md.melted_coin.h_age_commitment)
     357             :       ? GNUNET_JSON_pack_data_auto ("old_age_commitment_h",
     358             :                                     mh->md.melted_coin.h_age_commitment)
     359             :       : GNUNET_JSON_pack_string ("old_age_commitment_h",
     360             :                                  NULL)),
     361             :     GNUNET_JSON_pack_data_auto ("refresh_seed",
     362             :                                 &mh->md.refresh_seed),
     363             :     GNUNET_JSON_pack_allow_null (
     364             :       (mh->md.no_blinding_seed)
     365             :       ? GNUNET_JSON_pack_string ("blinding_seed",
     366             :                                  NULL)
     367             :       : GNUNET_JSON_pack_data_auto ("blinding_seed",
     368             :                                     &mh->md.blinding_seed)),
     369             :     TALER_JSON_pack_array_of_data ("denoms_h",
     370             :                                    mh->md.num_fresh_coins,
     371             :                                    mh->md.denoms_h,
     372             :                                    sizeof(*mh->md.denoms_h))
     373             :     );
     374          30 :   GNUNET_assert (NULL != j_request_body);
     375          30 :   j_coin_evs = json_array ();
     376          30 :   GNUNET_assert (NULL != j_coin_evs);
     377             :   /**
     378             :    * Fill the kappa array of coin envelopes
     379             :    */
     380         120 :   for (uint8_t k=0; k<TALER_CNC_KAPPA; k++)
     381             :   {
     382          90 :     json_t *j_envs = json_array ();
     383          90 :     GNUNET_assert (NULL != j_envs);
     384         450 :     for (size_t i = 0; i < mh->md.num_fresh_coins; i++)
     385             :     {
     386         360 :       json_t *j_coin = GNUNET_JSON_PACK (
     387             :         TALER_JSON_pack_blinded_planchet (NULL,
     388             :                                           &mh->md.kappa_blinded_planchets[k][i])
     389             :         );
     390         360 :       GNUNET_assert (NULL != j_coin);
     391         360 :       GNUNET_assert (0 ==
     392             :                      json_array_append_new (j_envs, j_coin));
     393             :     }
     394          90 :     GNUNET_assert (0 ==
     395             :                    json_array_append_new (j_coin_evs, j_envs));
     396             :   }
     397          30 :   GNUNET_assert (0 ==
     398             :                  json_object_set_new (j_request_body,
     399             :                                       "coin_evs",
     400             :                                       j_coin_evs));
     401             :   /* and now we can at last begin the actual request handling */
     402          30 :   mh->url = TALER_url_join (mh->exchange_url,
     403             :                             "melt",
     404             :                             NULL);
     405          30 :   if (NULL == mh->url)
     406             :   {
     407           0 :     json_decref (j_request_body);
     408           0 :     return GNUNET_SYSERR;
     409             :   }
     410          30 :   eh = TALER_EXCHANGE_curl_easy_get_ (mh->url);
     411          60 :   if ( (NULL == eh) ||
     412             :        (GNUNET_OK !=
     413          30 :         TALER_curl_easy_post (&mh->ctx,
     414             :                               eh,
     415             :                               j_request_body)) )
     416             :   {
     417           0 :     GNUNET_break (0);
     418           0 :     if (NULL != eh)
     419           0 :       curl_easy_cleanup (eh);
     420           0 :     json_decref (j_request_body);
     421           0 :     return GNUNET_SYSERR;
     422             :   }
     423          30 :   json_decref (j_request_body);
     424          60 :   mh->job = GNUNET_CURL_job_add2 (mh->cctx,
     425             :                                   eh,
     426          30 :                                   mh->ctx.headers,
     427             :                                   &handle_melt_v27_finished,
     428             :                                   mh);
     429          30 :   return GNUNET_OK;
     430             : }
     431             : 
     432             : 
     433             : /**
     434             :  * The melt request @a mh failed, return an error to
     435             :  * the application and cancel the operation.
     436             :  *
     437             :  * @param[in] mh melt request that failed
     438             :  * @param ec error code to fail with
     439             :  */
     440             : static void
     441           0 : fail_mh (struct TALER_EXCHANGE_MeltHandle_v27 *mh,
     442             :          enum TALER_ErrorCode ec)
     443             : {
     444           0 :   struct TALER_EXCHANGE_MeltResponse_v27 mr = {
     445             :     .hr.ec = ec
     446             :   };
     447             : 
     448           0 :   mh->melt_cb (mh->melt_cb_cls,
     449             :                &mr);
     450           0 :   TALER_EXCHANGE_melt_v27_cancel (mh);
     451           0 : }
     452             : 
     453             : 
     454             : /**
     455             :  * Callbacks of this type are used to serve the result of submitting a
     456             :  * /blinding-prepare request to a exchange.
     457             :  *
     458             :  * @param cls closure with our `struct TALER_EXCHANGE_MeltHandle_v27 *`
     459             :  * @param bpr response details
     460             :  */
     461             : static void
     462          15 : blinding_prepare_cb (void *cls,
     463             :                      const struct TALER_EXCHANGE_BlindingPrepareResponse *bpr)
     464             : {
     465          15 :   struct TALER_EXCHANGE_MeltHandle_v27 *mh = cls;
     466          15 :   unsigned int nks_off = 0;
     467             : 
     468          15 :   mh->bpr = NULL;
     469          15 :   if (MHD_HTTP_OK != bpr->hr.http_status)
     470             :   {
     471           0 :     struct TALER_EXCHANGE_MeltResponse_v27 mr = {
     472             :       .hr = bpr->hr
     473             :     };
     474             : 
     475           0 :     mr.hr.hint = "/blinding-prepare failed";
     476           0 :     mh->melt_cb (mh->melt_cb_cls,
     477             :                  &mr);
     478           0 :     TALER_EXCHANGE_melt_v27_cancel (mh);
     479           0 :     return;
     480             :   }
     481          75 :   for (unsigned int i = 0; i<mh->rd->num_fresh_denom_pubs; i++)
     482             :   {
     483          60 :     const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk =
     484          60 :       &mh->rd->fresh_denom_pubs[i];
     485          60 :     struct TALER_ExchangeBlindingValues *wv = &mh->melt_blinding_values[i];
     486             : 
     487          60 :     switch (fresh_pk->key.bsign_pub_key->cipher)
     488             :     {
     489           0 :     case GNUNET_CRYPTO_BSA_INVALID:
     490           0 :       GNUNET_break (0);
     491           0 :       fail_mh (mh,
     492             :                TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR);
     493           0 :       return;
     494           0 :     case GNUNET_CRYPTO_BSA_RSA:
     495           0 :       break;
     496          60 :     case GNUNET_CRYPTO_BSA_CS:
     497          60 :       TALER_denom_ewv_copy (wv,
     498          60 :                             &bpr->details.ok.blinding_values[nks_off]);
     499          60 :       nks_off++;
     500          60 :       break;
     501             :     }
     502             :   }
     503          15 :   if (GNUNET_OK !=
     504          15 :       start_melt (mh))
     505             :   {
     506           0 :     GNUNET_break (0);
     507           0 :     fail_mh (mh,
     508             :              TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR);
     509           0 :     return;
     510             :   }
     511             : }
     512             : 
     513             : 
     514             : struct TALER_EXCHANGE_MeltHandle_v27 *
     515          30 : TALER_EXCHANGE_melt_v27 (
     516             :   struct GNUNET_CURL_Context *ctx,
     517             :   const char *url,
     518             :   struct TALER_EXCHANGE_Keys *keys,
     519             :   const struct TALER_RefreshMasterSecretP *rms,
     520             :   const struct TALER_EXCHANGE_MeltInput *rd,
     521             :   TALER_EXCHANGE_MeltCallback_v27 melt_cb,
     522             :   void *melt_cb_cls)
     523          30 : {
     524          30 :   struct TALER_EXCHANGE_NonceKey nks[GNUNET_NZL (rd->num_fresh_denom_pubs)];
     525          30 :   unsigned int nks_off = 0;
     526             :   struct TALER_EXCHANGE_MeltHandle_v27 *mh;
     527             : 
     528          30 :   if (0 == rd->num_fresh_denom_pubs)
     529             :   {
     530           0 :     GNUNET_break (0);
     531           0 :     return NULL;
     532             :   }
     533          30 :   mh = GNUNET_new (struct TALER_EXCHANGE_MeltHandle_v27);
     534          30 :   mh->noreveal_index = TALER_CNC_KAPPA; /* invalid value */
     535          30 :   mh->cctx = ctx;
     536          30 :   mh->exchange_url = GNUNET_strdup (url);
     537          30 :   mh->rd = rd;
     538          30 :   mh->rms = *rms;
     539          30 :   mh->melt_cb = melt_cb;
     540          30 :   mh->melt_cb_cls = melt_cb_cls;
     541          30 :   mh->no_blinding_seed = true;
     542          30 :   mh->melt_blinding_values =
     543          30 :     GNUNET_new_array (rd->num_fresh_denom_pubs,
     544             :                       struct TALER_ExchangeBlindingValues);
     545         150 :   for (unsigned int i = 0; i<rd->num_fresh_denom_pubs; i++)
     546             :   {
     547         120 :     const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk =
     548         120 :       &rd->fresh_denom_pubs[i];
     549             : 
     550         120 :     switch (fresh_pk->key.bsign_pub_key->cipher)
     551             :     {
     552           0 :     case GNUNET_CRYPTO_BSA_INVALID:
     553           0 :       GNUNET_break (0);
     554           0 :       GNUNET_free (mh->melt_blinding_values);
     555           0 :       GNUNET_free (mh);
     556           0 :       return NULL;
     557          60 :     case GNUNET_CRYPTO_BSA_RSA:
     558          60 :       TALER_denom_ewv_copy (&mh->melt_blinding_values[i],
     559             :                             TALER_denom_ewv_rsa_singleton ());
     560          60 :       break;
     561          60 :     case GNUNET_CRYPTO_BSA_CS:
     562          60 :       nks[nks_off].pk = fresh_pk;
     563          60 :       nks[nks_off].cnc_num = i;
     564          60 :       nks_off++;
     565          60 :       break;
     566             :     }
     567             :   }
     568          30 :   mh->keys = TALER_EXCHANGE_keys_incref (keys);
     569          30 :   if (0 != nks_off)
     570             :   {
     571          15 :     mh->no_blinding_seed = false;
     572          15 :     TALER_cs_refresh_secret_to_blinding_seed (
     573             :       rms,
     574             :       &mh->blinding_seed);
     575          15 :     mh->bpr = TALER_EXCHANGE_blinding_prepare_for_melt (ctx,
     576             :                                                         url,
     577             :                                                         &mh->blinding_seed,
     578             :                                                         nks_off,
     579             :                                                         nks,
     580             :                                                         &blinding_prepare_cb,
     581             :                                                         mh);
     582          15 :     if (NULL == mh->bpr)
     583             :     {
     584           0 :       GNUNET_break (0);
     585           0 :       TALER_EXCHANGE_melt_v27_cancel (mh);
     586           0 :       return NULL;
     587             :     }
     588          15 :     return mh;
     589             :   }
     590          15 :   if (GNUNET_OK !=
     591          15 :       start_melt (mh))
     592             :   {
     593           0 :     GNUNET_break (0);
     594           0 :     TALER_EXCHANGE_melt_v27_cancel (mh);
     595           0 :     return NULL;
     596             :   }
     597          15 :   return mh;
     598             : }
     599             : 
     600             : 
     601             : void
     602          30 : TALER_EXCHANGE_melt_v27_cancel (struct TALER_EXCHANGE_MeltHandle_v27 *mh)
     603             : {
     604         150 :   for (unsigned int i = 0; i<mh->rd->num_fresh_denom_pubs; i++)
     605         120 :     TALER_denom_ewv_free (&mh->melt_blinding_values[i]);
     606          30 :   if (NULL != mh->job)
     607             :   {
     608           0 :     GNUNET_CURL_job_cancel (mh->job);
     609           0 :     mh->job = NULL;
     610             :   }
     611          30 :   if (NULL != mh->bpr)
     612             :   {
     613           0 :     TALER_EXCHANGE_blinding_prepare_cancel (mh->bpr);
     614           0 :     mh->bpr = NULL;
     615             :   }
     616          30 :   TALER_EXCHANGE_free_melt_data_v27 (&mh->md); /* does not free 'md' itself */
     617          30 :   GNUNET_free (mh->melt_blinding_values);
     618          30 :   GNUNET_free (mh->url);
     619          30 :   GNUNET_free (mh->exchange_url);
     620          30 :   TALER_curl_easy_post_finished (&mh->ctx);
     621          30 :   TALER_EXCHANGE_keys_decref (mh->keys);
     622          30 :   GNUNET_free (mh);
     623          30 : }
     624             : 
     625             : 
     626             : /* end of exchange_api_melt.c */

Generated by: LCOV version 1.16