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-05 21:03:14 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 "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 /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         360 :       GNUNET_assert (NULL != j_coin);
     390         360 :       GNUNET_assert (0 ==
     391             :                      json_array_append_new (j_envs, j_coin));
     392             :     }
     393          90 :     GNUNET_assert (0 ==
     394             :                    json_array_append_new (j_coin_evs, j_envs));
     395             :   }
     396          30 :   GNUNET_assert (0 ==
     397             :                  json_object_set_new (j_request_body,
     398             :                                       "coin_evs",
     399             :                                       j_coin_evs));
     400             :   /* and now we can at last begin the actual request handling */
     401          30 :   mh->url = TALER_url_join (mh->exchange_url,
     402             :                             "melt",
     403             :                             NULL);
     404          30 :   if (NULL == mh->url)
     405             :   {
     406           0 :     json_decref (j_request_body);
     407           0 :     return GNUNET_SYSERR;
     408             :   }
     409          30 :   eh = TALER_EXCHANGE_curl_easy_get_ (mh->url);
     410          60 :   if ( (NULL == eh) ||
     411             :        (GNUNET_OK !=
     412          30 :         TALER_curl_easy_post (&mh->ctx,
     413             :                               eh,
     414             :                               j_request_body)) )
     415             :   {
     416           0 :     GNUNET_break (0);
     417           0 :     if (NULL != eh)
     418           0 :       curl_easy_cleanup (eh);
     419           0 :     json_decref (j_request_body);
     420           0 :     return GNUNET_SYSERR;
     421             :   }
     422          30 :   json_decref (j_request_body);
     423          60 :   mh->job = GNUNET_CURL_job_add2 (mh->cctx,
     424             :                                   eh,
     425          30 :                                   mh->ctx.headers,
     426             :                                   &handle_melt_v27_finished,
     427             :                                   mh);
     428          30 :   return GNUNET_OK;
     429             : }
     430             : 
     431             : 
     432             : /**
     433             :  * The melt request @a mh failed, return an error to
     434             :  * the application and cancel the operation.
     435             :  *
     436             :  * @param[in] mh melt request that failed
     437             :  * @param ec error code to fail with
     438             :  */
     439             : static void
     440           0 : fail_mh (struct TALER_EXCHANGE_MeltHandle_v27 *mh,
     441             :          enum TALER_ErrorCode ec)
     442             : {
     443           0 :   struct TALER_EXCHANGE_MeltResponse_v27 mr = {
     444             :     .hr.ec = ec
     445             :   };
     446             : 
     447           0 :   mh->melt_cb (mh->melt_cb_cls,
     448             :                &mr);
     449           0 :   TALER_EXCHANGE_melt_v27_cancel (mh);
     450           0 : }
     451             : 
     452             : 
     453             : /**
     454             :  * Callbacks of this type are used to serve the result of submitting a
     455             :  * /blinding-prepare request to a exchange.
     456             :  *
     457             :  * @param cls closure with our `struct TALER_EXCHANGE_MeltHandle_v27 *`
     458             :  * @param bpr response details
     459             :  */
     460             : static void
     461          15 : blinding_prepare_cb (void *cls,
     462             :                      const struct TALER_EXCHANGE_BlindingPrepareResponse *bpr)
     463             : {
     464          15 :   struct TALER_EXCHANGE_MeltHandle_v27 *mh = cls;
     465          15 :   unsigned int nks_off = 0;
     466             : 
     467          15 :   mh->bpr = NULL;
     468          15 :   if (MHD_HTTP_OK != bpr->hr.http_status)
     469             :   {
     470           0 :     struct TALER_EXCHANGE_MeltResponse_v27 mr = {
     471             :       .hr = bpr->hr
     472             :     };
     473             : 
     474           0 :     mr.hr.hint = "/blinding-prepare failed";
     475           0 :     mh->melt_cb (mh->melt_cb_cls,
     476             :                  &mr);
     477           0 :     TALER_EXCHANGE_melt_v27_cancel (mh);
     478           0 :     return;
     479             :   }
     480          75 :   for (unsigned int i = 0; i<mh->rd->num_fresh_denom_pubs; i++)
     481             :   {
     482          60 :     const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk =
     483          60 :       &mh->rd->fresh_denom_pubs[i];
     484          60 :     struct TALER_ExchangeBlindingValues *wv = &mh->melt_blinding_values[i];
     485             : 
     486          60 :     switch (fresh_pk->key.bsign_pub_key->cipher)
     487             :     {
     488           0 :     case GNUNET_CRYPTO_BSA_INVALID:
     489           0 :       GNUNET_break (0);
     490           0 :       fail_mh (mh,
     491             :                TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR);
     492           0 :       return;
     493           0 :     case GNUNET_CRYPTO_BSA_RSA:
     494           0 :       break;
     495          60 :     case GNUNET_CRYPTO_BSA_CS:
     496          60 :       TALER_denom_ewv_copy (wv,
     497          60 :                             &bpr->details.ok.blinding_values[nks_off]);
     498          60 :       nks_off++;
     499          60 :       break;
     500             :     }
     501             :   }
     502          15 :   if (GNUNET_OK !=
     503          15 :       start_melt (mh))
     504             :   {
     505           0 :     GNUNET_break (0);
     506           0 :     fail_mh (mh,
     507             :              TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR);
     508           0 :     return;
     509             :   }
     510             : }
     511             : 
     512             : 
     513             : struct TALER_EXCHANGE_MeltHandle_v27 *
     514          30 : TALER_EXCHANGE_melt_v27 (
     515             :   struct GNUNET_CURL_Context *ctx,
     516             :   const char *url,
     517             :   struct TALER_EXCHANGE_Keys *keys,
     518             :   const struct TALER_RefreshMasterSecretP *rms,
     519             :   const struct TALER_EXCHANGE_MeltInput *rd,
     520             :   TALER_EXCHANGE_MeltCallback_v27 melt_cb,
     521             :   void *melt_cb_cls)
     522          30 : {
     523          30 :   struct TALER_EXCHANGE_NonceKey nks[GNUNET_NZL (rd->num_fresh_denom_pubs)];
     524          30 :   unsigned int nks_off = 0;
     525             :   struct TALER_EXCHANGE_MeltHandle_v27 *mh;
     526             : 
     527          30 :   if (0 == rd->num_fresh_denom_pubs)
     528             :   {
     529           0 :     GNUNET_break (0);
     530           0 :     return NULL;
     531             :   }
     532          30 :   mh = GNUNET_new (struct TALER_EXCHANGE_MeltHandle_v27);
     533          30 :   mh->noreveal_index = TALER_CNC_KAPPA; /* invalid value */
     534          30 :   mh->cctx = ctx;
     535          30 :   mh->exchange_url = GNUNET_strdup (url);
     536          30 :   mh->rd = rd;
     537          30 :   mh->rms = *rms;
     538          30 :   mh->melt_cb = melt_cb;
     539          30 :   mh->melt_cb_cls = melt_cb_cls;
     540          30 :   mh->no_blinding_seed = true;
     541          30 :   mh->melt_blinding_values =
     542          30 :     GNUNET_new_array (rd->num_fresh_denom_pubs,
     543             :                       struct TALER_ExchangeBlindingValues);
     544         150 :   for (unsigned int i = 0; i<rd->num_fresh_denom_pubs; i++)
     545             :   {
     546         120 :     const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk =
     547         120 :       &rd->fresh_denom_pubs[i];
     548             : 
     549         120 :     switch (fresh_pk->key.bsign_pub_key->cipher)
     550             :     {
     551           0 :     case GNUNET_CRYPTO_BSA_INVALID:
     552           0 :       GNUNET_break (0);
     553           0 :       GNUNET_free (mh->melt_blinding_values);
     554           0 :       GNUNET_free (mh);
     555           0 :       return NULL;
     556          60 :     case GNUNET_CRYPTO_BSA_RSA:
     557          60 :       TALER_denom_ewv_copy (&mh->melt_blinding_values[i],
     558             :                             TALER_denom_ewv_rsa_singleton ());
     559          60 :       break;
     560          60 :     case GNUNET_CRYPTO_BSA_CS:
     561          60 :       nks[nks_off].pk = fresh_pk;
     562          60 :       nks[nks_off].cnc_num = i;
     563          60 :       nks_off++;
     564          60 :       break;
     565             :     }
     566             :   }
     567          30 :   mh->keys = TALER_EXCHANGE_keys_incref (keys);
     568          30 :   if (0 != nks_off)
     569             :   {
     570          15 :     mh->no_blinding_seed = false;
     571          15 :     TALER_cs_refresh_secret_to_blinding_seed (
     572             :       rms,
     573             :       &mh->blinding_seed);
     574          15 :     mh->bpr = TALER_EXCHANGE_blinding_prepare_for_melt (ctx,
     575             :                                                         url,
     576             :                                                         &mh->blinding_seed,
     577             :                                                         nks_off,
     578             :                                                         nks,
     579             :                                                         &blinding_prepare_cb,
     580             :                                                         mh);
     581          15 :     if (NULL == mh->bpr)
     582             :     {
     583           0 :       GNUNET_break (0);
     584           0 :       TALER_EXCHANGE_melt_v27_cancel (mh);
     585           0 :       return NULL;
     586             :     }
     587          15 :     return mh;
     588             :   }
     589          15 :   if (GNUNET_OK !=
     590          15 :       start_melt (mh))
     591             :   {
     592           0 :     GNUNET_break (0);
     593           0 :     TALER_EXCHANGE_melt_v27_cancel (mh);
     594           0 :     return NULL;
     595             :   }
     596          15 :   return mh;
     597             : }
     598             : 
     599             : 
     600             : void
     601          30 : TALER_EXCHANGE_melt_v27_cancel (struct TALER_EXCHANGE_MeltHandle_v27 *mh)
     602             : {
     603         150 :   for (unsigned int i = 0; i<mh->rd->num_fresh_denom_pubs; i++)
     604         120 :     TALER_denom_ewv_free (&mh->melt_blinding_values[i]);
     605          30 :   if (NULL != mh->job)
     606             :   {
     607           0 :     GNUNET_CURL_job_cancel (mh->job);
     608           0 :     mh->job = NULL;
     609             :   }
     610          30 :   if (NULL != mh->bpr)
     611             :   {
     612           0 :     TALER_EXCHANGE_blinding_prepare_cancel (mh->bpr);
     613           0 :     mh->bpr = NULL;
     614             :   }
     615          30 :   TALER_EXCHANGE_free_melt_data_v27 (&mh->md); /* does not free 'md' itself */
     616          30 :   GNUNET_free (mh->melt_blinding_values);
     617          30 :   GNUNET_free (mh->url);
     618          30 :   GNUNET_free (mh->exchange_url);
     619          30 :   TALER_curl_easy_post_finished (&mh->ctx);
     620          30 :   TALER_EXCHANGE_keys_decref (mh->keys);
     621          30 :   GNUNET_free (mh);
     622          30 : }
     623             : 
     624             : 
     625             : /* end of exchange_api_melt.c */

Generated by: LCOV version 1.16