LCOV - code coverage report
Current view: top level - lib - exchange_api_post-melt.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 66.3 % 273 181
Test Date: 2026-10-29 19:05:17 Functions: 88.9 % 9 8

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

Generated by: LCOV version 2.0-1