LCOV - code coverage report
Current view: top level - exchange-lib - exchange_api_refresh.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 375 495 75.8 %
Date: 2017-11-25 11:31:41 Functions: 21 21 100.0 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2015, 2016 GNUnet e.V.
       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 exchange-lib/exchange_api_refresh.c
      19             :  * @brief Implementation of the /refresh/melt+reveal requests of the exchange's HTTP API
      20             :  * @author Christian Grothoff
      21             :  */
      22             : #include "platform.h"
      23             : #include <curl/curl.h>
      24             : #include <jansson.h>
      25             : #include <microhttpd.h> /* just for HTTP status codes */
      26             : #include <gnunet/gnunet_util_lib.h>
      27             : #include <gnunet/gnunet_json_lib.h>
      28             : #include <gnunet/gnunet_curl_lib.h>
      29             : #include "taler_json_lib.h"
      30             : #include "taler_exchange_service.h"
      31             : #include "exchange_api_handle.h"
      32             : #include "taler_signatures.h"
      33             : 
      34             : 
      35             : /* ********************* /refresh/ common ***************************** */
      36             : 
      37             : /* structures for committing refresh data to disk before doing the
      38             :    network interaction(s) */
      39             : 
      40             : GNUNET_NETWORK_STRUCT_BEGIN
      41             : 
      42             : /**
      43             :  * Header of serialized information about a coin we are melting.
      44             :  */
      45             : struct MeltedCoinP
      46             : {
      47             :   /**
      48             :    * Private key of the coin.
      49             :    */
      50             :   struct TALER_CoinSpendPrivateKeyP coin_priv;
      51             : 
      52             :   /**
      53             :    * Amount this coin contributes to the melt, including fee.
      54             :    */
      55             :   struct TALER_AmountNBO melt_amount_with_fee;
      56             : 
      57             :   /**
      58             :    * The applicable fee for withdrawing a coin of this denomination
      59             :    */
      60             :   struct TALER_AmountNBO fee_melt;
      61             : 
      62             :   /**
      63             :    * The original value of the coin.
      64             :    */
      65             :   struct TALER_AmountNBO original_value;
      66             : 
      67             :   /**
      68             :    * Transfer private keys for each cut-and-choose dimension.
      69             :    */
      70             :   struct TALER_TransferPrivateKeyP transfer_priv[TALER_CNC_KAPPA];
      71             : 
      72             :   /**
      73             :    * Timestamp indicating when coins of this denomination become invalid.
      74             :    */
      75             :   struct GNUNET_TIME_AbsoluteNBO expire_deposit;
      76             : 
      77             :   /**
      78             :    * Size of the encoded public key that follows.
      79             :    */
      80             :   uint16_t pbuf_size;
      81             : 
      82             :   /**
      83             :    * Size of the encoded signature that follows.
      84             :    */
      85             :   uint16_t sbuf_size;
      86             : 
      87             :   /* Followed by serializations of:
      88             :      1) struct TALER_DenominationPublicKey pub_key;
      89             :      2) struct TALER_DenominationSignature sig;
      90             :   */
      91             : };
      92             : 
      93             : 
      94             : /**
      95             :  * Header of serialized data about a melt operation, suitable for
      96             :  * persisting it on disk.
      97             :  */
      98             : struct MeltDataP
      99             : {
     100             : 
     101             :   /**
     102             :    * Hash over the melting session.
     103             :    */
     104             :   struct GNUNET_HashCode melt_session_hash;
     105             : 
     106             :   /**
     107             :    * Number of coins we are melting, in NBO
     108             :    */
     109             :   uint16_t num_melted_coins GNUNET_PACKED;
     110             : 
     111             :   /**
     112             :    * Number of coins we are creating, in NBO
     113             :    */
     114             :   uint16_t num_fresh_coins GNUNET_PACKED;
     115             : 
     116             :   /* Followed by serializations of:
     117             :      1) struct MeltedCoinP melted_coins[num_melted_coins];
     118             :      2) struct TALER_EXCHANGE_DenomPublicKey fresh_pks[num_fresh_coins];
     119             :      3) TALER_CNC_KAPPA times:
     120             :         3a) struct TALER_PlanchetSecretsP fresh_coins[num_fresh_coins];
     121             :   */
     122             : };
     123             : 
     124             : 
     125             : GNUNET_NETWORK_STRUCT_END
     126             : 
     127             : 
     128             : /**
     129             :  * Information about a coin we are melting.
     130             :  */
     131             : struct MeltedCoin
     132             : {
     133             :   /**
     134             :    * Private key of the coin.
     135             :    */
     136             :   struct TALER_CoinSpendPrivateKeyP coin_priv;
     137             : 
     138             :   /**
     139             :    * Amount this coin contributes to the melt, including fee.
     140             :    */
     141             :   struct TALER_Amount melt_amount_with_fee;
     142             : 
     143             :   /**
     144             :    * The applicable fee for melting a coin of this denomination
     145             :    */
     146             :   struct TALER_Amount fee_melt;
     147             : 
     148             :   /**
     149             :    * The original value of the coin.
     150             :    */
     151             :   struct TALER_Amount original_value;
     152             : 
     153             :   /**
     154             :    * Transfer private keys for each cut-and-choose dimension.
     155             :    */
     156             :   struct TALER_TransferPrivateKeyP transfer_priv[TALER_CNC_KAPPA];
     157             : 
     158             :   /**
     159             :    * Timestamp indicating when coins of this denomination become invalid.
     160             :    */
     161             :   struct GNUNET_TIME_Absolute expire_deposit;
     162             : 
     163             :   /**
     164             :    * Denomination key of the original coin.
     165             :    */
     166             :   struct TALER_DenominationPublicKey pub_key;
     167             : 
     168             :   /**
     169             :    * Exchange's signature over the coin.
     170             :    */
     171             :   struct TALER_DenominationSignature sig;
     172             : 
     173             : };
     174             : 
     175             : 
     176             : /**
     177             :  * Melt data in non-serialized format for convenient processing.
     178             :  */
     179             : struct MeltData
     180             : {
     181             : 
     182             :   /**
     183             :    * Hash over the melting session.
     184             :    */
     185             :   struct GNUNET_HashCode melt_session_hash;
     186             : 
     187             :   /**
     188             :    * Number of coins we are creating
     189             :    */
     190             :   uint16_t num_fresh_coins;
     191             : 
     192             :   /**
     193             :    * Information about the melted coin.
     194             :    */
     195             :   struct MeltedCoin melted_coin;
     196             : 
     197             :   /**
     198             :    * Array of @e num_fresh_coins denomination keys for the coins to be
     199             :    * freshly exchangeed.
     200             :    */
     201             :   struct TALER_DenominationPublicKey *fresh_pks;
     202             : 
     203             :   /**
     204             :    * Arrays of @e num_fresh_coins with information about the fresh
     205             :    * coins to be created, for each cut-and-choose dimension.
     206             :    */
     207             :   struct TALER_PlanchetSecretsP *fresh_coins[TALER_CNC_KAPPA];
     208             : };
     209             : 
     210             : 
     211             : /**
     212             :  * Free all information associated with a melted coin session.
     213             :  *
     214             :  * @param mc melted coin to release, the pointer itself is NOT
     215             :  *           freed (as it is typically not allocated by itself)
     216             :  */
     217             : static void
     218           6 : free_melted_coin (struct MeltedCoin *mc)
     219             : {
     220           6 :   if (NULL != mc->pub_key.rsa_public_key)
     221           6 :     GNUNET_CRYPTO_rsa_public_key_free (mc->pub_key.rsa_public_key);
     222           6 :   if (NULL != mc->sig.rsa_signature)
     223           6 :     GNUNET_CRYPTO_rsa_signature_free (mc->sig.rsa_signature);
     224           6 : }
     225             : 
     226             : 
     227             : /**
     228             :  * Free all information associated with a melting session.  Note
     229             :  * that we allow the melting session to be only partially initialized,
     230             :  * as we use this function also when freeing melt data that was not
     231             :  * fully initialized (i.e. due to failures in #deserialize_melt_data()).
     232             :  *
     233             :  * @param md melting data to release, the pointer itself is NOT
     234             :  *           freed (as it is typically not allocated by itself)
     235             :  */
     236             : static void
     237           6 : free_melt_data (struct MeltData *md)
     238             : {
     239           6 :   free_melted_coin (&md->melted_coin);
     240           6 :   if (NULL != md->fresh_pks)
     241             :   {
     242         108 :     for (unsigned int i=0;i<md->num_fresh_coins;i++)
     243         102 :       if (NULL != md->fresh_pks[i].rsa_public_key)
     244         102 :         GNUNET_CRYPTO_rsa_public_key_free (md->fresh_pks[i].rsa_public_key);
     245           6 :     GNUNET_free (md->fresh_pks);
     246             :   }
     247             : 
     248          24 :   for (unsigned int i=0;i<TALER_CNC_KAPPA;i++)
     249          18 :     GNUNET_free (md->fresh_coins[i]);
     250             :   /* Finally, clean up a bit...
     251             :      (NOTE: compilers might optimize this away, so this is
     252             :      not providing any strong assurances that the key material
     253             :      is purged.) */
     254           6 :   memset (md,
     255             :           0,
     256             :           sizeof (struct MeltData));
     257           6 : }
     258             : 
     259             : 
     260             : /**
     261             :  * Serialize information about a coin we are melting.
     262             :  *
     263             :  * @param mc information to serialize
     264             :  * @param buf buffer to write data in, NULL to just compute
     265             :  *            required size
     266             :  * @param off offeset at @a buf to use
     267             :  * @return number of bytes written to @a buf at @a off, or if
     268             :  *        @a buf is NULL, number of bytes required; 0 on error
     269             :  */
     270             : static size_t
     271           4 : serialize_melted_coin (const struct MeltedCoin *mc,
     272             :                        char *buf,
     273             :                        size_t off)
     274             : {
     275             :   struct MeltedCoinP mcp;
     276             :   unsigned int i;
     277             :   char *pbuf;
     278             :   size_t pbuf_size;
     279             :   char *sbuf;
     280             :   size_t sbuf_size;
     281             : 
     282           4 :   sbuf_size = GNUNET_CRYPTO_rsa_signature_encode (mc->sig.rsa_signature,
     283             :                                                   &sbuf);
     284           4 :   pbuf_size = GNUNET_CRYPTO_rsa_public_key_encode (mc->pub_key.rsa_public_key,
     285             :                                                    &pbuf);
     286           4 :   if (NULL == buf)
     287             :   {
     288           2 :     GNUNET_free (sbuf);
     289           2 :     GNUNET_free (pbuf);
     290           2 :     return sizeof (struct MeltedCoinP) + sbuf_size + pbuf_size;
     291             :   }
     292           2 :   if ( (sbuf_size > UINT16_MAX) ||
     293             :        (pbuf_size > UINT16_MAX) )
     294             :   {
     295           0 :     GNUNET_break (0);
     296           0 :     return 0;
     297             :   }
     298           2 :   mcp.coin_priv = mc->coin_priv;
     299           2 :   TALER_amount_hton (&mcp.melt_amount_with_fee,
     300             :                      &mc->melt_amount_with_fee);
     301           2 :   TALER_amount_hton (&mcp.fee_melt,
     302             :                      &mc->fee_melt);
     303           2 :   TALER_amount_hton (&mcp.original_value,
     304             :                      &mc->original_value);
     305           8 :   for (i=0;i<TALER_CNC_KAPPA;i++)
     306           6 :     mcp.transfer_priv[i] = mc->transfer_priv[i];
     307           2 :   mcp.expire_deposit = GNUNET_TIME_absolute_hton (mc->expire_deposit);
     308           2 :   mcp.pbuf_size = htons ((uint16_t) pbuf_size);
     309           2 :   mcp.sbuf_size = htons ((uint16_t) sbuf_size);
     310           2 :   memcpy (&buf[off],
     311             :           &mcp,
     312             :           sizeof (struct MeltedCoinP));
     313           2 :   memcpy (&buf[off + sizeof (struct MeltedCoinP)],
     314             :           pbuf,
     315             :           pbuf_size);
     316           2 :   memcpy (&buf[off + sizeof (struct MeltedCoinP) + pbuf_size],
     317             :           sbuf,
     318             :           sbuf_size);
     319           2 :   GNUNET_free (sbuf);
     320           2 :   GNUNET_free (pbuf);
     321           2 :   return sizeof (struct MeltedCoinP) + sbuf_size + pbuf_size;
     322             : }
     323             : 
     324             : 
     325             : /**
     326             :  * Deserialize information about a coin we are melting.
     327             :  *
     328             :  * @param[out] mc information to deserialize
     329             :  * @param buf buffer to read data from
     330             :  * @param size number of bytes available at @a buf to use
     331             :  * @param[out] ok set to #GNUNET_NO to report errors
     332             :  * @return number of bytes read from @a buf, 0 on error
     333             :  */
     334             : static size_t
     335           4 : deserialize_melted_coin (struct MeltedCoin *mc,
     336             :                          const char *buf,
     337             :                          size_t size,
     338             :                          int *ok)
     339             : {
     340             :   struct MeltedCoinP mcp;
     341             :   unsigned int i;
     342             :   size_t pbuf_size;
     343             :   size_t sbuf_size;
     344             :   size_t off;
     345             : 
     346           4 :   if (size < sizeof (struct MeltedCoinP))
     347             :   {
     348           0 :     GNUNET_break (0);
     349           0 :     *ok = GNUNET_NO;
     350           0 :     return 0;
     351             :   }
     352           4 :   memcpy (&mcp,
     353             :           buf,
     354             :           sizeof (struct MeltedCoinP));
     355           4 :   pbuf_size = ntohs (mcp.pbuf_size);
     356           4 :   sbuf_size = ntohs (mcp.sbuf_size);
     357           4 :   if (size < sizeof (struct MeltedCoinP) + pbuf_size + sbuf_size)
     358             :   {
     359           0 :     GNUNET_break (0);
     360           0 :     *ok = GNUNET_NO;
     361           0 :     return 0;
     362             :   }
     363           4 :   off = sizeof (struct MeltedCoinP);
     364             :   mc->pub_key.rsa_public_key
     365           4 :     = GNUNET_CRYPTO_rsa_public_key_decode (&buf[off],
     366             :                                            pbuf_size);
     367           4 :   off += pbuf_size;
     368             :   mc->sig.rsa_signature
     369           4 :     = GNUNET_CRYPTO_rsa_signature_decode (&buf[off],
     370             :                                           sbuf_size);
     371           4 :   off += sbuf_size;
     372           8 :   if ( (NULL == mc->pub_key.rsa_public_key) ||
     373           4 :        (NULL == mc->sig.rsa_signature) )
     374             :   {
     375           0 :     GNUNET_break (0);
     376           0 :     *ok = GNUNET_NO;
     377           0 :     return 0;
     378             :   }
     379             : 
     380           4 :   mc->coin_priv = mcp.coin_priv;
     381           4 :   TALER_amount_ntoh (&mc->melt_amount_with_fee,
     382             :                      &mcp.melt_amount_with_fee);
     383           4 :   TALER_amount_ntoh (&mc->fee_melt,
     384             :                      &mcp.fee_melt);
     385           4 :   TALER_amount_ntoh (&mc->original_value,
     386             :                      &mcp.original_value);
     387          16 :   for (i=0;i<TALER_CNC_KAPPA;i++)
     388          12 :     mc->transfer_priv[i] = mcp.transfer_priv[i];
     389           4 :   mc->expire_deposit = GNUNET_TIME_absolute_ntoh (mcp.expire_deposit);
     390           4 :   return off;
     391             : }
     392             : 
     393             : 
     394             : /**
     395             :  * Serialize information about a denomination key.
     396             :  *
     397             :  * @param dk information to serialize
     398             :  * @param buf buffer to write data in, NULL to just compute
     399             :  *            required size
     400             :  * @param off offeset at @a buf to use
     401             :  * @return number of bytes written to @a buf at @a off, or if
     402             :  *        @a buf is NULL, number of bytes required
     403             :  */
     404             : static size_t
     405          68 : serialize_denomination_key (const struct TALER_DenominationPublicKey *dk,
     406             :                             char *buf,
     407             :                             size_t off)
     408             : {
     409             :   char *pbuf;
     410             :   size_t pbuf_size;
     411             :   uint32_t be;
     412             : 
     413          68 :   pbuf_size = GNUNET_CRYPTO_rsa_public_key_encode (dk->rsa_public_key,
     414             :                                                    &pbuf);
     415          68 :   if (NULL == buf)
     416             :   {
     417          34 :     GNUNET_free (pbuf);
     418          34 :     return pbuf_size + sizeof (uint32_t);
     419             :   }
     420          34 :   be = htonl ((uint32_t) pbuf_size);
     421          34 :   memcpy (&buf[off],
     422             :           &be,
     423             :           sizeof (uint32_t));
     424          34 :   memcpy (&buf[off + sizeof (uint32_t)],
     425             :           pbuf,
     426             :           pbuf_size);
     427          34 :   GNUNET_free (pbuf);
     428          34 :   return pbuf_size + sizeof (uint32_t);
     429             : }
     430             : 
     431             : 
     432             : /**
     433             :  * Deserialize information about a denomination key.
     434             :  *
     435             :  * @param[out] dk information to deserialize
     436             :  * @param buf buffer to read data from
     437             :  * @param size number of bytes available at @a buf to use
     438             :  * @param[out] ok set to #GNUNET_NO to report errors
     439             :  * @return number of bytes read from @a buf, 0 on error
     440             :  */
     441             : static size_t
     442          68 : deserialize_denomination_key (struct TALER_DenominationPublicKey *dk,
     443             :                               const char *buf,
     444             :                               size_t size,
     445             :                               int *ok)
     446             : {
     447             :   size_t pbuf_size;
     448             :   uint32_t be;
     449             : 
     450          68 :   if (size < sizeof (uint32_t))
     451             :   {
     452           0 :     GNUNET_break (0);
     453           0 :     *ok = GNUNET_NO;
     454           0 :     return 0;
     455             :   }
     456          68 :   memcpy (&be,
     457             :           buf,
     458             :           sizeof (uint32_t));
     459          68 :   pbuf_size = ntohl (be);
     460          68 :   if (size < sizeof (uint32_t) + pbuf_size)
     461             :   {
     462           0 :     GNUNET_break (0);
     463           0 :     *ok = GNUNET_NO;
     464           0 :     return 0;
     465             :   }
     466             :   dk->rsa_public_key
     467          68 :     = GNUNET_CRYPTO_rsa_public_key_decode (&buf[sizeof (uint32_t)],
     468             :                                            pbuf_size);
     469             : 
     470          68 :   if (NULL == dk->rsa_public_key)
     471             :   {
     472           0 :     GNUNET_break (0);
     473           0 :     *ok = GNUNET_NO;
     474           0 :     return 0;
     475             :   }
     476          68 :   return sizeof (uint32_t) + pbuf_size;
     477             : }
     478             : 
     479             : 
     480             : /**
     481             :  * Serialize information about a fresh coin we are generating.
     482             :  *
     483             :  * @param fc information to serialize
     484             :  * @param buf buffer to write data in, NULL to just compute
     485             :  *            required size
     486             :  * @param off offeset at @a buf to use
     487             :  * @return number of bytes written to @a buf at @a off, or if
     488             :  *        @a buf is NULL, number of bytes required
     489             :  */
     490             : static size_t
     491         204 : serialize_fresh_coin (const struct TALER_PlanchetSecretsP *fc,
     492             :                       char *buf,
     493             :                       size_t off)
     494             : {
     495         204 :   if (NULL != buf)
     496         102 :     memcpy (&buf[off],
     497             :             fc,
     498             :             sizeof (struct TALER_PlanchetSecretsP));
     499         204 :   return sizeof (struct TALER_PlanchetSecretsP);
     500             : }
     501             : 
     502             : 
     503             : /**
     504             :  * Deserialize information about a fresh coin we are generating.
     505             :  *
     506             :  * @param[out] fc information to deserialize
     507             :  * @param buf buffer to read data from
     508             :  * @param size number of bytes available at @a buf to use
     509             :  * @param[out] ok set to #GNUNET_NO to report errors
     510             :  * @return number of bytes read from @a buf, 0 on error
     511             :  */
     512             : static size_t
     513         204 : deserialize_fresh_coin (struct TALER_PlanchetSecretsP *fc,
     514             :                         const char *buf,
     515             :                         size_t size,
     516             :                         int *ok)
     517             : {
     518         204 :   if (size < sizeof (struct TALER_PlanchetSecretsP))
     519             :   {
     520           0 :     GNUNET_break (0);
     521           0 :     *ok = GNUNET_NO;
     522           0 :     return 0;
     523             :   }
     524         204 :   memcpy (fc,
     525             :           buf,
     526             :           sizeof (struct TALER_PlanchetSecretsP));
     527         204 :   return sizeof (struct TALER_PlanchetSecretsP);
     528             : }
     529             : 
     530             : 
     531             : /**
     532             :  * Serialize melt data.
     533             :  *
     534             :  * @param md data to serialize
     535             :  * @param[out] res_size size of buffer returned
     536             :  * @return serialized melt data
     537             :  */
     538             : static char *
     539           2 : serialize_melt_data (const struct MeltData *md,
     540             :                      size_t *res_size)
     541             : {
     542             :   size_t size;
     543             :   size_t asize;
     544             :   char *buf;
     545             :   unsigned int i;
     546             :   unsigned int j;
     547             : 
     548           2 :   size = 0;
     549           2 :   asize = (size_t) -1; /* make the compiler happy */
     550           2 :   buf = NULL;
     551             :   /* we do 2 iterations, #1 to determine total size, #2 to
     552             :      actually construct the buffer */
     553             :   do {
     554           4 :     if (0 == size)
     555             :     {
     556           2 :       size = sizeof (struct MeltDataP);
     557             :     }
     558             :     else
     559             :     {
     560             :       struct MeltDataP *mdp;
     561             : 
     562           2 :       buf = GNUNET_malloc (size);
     563           2 :       asize = size; /* just for invariant check later */
     564           2 :       size = sizeof (struct MeltDataP);
     565           2 :       mdp = (struct MeltDataP *) buf;
     566           2 :       mdp->melt_session_hash = md->melt_session_hash;
     567           2 :       mdp->num_fresh_coins = htons (md->num_fresh_coins);
     568             :     }
     569           4 :     size += serialize_melted_coin (&md->melted_coin,
     570             :                                    buf,
     571             :                                    size);
     572          72 :     for (i=0;i<md->num_fresh_coins;i++)
     573          68 :       size += serialize_denomination_key (&md->fresh_pks[i],
     574             :                                           buf,
     575             :                                           size);
     576          16 :     for (i=0;i<TALER_CNC_KAPPA;i++)
     577         216 :       for(j=0;j<md->num_fresh_coins;j++)
     578         204 :         size += serialize_fresh_coin (&md->fresh_coins[i][j],
     579             :                                       buf,
     580             :                                       size);
     581           4 :   } while (NULL == buf);
     582           2 :   GNUNET_assert (size == asize);
     583           2 :   *res_size = size;
     584           2 :   return buf;
     585             : }
     586             : 
     587             : 
     588             : /**
     589             :  * Deserialize melt data.
     590             :  *
     591             :  * @param buf serialized data
     592             :  * @param buf_size size of @a buf
     593             :  * @return deserialized melt data, NULL on error
     594             :  */
     595             : static struct MeltData *
     596           4 : deserialize_melt_data (const char *buf,
     597             :                        size_t buf_size)
     598             : {
     599             :   struct MeltData *md;
     600             :   struct MeltDataP mdp;
     601             :   size_t off;
     602             :   int ok;
     603             : 
     604           4 :   if (buf_size < sizeof (struct MeltDataP))
     605           0 :     return NULL;
     606           4 :   memcpy (&mdp,
     607             :           buf,
     608             :           sizeof (struct MeltDataP));
     609           4 :   md = GNUNET_new (struct MeltData);
     610           4 :   md->melt_session_hash = mdp.melt_session_hash;
     611           4 :   md->num_fresh_coins = ntohs (mdp.num_fresh_coins);
     612           4 :   md->fresh_pks = GNUNET_new_array (md->num_fresh_coins,
     613             :                                     struct TALER_DenominationPublicKey);
     614          16 :   for (unsigned int i=0;i<TALER_CNC_KAPPA;i++)
     615          12 :     md->fresh_coins[i] = GNUNET_new_array (md->num_fresh_coins,
     616             :                                            struct TALER_PlanchetSecretsP);
     617           4 :   off = sizeof (struct MeltDataP);
     618           4 :   ok = GNUNET_YES;
     619           4 :   off += deserialize_melted_coin (&md->melted_coin,
     620             :                                   &buf[off],
     621             :                                   buf_size - off,
     622             :                                   &ok);
     623          72 :   for (unsigned int i=0;(i<md->num_fresh_coins)&&(GNUNET_YES == ok);i++)
     624          68 :     off += deserialize_denomination_key (&md->fresh_pks[i],
     625             :                                          &buf[off],
     626             :                                          buf_size - off,
     627             :                                          &ok);
     628             : 
     629          16 :   for (unsigned int i=0;i<TALER_CNC_KAPPA;i++)
     630         216 :     for (unsigned int j=0;(j<md->num_fresh_coins)&&(GNUNET_YES == ok);j++)
     631         204 :       off += deserialize_fresh_coin (&md->fresh_coins[i][j],
     632             :                                      &buf[off],
     633             :                                      buf_size - off,
     634             :                                      &ok);
     635           4 :   if (off != buf_size)
     636             :   {
     637           0 :     GNUNET_break (0);
     638           0 :     ok = GNUNET_NO;
     639             :   }
     640           4 :   if (GNUNET_YES != ok)
     641             :   {
     642           0 :     free_melt_data (md);
     643           0 :     GNUNET_free (md);
     644           0 :     return NULL;
     645             :   }
     646           4 :   return md;
     647             : }
     648             : 
     649             : 
     650             : /**
     651             :  * Melt (partially spent) coins to obtain fresh coins that are
     652             :  * unlinkable to the original coin(s).  Note that melting more
     653             :  * than one coin in a single request will make those coins linkable,
     654             :  * so the safest operation only melts one coin at a time.
     655             :  *
     656             :  * This API is typically used by a wallet.  Note that to ensure that
     657             :  * no money is lost in case of hardware failures, is operation does
     658             :  * not actually initiate the request. Instead, it generates a buffer
     659             :  * which the caller must store before proceeding with the actual call
     660             :  * to #TALER_EXCHANGE_refresh_melt() that will generate the request.
     661             :  *
     662             :  * This function does verify that the given request data is internally
     663             :  * consistent.  However, the @a melts_sigs are only verified if
     664             :  * @a check_sigs is set to #GNUNET_YES, as this may be relatively
     665             :  * expensive and should be redundant.
     666             :  *
     667             :  * Aside from some non-trivial cryptographic operations that might
     668             :  * take a bit of CPU time to complete, this function returns
     669             :  * its result immediately and does not start any asynchronous
     670             :  * processing.  This function is also thread-safe.
     671             :  *
     672             :  * @param melt_priv private key of the coin to melt
     673             :  * @param melt_amount amount specifying how much
     674             :  *                     the coin will contribute to the melt (including fee)
     675             :  * @param melt_sig signature affirming the
     676             :  *                   validity of the public keys corresponding to the
     677             :  *                   @a melt_priv private key
     678             :  * @param melt_pk denomination key information
     679             :  *                   record corresponding to the @a melt_sig
     680             :  *                   validity of the keys
     681             :  * @param check_sig verify the validity of the @a melt_sig signature
     682             :  * @param fresh_pks_len length of the @a pks array
     683             :  * @param fresh_pks array of @a pks_len denominations of fresh coins to create
     684             :  * @param[out] res_size set to the size of the return value, or 0 on error
     685             :  * @return NULL
     686             :  *         if the inputs are invalid (i.e. denomination key not with this exchange).
     687             :  *         Otherwise, pointer to a buffer of @a res_size to store persistently
     688             :  *         before proceeding to #TALER_EXCHANGE_refresh_melt().
     689             :  *         Non-null results should be freed using GNUNET_free().
     690             :  */
     691             : char *
     692           2 : TALER_EXCHANGE_refresh_prepare (const struct TALER_CoinSpendPrivateKeyP *melt_priv,
     693             :                                 const struct TALER_Amount *melt_amount,
     694             :                                 const struct TALER_DenominationSignature *melt_sig,
     695             :                                 const struct TALER_EXCHANGE_DenomPublicKey *melt_pk,
     696             :                                 int check_sig,
     697             :                                 unsigned int fresh_pks_len,
     698             :                                 const struct TALER_EXCHANGE_DenomPublicKey *fresh_pks,
     699             :                                 size_t *res_size)
     700             : {
     701             :   struct MeltData md;
     702             :   char *buf;
     703             :   struct GNUNET_HashContext *hash_context;
     704             :   struct TALER_Amount total;
     705             :   struct TALER_CoinSpendPublicKeyP coin_pub;
     706             :   struct TALER_TransferSecretP trans_sec[TALER_CNC_KAPPA];
     707             : 
     708           2 :   GNUNET_CRYPTO_eddsa_key_get_public (&melt_priv->eddsa_priv,
     709             :                                       &coin_pub.eddsa_pub);
     710           2 :   hash_context = GNUNET_CRYPTO_hash_context_start ();
     711             :   /* build up melt data structure */
     712           8 :   for (unsigned int i=0;i<TALER_CNC_KAPPA;i++)
     713             :   {
     714             :     struct GNUNET_CRYPTO_EcdhePrivateKey *tpk;
     715             :     struct TALER_TransferPublicKeyP tp;
     716             : 
     717           6 :     tpk = GNUNET_CRYPTO_ecdhe_key_create ();
     718           6 :     md.melted_coin.transfer_priv[i].ecdhe_priv = *tpk;
     719           6 :     GNUNET_free (tpk);
     720             : 
     721           6 :     GNUNET_CRYPTO_ecdhe_key_get_public (&md.melted_coin.transfer_priv[i].ecdhe_priv,
     722             :                                         &tp.ecdhe_pub);
     723           6 :     GNUNET_CRYPTO_hash_context_read (hash_context,
     724             :                                      &tp,
     725             :                                      sizeof (struct TALER_TransferPublicKeyP));
     726             :     /* DH */
     727          12 :     TALER_link_derive_transfer_secret  (melt_priv,
     728           6 :                                         &md.melted_coin.transfer_priv[i],
     729             :                                         &trans_sec[i]);
     730             :   }
     731           2 :   md.num_fresh_coins = fresh_pks_len;
     732           2 :   md.melted_coin.coin_priv = *melt_priv;
     733           2 :   md.melted_coin.melt_amount_with_fee = *melt_amount;
     734           2 :   md.melted_coin.fee_melt = melt_pk->fee_refresh;
     735           2 :   md.melted_coin.original_value = melt_pk->value;
     736             :   md.melted_coin.expire_deposit
     737           2 :     = melt_pk->expire_deposit;
     738             :   md.melted_coin.pub_key.rsa_public_key
     739           2 :     = GNUNET_CRYPTO_rsa_public_key_dup (melt_pk->key.rsa_public_key);
     740             :   md.melted_coin.sig.rsa_signature
     741           2 :     = GNUNET_CRYPTO_rsa_signature_dup (melt_sig->rsa_signature);
     742           2 :   md.fresh_pks = GNUNET_new_array (fresh_pks_len,
     743             :                                    struct TALER_DenominationPublicKey);
     744          36 :   for (unsigned int i=0;i<fresh_pks_len;i++)
     745          34 :     md.fresh_pks[i].rsa_public_key
     746          34 :       = GNUNET_CRYPTO_rsa_public_key_dup (fresh_pks[i].key.rsa_public_key);
     747           8 :   for (unsigned int i=0;i<TALER_CNC_KAPPA;i++)
     748             :   {
     749           6 :     md.fresh_coins[i] = GNUNET_new_array (fresh_pks_len,
     750             :                                           struct TALER_PlanchetSecretsP);
     751         108 :     for (unsigned int j=0;j<fresh_pks_len;j++)
     752             :     {
     753         102 :       TALER_planchet_setup_refresh (&trans_sec[i],
     754             :                                     j,
     755         102 :                                     &md.fresh_coins[i][j]);
     756             :     }
     757             :   }
     758             : 
     759             :   /* verify that melt_amount is above total cost */
     760           2 :   GNUNET_assert (GNUNET_OK ==
     761             :                  TALER_amount_get_zero (melt_amount->currency,
     762             :                                         &total));
     763          36 :   for (unsigned int j=0;j<fresh_pks_len;j++)
     764             :   {
     765          34 :     if ( (GNUNET_OK !=
     766          34 :           TALER_amount_add (&total,
     767             :                             &total,
     768          68 :                             &fresh_pks[j].value)) ||
     769             :          (GNUNET_OK !=
     770          34 :           TALER_amount_add (&total,
     771             :                             &total,
     772          34 :                             &fresh_pks[j].fee_withdraw)) )
     773             :     {
     774           0 :       GNUNET_break (0);
     775           0 :       free_melt_data (&md);
     776           0 :       return NULL;
     777             :     }
     778             :   }
     779           2 :   if (1 ==
     780           2 :       TALER_amount_cmp (&total,
     781             :                         melt_amount) )
     782             :   {
     783             :     /* Eh, this operation is more expensive than the
     784             :        @a melt_amount. This is not OK. */
     785           0 :     GNUNET_break (0);
     786           0 :     free_melt_data (&md);
     787           0 :     return NULL;
     788             :   }
     789             : 
     790             :   /* next, add all of the hashes from the denomination keys to the
     791             :      hash_context */
     792          36 :   for (unsigned int i=0;i<fresh_pks_len;i++)
     793             :   {
     794             :     char *buf;
     795             :     size_t buf_size;
     796             : 
     797          34 :     buf_size = GNUNET_CRYPTO_rsa_public_key_encode (fresh_pks[i].key.rsa_public_key,
     798             :                                                     &buf);
     799          34 :     GNUNET_CRYPTO_hash_context_read (hash_context,
     800             :                                      buf,
     801             :                                      buf_size);
     802          34 :     GNUNET_free (buf);
     803             :   }
     804             :   {
     805             :     struct TALER_AmountNBO melt_amountn;
     806             : 
     807           2 :     GNUNET_CRYPTO_hash_context_read (hash_context,
     808             :                                      &coin_pub,
     809             :                                      sizeof (struct TALER_CoinSpendPublicKeyP));
     810           2 :     TALER_amount_hton (&melt_amountn,
     811             :                        melt_amount);
     812           2 :     GNUNET_CRYPTO_hash_context_read (hash_context,
     813             :                                      &melt_amountn,
     814             :                                      sizeof (struct TALER_AmountNBO));
     815             : 
     816             :   }
     817           8 :   for (unsigned int i = 0; i < TALER_CNC_KAPPA; i++)
     818             :   {
     819         108 :     for (unsigned int j = 0; j < fresh_pks_len; j++)
     820             :     {
     821             :       const struct TALER_PlanchetSecretsP *fc; /* coin this is about */
     822             :       struct TALER_PlanchetDetail pd;
     823             : 
     824         102 :       fc = &md.fresh_coins[i][j];
     825         102 :       if (GNUNET_OK !=
     826         102 :           TALER_planchet_prepare (&md.fresh_pks[j],
     827             :                                   fc,
     828             :                                   &pd))
     829             :       {
     830           0 :         GNUNET_break_op (0);
     831           0 :         GNUNET_CRYPTO_hash_context_abort (hash_context);
     832           0 :         free_melt_data (&md);
     833           0 :         return NULL;
     834             :       }
     835         204 :       GNUNET_CRYPTO_hash_context_read (hash_context,
     836         102 :                                        pd.coin_ev,
     837             :                                        pd.coin_ev_size);
     838         102 :       GNUNET_free (pd.coin_ev);
     839             :     }
     840             :   }
     841           2 :   GNUNET_CRYPTO_hash_context_finish (hash_context,
     842             :                                      &md.melt_session_hash);
     843             : 
     844             :   /* finally, serialize everything */
     845           2 :   buf = serialize_melt_data (&md,
     846             :                              res_size);
     847           2 :   free_melt_data (&md);
     848           2 :   return buf;
     849             : }
     850             : 
     851             : 
     852             : /* ********************* /refresh/melt ***************************** */
     853             : 
     854             : 
     855             : /**
     856             :  * @brief A /refresh/melt Handle
     857             :  */
     858             : struct TALER_EXCHANGE_RefreshMeltHandle
     859             : {
     860             : 
     861             :   /**
     862             :    * The connection to exchange this request handle will use
     863             :    */
     864             :   struct TALER_EXCHANGE_Handle *exchange;
     865             : 
     866             :   /**
     867             :    * The url for this request.
     868             :    */
     869             :   char *url;
     870             : 
     871             :   /**
     872             :    * JSON encoding of the request to POST.
     873             :    */
     874             :   char *json_enc;
     875             : 
     876             :   /**
     877             :    * Handle for the request.
     878             :    */
     879             :   struct GNUNET_CURL_Job *job;
     880             : 
     881             :   /**
     882             :    * Function to call with refresh melt failure results.
     883             :    */
     884             :   TALER_EXCHANGE_RefreshMeltCallback melt_cb;
     885             : 
     886             :   /**
     887             :    * Closure for @e result_cb and @e melt_failure_cb.
     888             :    */
     889             :   void *melt_cb_cls;
     890             : 
     891             :   /**
     892             :    * Actual information about the melt operation.
     893             :    */
     894             :   struct MeltData *md;
     895             : };
     896             : 
     897             : 
     898             : /**
     899             :  * Verify that the signature on the "200 OK" response
     900             :  * from the exchange is valid.
     901             :  *
     902             :  * @param rmh melt handle
     903             :  * @param json json reply with the signature
     904             :  * @param[out] exchange_pub public key of the exchange used for the signature
     905             :  * @param[out] noreveal_index set to the noreveal index selected by the exchange
     906             :  * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
     907             :  */
     908             : static int
     909           1 : verify_refresh_melt_signature_ok (struct TALER_EXCHANGE_RefreshMeltHandle *rmh,
     910             :                                   const json_t *json,
     911             :                                   struct TALER_ExchangePublicKeyP *exchange_pub,
     912             :                                   uint16_t *noreveal_index)
     913             : {
     914             :   struct TALER_ExchangeSignatureP exchange_sig;
     915             :   const struct TALER_EXCHANGE_Keys *key_state;
     916           1 :   struct GNUNET_JSON_Specification spec[] = {
     917             :     GNUNET_JSON_spec_fixed_auto ("exchange_sig", &exchange_sig),
     918             :     GNUNET_JSON_spec_fixed_auto ("exchange_pub", exchange_pub),
     919             :     GNUNET_JSON_spec_uint16 ("noreveal_index", noreveal_index),
     920             :     GNUNET_JSON_spec_end()
     921             :   };
     922             :   struct TALER_RefreshMeltConfirmationPS confirm;
     923             : 
     924           1 :   if (GNUNET_OK !=
     925           1 :       GNUNET_JSON_parse (json,
     926             :                          spec,
     927             :                          NULL, NULL))
     928             :   {
     929           0 :     GNUNET_break_op (0);
     930           0 :     return GNUNET_SYSERR;
     931             :   }
     932             : 
     933             :   /* check that exchange signing key is permitted */
     934           1 :   key_state = TALER_EXCHANGE_get_keys (rmh->exchange);
     935           1 :   if (GNUNET_OK !=
     936           1 :       TALER_EXCHANGE_test_signing_key (key_state,
     937             :                                        exchange_pub))
     938             :   {
     939           0 :     GNUNET_break_op (0);
     940           0 :     return GNUNET_SYSERR;
     941             :   }
     942             : 
     943             :   /* check that noreveal index is in permitted range */
     944           1 :   if (TALER_CNC_KAPPA <= *noreveal_index)
     945             :   {
     946           0 :     GNUNET_break_op (0);
     947           0 :     return GNUNET_SYSERR;
     948             :   }
     949             : 
     950             :   /* verify signature by exchange */
     951           1 :   confirm.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT);
     952           1 :   confirm.purpose.size = htonl (sizeof (struct TALER_RefreshMeltConfirmationPS));
     953           1 :   confirm.session_hash = rmh->md->melt_session_hash;
     954           1 :   confirm.noreveal_index = htons (*noreveal_index);
     955           1 :   confirm.reserved = htons (0);
     956           1 :   if (GNUNET_OK !=
     957           1 :       GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT,
     958             :                                   &confirm.purpose,
     959             :                                   &exchange_sig.eddsa_signature,
     960           1 :                                   &exchange_pub->eddsa_pub))
     961             :   {
     962           0 :     GNUNET_break_op (0);
     963           0 :     return GNUNET_SYSERR;
     964             :   }
     965           1 :   return GNUNET_OK;
     966             : }
     967             : 
     968             : 
     969             : /**
     970             :  * Verify that the signatures on the "403 FORBIDDEN" response from the
     971             :  * exchange demonstrating customer double-spending are valid.
     972             :  *
     973             :  * @param rmh melt handle
     974             :  * @param json json reply with the signature(s) and transaction history
     975             :  * @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not
     976             :  */
     977             : static int
     978           1 : verify_refresh_melt_signature_forbidden (struct TALER_EXCHANGE_RefreshMeltHandle *rmh,
     979             :                                          const json_t *json)
     980             : {
     981             :   json_t *history;
     982             :   struct TALER_Amount original_value;
     983             :   struct TALER_Amount melt_value_with_fee;
     984             :   struct TALER_Amount total;
     985             :   struct TALER_CoinSpendPublicKeyP coin_pub;
     986           1 :   struct GNUNET_JSON_Specification spec[] = {
     987             :     GNUNET_JSON_spec_json ("history", &history),
     988             :     GNUNET_JSON_spec_fixed_auto ("coin_pub", &coin_pub),
     989             :     TALER_JSON_spec_amount ("original_value", &original_value),
     990             :     TALER_JSON_spec_amount ("requested_value", &melt_value_with_fee),
     991             :     GNUNET_JSON_spec_end()
     992             :   };
     993             :   const struct MeltedCoin *mc;
     994             : 
     995             :   /* parse JSON reply */
     996           1 :   if (GNUNET_OK !=
     997           1 :       GNUNET_JSON_parse (json,
     998             :                          spec,
     999             :                          NULL, NULL))
    1000             :   {
    1001           0 :     GNUNET_break_op (0);
    1002           0 :     return GNUNET_SYSERR;
    1003             :   }
    1004             : 
    1005             :   /* Find out which coin was deemed problematic by the exchange */
    1006           1 :   mc = &rmh->md->melted_coin;
    1007             : 
    1008             :   /* check basic coin properties */
    1009           1 :   if (0 != TALER_amount_cmp (&original_value,
    1010             :                              &mc->original_value))
    1011             :   {
    1012             :     /* We disagree on the value of the coin */
    1013           0 :     GNUNET_break_op (0);
    1014           0 :     json_decref (history);
    1015           0 :     return GNUNET_SYSERR;
    1016             :   }
    1017           1 :   if (0 != TALER_amount_cmp (&melt_value_with_fee,
    1018             :                              &mc->melt_amount_with_fee))
    1019             :   {
    1020             :     /* We disagree on the value of the coin */
    1021           0 :     GNUNET_break_op (0);
    1022           0 :     json_decref (history);
    1023           0 :     return GNUNET_SYSERR;
    1024             :   }
    1025             : 
    1026             :   /* verify coin history */
    1027           1 :   history = json_object_get (json,
    1028             :                              "history");
    1029           1 :   if (GNUNET_OK !=
    1030           1 :       TALER_EXCHANGE_verify_coin_history (original_value.currency,
    1031             :                                        &coin_pub,
    1032             :                                        history,
    1033             :                                        &total))
    1034             :   {
    1035           0 :     GNUNET_break_op (0);
    1036           0 :     json_decref (history);
    1037           0 :     return GNUNET_SYSERR;
    1038             :   }
    1039           1 :   json_decref (history);
    1040             : 
    1041             :   /* check if melt operation was really too expensive given history */
    1042           1 :   if (GNUNET_OK !=
    1043           1 :       TALER_amount_add (&total,
    1044             :                         &total,
    1045             :                         &melt_value_with_fee))
    1046             :   {
    1047             :     /* clearly not OK if our transaction would have caused
    1048             :        the overflow... */
    1049           0 :     return GNUNET_OK;
    1050             :   }
    1051             : 
    1052           1 :   if (0 >= TALER_amount_cmp (&total,
    1053             :                              &original_value))
    1054             :   {
    1055             :     /* transaction should have still fit */
    1056           0 :     GNUNET_break (0);
    1057           0 :     return GNUNET_SYSERR;
    1058             :   }
    1059             : 
    1060             :   /* everything OK, valid proof of double-spending was provided */
    1061           1 :   return GNUNET_OK;
    1062             : }
    1063             : 
    1064             : 
    1065             : /**
    1066             :  * Function called when we're done processing the
    1067             :  * HTTP /refresh/melt request.
    1068             :  *
    1069             :  * @param cls the `struct TALER_EXCHANGE_RefreshMeltHandle`
    1070             :  * @param response_code HTTP response code, 0 on error
    1071             :  * @param json parsed JSON result, NULL on error
    1072             :  */
    1073             : static void
    1074           2 : handle_refresh_melt_finished (void *cls,
    1075             :                               long response_code,
    1076             :                               const json_t *json)
    1077             : {
    1078           2 :   struct TALER_EXCHANGE_RefreshMeltHandle *rmh = cls;
    1079           2 :   uint16_t noreveal_index = TALER_CNC_KAPPA; /* invalid value */
    1080             :   struct TALER_ExchangePublicKeyP exchange_pub;
    1081             : 
    1082           2 :   rmh->job = NULL;
    1083           2 :   switch (response_code)
    1084             :   {
    1085             :   case 0:
    1086           0 :     break;
    1087             :   case MHD_HTTP_OK:
    1088           1 :     if (GNUNET_OK !=
    1089           1 :         verify_refresh_melt_signature_ok (rmh,
    1090             :                                           json,
    1091             :                                           &exchange_pub,
    1092             :                                           &noreveal_index))
    1093             :     {
    1094           0 :       GNUNET_break_op (0);
    1095           0 :       response_code = 0;
    1096             :     }
    1097           1 :     if (NULL != rmh->melt_cb)
    1098             :     {
    1099           1 :       rmh->melt_cb (rmh->melt_cb_cls,
    1100             :                     response_code,
    1101             :                     TALER_JSON_get_error_code (json),
    1102             :                     noreveal_index,
    1103             :                     (0 == response_code) ? NULL : &exchange_pub,
    1104             :                     json);
    1105           1 :       rmh->melt_cb = NULL;
    1106             :     }
    1107           1 :     break;
    1108             :   case MHD_HTTP_BAD_REQUEST:
    1109             :     /* This should never happen, either us or the exchange is buggy
    1110             :        (or API version conflict); just pass JSON reply to the application */
    1111           0 :     break;
    1112             :   case MHD_HTTP_FORBIDDEN:
    1113             :     /* Double spending; check signatures on transaction history */
    1114           1 :     if (GNUNET_OK !=
    1115           1 :         verify_refresh_melt_signature_forbidden (rmh,
    1116             :                                                  json))
    1117             :     {
    1118           0 :       GNUNET_break_op (0);
    1119           0 :       response_code = 0;
    1120             :     }
    1121           1 :     break;
    1122             :   case MHD_HTTP_UNAUTHORIZED:
    1123             :     /* Nothing really to verify, exchange says one of the signatures is
    1124             :        invalid; assuming we checked them, this should never happen, we
    1125             :        should pass the JSON reply to the application */
    1126           0 :     break;
    1127             :   case MHD_HTTP_NOT_FOUND:
    1128             :     /* Nothing really to verify, this should never
    1129             :        happen, we should pass the JSON reply to the application */
    1130           0 :     break;
    1131             :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    1132             :     /* Server had an internal issue; we should retry, but this API
    1133             :        leaves this to the application */
    1134           0 :     break;
    1135             :   default:
    1136             :     /* unexpected response code */
    1137           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1138             :                 "Unexpected response code %u\n",
    1139             :                 (unsigned int) response_code);
    1140           0 :     GNUNET_break (0);
    1141           0 :     response_code = 0;
    1142           0 :     break;
    1143             :   }
    1144           2 :   if (NULL != rmh->melt_cb)
    1145           1 :     rmh->melt_cb (rmh->melt_cb_cls,
    1146             :                   response_code,
    1147             :                   TALER_JSON_get_error_code (json),
    1148             :                   UINT16_MAX,
    1149             :                   NULL,
    1150             :                   json);
    1151           2 :   TALER_EXCHANGE_refresh_melt_cancel (rmh);
    1152           2 : }
    1153             : 
    1154             : 
    1155             : /**
    1156             :  * Convert a coin to be melted to the respective JSON encoding.
    1157             :  *
    1158             :  * @param melt_session_hash session hash to use
    1159             :  * @param mc coin to be melted
    1160             :  * @return JSON encoding of the melting request
    1161             :  */
    1162             : static json_t *
    1163           2 : melted_coin_to_json (const struct GNUNET_HashCode *melt_session_hash,
    1164             :                      const struct MeltedCoin *mc)
    1165             : {
    1166             :   struct TALER_CoinSpendSignatureP confirm_sig;
    1167             :   struct TALER_RefreshMeltCoinAffirmationPS melt;
    1168             : 
    1169           2 :   melt.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT);
    1170           2 :   melt.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS));
    1171           2 :   melt.session_hash = *melt_session_hash;
    1172           2 :   TALER_amount_hton (&melt.amount_with_fee,
    1173             :                      &mc->melt_amount_with_fee);
    1174           2 :   TALER_amount_hton (&melt.melt_fee,
    1175             :                      &mc->fee_melt);
    1176           2 :   GNUNET_CRYPTO_eddsa_key_get_public (&mc->coin_priv.eddsa_priv,
    1177             :                                       &melt.coin_pub.eddsa_pub);
    1178           2 :   GNUNET_CRYPTO_eddsa_sign (&mc->coin_priv.eddsa_priv,
    1179             :                             &melt.purpose,
    1180             :                             &confirm_sig.eddsa_signature);
    1181           6 :   return json_pack ("{s:o, s:o, s:o, s:o, s:o}",
    1182             :                     "coin_pub",
    1183             :                     GNUNET_JSON_from_data_auto (&melt.coin_pub),
    1184             :                     "denom_pub",
    1185           2 :                     GNUNET_JSON_from_rsa_public_key (mc->pub_key.rsa_public_key),
    1186             :                     "denom_sig",
    1187           2 :                     GNUNET_JSON_from_rsa_signature (mc->sig.rsa_signature),
    1188             :                     "confirm_sig",
    1189             :                     GNUNET_JSON_from_data_auto (&confirm_sig),
    1190             :                     "value_with_fee",
    1191             :                     TALER_JSON_from_amount (&mc->melt_amount_with_fee));
    1192             : }
    1193             : 
    1194             : 
    1195             : /**
    1196             :  * Submit a melt request to the exchange and get the exchange's
    1197             :  * response.
    1198             :  *
    1199             :  * This API is typically used by a wallet.  Note that to ensure that
    1200             :  * no money is lost in case of hardware failures, the provided
    1201             :  * argument should have been constructed using
    1202             :  * #TALER_EXCHANGE_refresh_prepare and committed to persistent storage
    1203             :  * prior to calling this function.
    1204             :  *
    1205             :  * @param exchange the exchange handle; the exchange must be ready to operate
    1206             :  * @param refresh_data_length size of the @a refresh_data (returned
    1207             :  *        in the `res_size` argument from #TALER_EXCHANGE_refresh_prepare())
    1208             :  * @param refresh_data the refresh data as returned from
    1209             :           #TALER_EXCHANGE_refresh_prepare())
    1210             :  * @param melt_cb the callback to call with the result
    1211             :  * @param melt_cb_cls closure for @a melt_cb
    1212             :  * @return a handle for this request; NULL if the argument was invalid.
    1213             :  *         In this case, neither callback will be called.
    1214             :  */
    1215             : struct TALER_EXCHANGE_RefreshMeltHandle *
    1216           2 : TALER_EXCHANGE_refresh_melt (struct TALER_EXCHANGE_Handle *exchange,
    1217             :                              size_t refresh_data_length,
    1218             :                              const char *refresh_data,
    1219             :                              TALER_EXCHANGE_RefreshMeltCallback melt_cb,
    1220             :                              void *melt_cb_cls)
    1221             : {
    1222             :   json_t *melt_obj;
    1223             :   json_t *new_denoms;
    1224             :   json_t *melt_coin;
    1225             :   json_t *coin_evs;
    1226             :   json_t *transfer_pubs;
    1227             :   json_t *tmp;
    1228             :   struct TALER_EXCHANGE_RefreshMeltHandle *rmh;
    1229             :   CURL *eh;
    1230             :   struct GNUNET_CURL_Context *ctx;
    1231             :   struct MeltData *md;
    1232             :   unsigned int i;
    1233             :   unsigned int j;
    1234             : 
    1235           2 :   GNUNET_assert (GNUNET_YES ==
    1236             :                  MAH_handle_is_ready (exchange));
    1237           2 :   md = deserialize_melt_data (refresh_data,
    1238             :                               refresh_data_length);
    1239           2 :   if (NULL == md)
    1240             :   {
    1241           0 :     GNUNET_break (0);
    1242           0 :     return NULL;
    1243             :   }
    1244             : 
    1245             :   /* build JSON request, each of the 4 arrays first */
    1246           2 :   new_denoms = json_array ();
    1247           2 :   melt_coin = melted_coin_to_json (&md->melt_session_hash,
    1248           2 :                                    &md->melted_coin);
    1249           2 :   coin_evs = json_array ();
    1250           2 :   transfer_pubs = json_array ();
    1251             : 
    1252             :   /* now transfer_pubs */
    1253           8 :   for (j=0;j<TALER_CNC_KAPPA;j++)
    1254             :   {
    1255           6 :     const struct MeltedCoin *mc = &md->melted_coin;
    1256             :     struct TALER_TransferPublicKeyP transfer_pub;
    1257             : 
    1258           6 :     GNUNET_CRYPTO_ecdhe_key_get_public (&mc->transfer_priv[j].ecdhe_priv,
    1259             :                                         &transfer_pub.ecdhe_pub);
    1260           6 :     GNUNET_assert (0 ==
    1261             :                    json_array_append_new (transfer_pubs,
    1262             :                                           GNUNET_JSON_from_data_auto (&transfer_pub)));
    1263             :   }
    1264             : 
    1265             :   /* now new_denoms */
    1266          36 :   for (i=0;i<md->num_fresh_coins;i++)
    1267             :   {
    1268          34 :     GNUNET_assert (0 ==
    1269             :                    json_array_append_new (new_denoms,
    1270             :                                           GNUNET_JSON_from_rsa_public_key
    1271             :                                           (md->fresh_pks[i].rsa_public_key)));
    1272             :   }
    1273             : 
    1274             :   /* now coin_evs */
    1275           8 :   for (j=0;j<TALER_CNC_KAPPA;j++)
    1276             :   {
    1277           6 :     tmp = json_array ();
    1278         108 :     for (i=0;i<md->num_fresh_coins;i++)
    1279             :     {
    1280         102 :       const struct TALER_PlanchetSecretsP *fc = &md->fresh_coins[j][i];
    1281             :       struct TALER_PlanchetDetail pd;
    1282             : 
    1283         102 :       if (GNUNET_OK !=
    1284         102 :           TALER_planchet_prepare (&md->fresh_pks[i],
    1285             :                                   fc,
    1286             :                                   &pd))
    1287             :       {
    1288             :         /* This should have been noticed during the preparation stage. */
    1289           0 :         GNUNET_break (0);
    1290           0 :         json_decref (new_denoms);
    1291           0 :         json_decref (tmp);
    1292           0 :         json_decref (coin_evs);
    1293           0 :         json_decref (melt_coin);
    1294           0 :         json_decref (transfer_pubs);
    1295           0 :         return NULL;
    1296             :       }
    1297         102 :       GNUNET_assert (0 ==
    1298             :                      json_array_append_new (tmp,
    1299             :                                             GNUNET_JSON_from_data (pd.coin_ev,
    1300             :                                                                    pd.coin_ev_size)));
    1301         102 :       GNUNET_free (pd.coin_ev);
    1302             :     }
    1303           6 :     GNUNET_assert (0 ==
    1304             :                    json_array_append_new (coin_evs,
    1305             :                                           tmp));
    1306             :   }
    1307             : 
    1308             :   /* finally, assemble main JSON request from constitutent arrays */
    1309           2 :   melt_obj = json_pack ("{s:o, s:o, s:o, s:o}",
    1310             :                         "new_denoms", new_denoms,
    1311             :                         "melt_coin", melt_coin,
    1312             :                         "coin_evs", coin_evs,
    1313             :                         "transfer_pubs", transfer_pubs);
    1314           2 :   if (NULL == melt_obj)
    1315             :   {
    1316           0 :     GNUNET_break (0);
    1317           0 :     return NULL;
    1318             :   }
    1319             : 
    1320             :   /* and now we can at last begin the actual request handling */
    1321           2 :   rmh = GNUNET_new (struct TALER_EXCHANGE_RefreshMeltHandle);
    1322           2 :   rmh->exchange = exchange;
    1323           2 :   rmh->melt_cb = melt_cb;
    1324           2 :   rmh->melt_cb_cls = melt_cb_cls;
    1325           2 :   rmh->md = md;
    1326           2 :   rmh->url = MAH_path_to_url (exchange,
    1327             :                               "/refresh/melt");
    1328             : 
    1329           2 :   eh = curl_easy_init ();
    1330           2 :   GNUNET_assert (NULL != (rmh->json_enc =
    1331             :                           json_dumps (melt_obj,
    1332             :                                       JSON_COMPACT)));
    1333           2 :   json_decref (melt_obj);
    1334           2 :   GNUNET_assert (CURLE_OK ==
    1335             :                  curl_easy_setopt (eh,
    1336             :                                    CURLOPT_URL,
    1337             :                                    rmh->url));
    1338           2 :   GNUNET_assert (CURLE_OK ==
    1339             :                  curl_easy_setopt (eh,
    1340             :                                    CURLOPT_POSTFIELDS,
    1341             :                                    rmh->json_enc));
    1342           2 :   GNUNET_assert (CURLE_OK ==
    1343             :                  curl_easy_setopt (eh,
    1344             :                                    CURLOPT_POSTFIELDSIZE,
    1345             :                                    strlen (rmh->json_enc)));
    1346           2 :   ctx = MAH_handle_to_context (exchange);
    1347           2 :   rmh->job = GNUNET_CURL_job_add (ctx,
    1348             :                           eh,
    1349             :                           GNUNET_YES,
    1350             :                           &handle_refresh_melt_finished,
    1351             :                           rmh);
    1352           2 :   return rmh;
    1353             : }
    1354             : 
    1355             : 
    1356             : /**
    1357             :  * Cancel a refresh execute request.  This function cannot be used
    1358             :  * on a request handle if either callback was already invoked.
    1359             :  *
    1360             :  * @param rmh the refresh melt handle
    1361             :  */
    1362             : void
    1363           2 : TALER_EXCHANGE_refresh_melt_cancel (struct TALER_EXCHANGE_RefreshMeltHandle *rmh)
    1364             : {
    1365           2 :   if (NULL != rmh->job)
    1366             :   {
    1367           0 :     GNUNET_CURL_job_cancel (rmh->job);
    1368           0 :     rmh->job = NULL;
    1369             :   }
    1370           2 :   free_melt_data (rmh->md); /* does not free 'md' itself */
    1371           2 :   GNUNET_free (rmh->md);
    1372           2 :   GNUNET_free (rmh->url);
    1373           2 :   GNUNET_free (rmh->json_enc);
    1374           2 :   GNUNET_free (rmh);
    1375           2 : }
    1376             : 
    1377             : 
    1378             : /* ********************* /refresh/reveal ***************************** */
    1379             : 
    1380             : 
    1381             : /**
    1382             :  * @brief A /refresh/reveal Handle
    1383             :  */
    1384             : struct TALER_EXCHANGE_RefreshRevealHandle
    1385             : {
    1386             : 
    1387             :   /**
    1388             :    * The connection to exchange this request handle will use
    1389             :    */
    1390             :   struct TALER_EXCHANGE_Handle *exchange;
    1391             : 
    1392             :   /**
    1393             :    * The url for this request.
    1394             :    */
    1395             :   char *url;
    1396             : 
    1397             :   /**
    1398             :    * JSON encoding of the request to POST.
    1399             :    */
    1400             :   char *json_enc;
    1401             : 
    1402             :   /**
    1403             :    * Handle for the request.
    1404             :    */
    1405             :   struct GNUNET_CURL_Job *job;
    1406             : 
    1407             :   /**
    1408             :    * Function to call with the result.
    1409             :    */
    1410             :   TALER_EXCHANGE_RefreshRevealCallback reveal_cb;
    1411             : 
    1412             :   /**
    1413             :    * Closure for @e reveal_cb.
    1414             :    */
    1415             :   void *reveal_cb_cls;
    1416             : 
    1417             :   /**
    1418             :    * Actual information about the melt operation.
    1419             :    */
    1420             :   struct MeltData *md;
    1421             : 
    1422             :   /**
    1423             :    * The index selected by the exchange in cut-and-choose to not be revealed.
    1424             :    */
    1425             :   uint16_t noreveal_index;
    1426             : 
    1427             : };
    1428             : 
    1429             : 
    1430             : /**
    1431             :  * We got a 200 OK response for the /refresh/reveal operation.
    1432             :  * Extract the coin signatures and return them to the caller.
    1433             :  * The signatures we get from the exchange is for the blinded value.
    1434             :  * Thus, we first must unblind them and then should verify their
    1435             :  * validity.
    1436             :  *
    1437             :  * If everything checks out, we return the unblinded signatures
    1438             :  * to the application via the callback.
    1439             :  *
    1440             :  * @param rrh operation handle
    1441             :  * @param json reply from the exchange
    1442             :  * @param[out] coin_privs array of length `num_fresh_coins`, initialized to contain private keys
    1443             :  * @param[out] sigs array of length `num_fresh_coins`, initialized to cointain RSA signatures
    1444             :  * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
    1445             :  */
    1446             : static int
    1447           2 : refresh_reveal_ok (struct TALER_EXCHANGE_RefreshRevealHandle *rrh,
    1448             :                    const json_t *json,
    1449             :                    struct TALER_CoinSpendPrivateKeyP *coin_privs,
    1450             :                    struct TALER_DenominationSignature *sigs)
    1451             : {
    1452             :   unsigned int i;
    1453             :   json_t *jsona;
    1454           2 :   struct GNUNET_JSON_Specification outer_spec[] = {
    1455             :     GNUNET_JSON_spec_json ("ev_sigs", &jsona),
    1456             :     GNUNET_JSON_spec_end()
    1457             :   };
    1458             : 
    1459           2 :   if (GNUNET_OK !=
    1460           2 :       GNUNET_JSON_parse (json,
    1461             :                          outer_spec,
    1462             :                          NULL, NULL))
    1463             :   {
    1464           0 :     GNUNET_break_op (0);
    1465           0 :     return GNUNET_SYSERR;
    1466             :   }
    1467           2 :   if (! json_is_array (jsona))
    1468             :   {
    1469             :     /* We expected an array of coins */
    1470           0 :     GNUNET_break_op (0);
    1471           0 :     GNUNET_JSON_parse_free (outer_spec);
    1472           0 :     return GNUNET_SYSERR;
    1473             :   }
    1474           2 :   if (rrh->md->num_fresh_coins != json_array_size (jsona))
    1475             :   {
    1476             :     /* Number of coins generated does not match our expectation */
    1477           0 :     GNUNET_break_op (0);
    1478           0 :     GNUNET_JSON_parse_free (outer_spec);
    1479           0 :     return GNUNET_SYSERR;
    1480             :   }
    1481          72 :   for (i=0;i<rrh->md->num_fresh_coins;i++)
    1482             :   {
    1483             :     const struct TALER_PlanchetSecretsP *fc;
    1484             :     struct TALER_DenominationPublicKey *pk;
    1485             :     json_t *jsonai;
    1486             :     struct GNUNET_CRYPTO_RsaSignature *blind_sig;
    1487             :     struct TALER_CoinSpendPublicKeyP coin_pub;
    1488             :     struct GNUNET_HashCode coin_hash;
    1489          34 :     struct GNUNET_JSON_Specification spec[] = {
    1490             :       GNUNET_JSON_spec_rsa_signature ("ev_sig", &blind_sig),
    1491             :       GNUNET_JSON_spec_end()
    1492             :     };
    1493             :     struct TALER_FreshCoin coin;
    1494             : 
    1495          34 :     fc = &rrh->md->fresh_coins[rrh->noreveal_index][i];
    1496          34 :     pk = &rrh->md->fresh_pks[i];
    1497          34 :     jsonai = json_array_get (jsona, i);
    1498          34 :     GNUNET_assert (NULL != jsonai);
    1499             : 
    1500          34 :     if (GNUNET_OK !=
    1501          34 :         GNUNET_JSON_parse (jsonai,
    1502             :                            spec,
    1503             :                            NULL, NULL))
    1504             :     {
    1505           0 :       GNUNET_break_op (0);
    1506           0 :       GNUNET_JSON_parse_free (outer_spec);
    1507           0 :       return GNUNET_SYSERR;
    1508             :     }
    1509             : 
    1510             :     /* needed to verify the signature, and we didn't store it earlier,
    1511             :        hence recomputing it here... */
    1512          34 :     GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
    1513             :                                         &coin_pub.eddsa_pub);
    1514          34 :     GNUNET_CRYPTO_hash (&coin_pub.eddsa_pub,
    1515             :                         sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
    1516             :                         &coin_hash);
    1517          34 :     if (GNUNET_OK !=
    1518          34 :         TALER_planchet_to_coin (pk,
    1519             :                                 blind_sig,
    1520             :                                 fc,
    1521             :                                 &coin_hash,
    1522             :                                 &coin))
    1523             :     {
    1524           0 :       GNUNET_break_op (0);
    1525           0 :       GNUNET_CRYPTO_rsa_signature_free (blind_sig);
    1526           0 :       GNUNET_JSON_parse_free (outer_spec);
    1527           0 :       return GNUNET_SYSERR;
    1528             :     }
    1529          34 :     GNUNET_CRYPTO_rsa_signature_free (blind_sig);
    1530          34 :     coin_privs[i] = coin.coin_priv;
    1531          34 :     sigs[i] = coin.sig;
    1532             :   }
    1533           2 :   GNUNET_JSON_parse_free (outer_spec);
    1534           2 :   return GNUNET_OK;
    1535             : }
    1536             : 
    1537             : 
    1538             : /**
    1539             :  * Function called when we're done processing the
    1540             :  * HTTP /refresh/reveal request.
    1541             :  *
    1542             :  * @param cls the `struct TALER_EXCHANGE_RefreshHandle`
    1543             :  * @param response_code HTTP response code, 0 on error
    1544             :  * @param json parsed JSON result, NULL on error
    1545             :  */
    1546             : static void
    1547           2 : handle_refresh_reveal_finished (void *cls,
    1548             :                                 long response_code,
    1549             :                                 const json_t *json)
    1550             : {
    1551           2 :   struct TALER_EXCHANGE_RefreshRevealHandle *rrh = cls;
    1552             : 
    1553           2 :   rrh->job = NULL;
    1554           2 :   switch (response_code)
    1555             :   {
    1556             :   case 0:
    1557           0 :     break;
    1558             :   case MHD_HTTP_OK:
    1559           2 :     {
    1560           2 :       struct TALER_CoinSpendPrivateKeyP coin_privs[rrh->md->num_fresh_coins];
    1561           2 :       struct TALER_DenominationSignature sigs[rrh->md->num_fresh_coins];
    1562             :       unsigned int i;
    1563             :       int ret;
    1564             : 
    1565           2 :       memset (sigs, 0, sizeof (sigs));
    1566           2 :       ret = refresh_reveal_ok (rrh,
    1567             :                                json,
    1568             :                                coin_privs,
    1569             :                                sigs);
    1570           2 :       if (GNUNET_OK != ret)
    1571             :       {
    1572           0 :         response_code = 0;
    1573             :       }
    1574             :       else
    1575             :       {
    1576           4 :         rrh->reveal_cb (rrh->reveal_cb_cls,
    1577             :                         MHD_HTTP_OK,
    1578             :                         TALER_EC_NONE,
    1579           2 :                         rrh->md->num_fresh_coins,
    1580             :                         coin_privs,
    1581             :                         sigs,
    1582             :                         json);
    1583           2 :         rrh->reveal_cb = NULL;
    1584             :       }
    1585          36 :       for (i=0;i<rrh->md->num_fresh_coins;i++)
    1586          34 :         if (NULL != sigs[i].rsa_signature)
    1587          34 :           GNUNET_CRYPTO_rsa_signature_free (sigs[i].rsa_signature);
    1588             :     }
    1589           2 :     break;
    1590             :   case MHD_HTTP_BAD_REQUEST:
    1591             :     /* This should never happen, either us or the exchange is buggy
    1592             :        (or API version conflict); just pass JSON reply to the application */
    1593           0 :     break;
    1594             :   case MHD_HTTP_CONFLICT:
    1595             :     /* Nothing really to verify, exchange says our reveal is inconsitent
    1596             :        with our commitment, so either side is buggy; we
    1597             :        should pass the JSON reply to the application */
    1598           0 :     break;
    1599             :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    1600             :     /* Server had an internal issue; we should retry, but this API
    1601             :        leaves this to the application */
    1602           0 :     break;
    1603             :   default:
    1604             :     /* unexpected response code */
    1605           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1606             :                 "Unexpected response code %u\n",
    1607             :                 (unsigned int) response_code);
    1608           0 :     GNUNET_break (0);
    1609           0 :     response_code = 0;
    1610           0 :     break;
    1611             :   }
    1612           2 :   if (NULL != rrh->reveal_cb)
    1613           0 :     rrh->reveal_cb (rrh->reveal_cb_cls,
    1614             :                     response_code,
    1615             :                     TALER_JSON_get_error_code (json),
    1616             :                     0,
    1617             :                     NULL,
    1618             :                     NULL,
    1619             :                     json);
    1620           2 :   TALER_EXCHANGE_refresh_reveal_cancel (rrh);
    1621           2 : }
    1622             : 
    1623             : 
    1624             : /**
    1625             :  * Submit a /refresh/reval request to the exchange and get the exchange's
    1626             :  * response.
    1627             :  *
    1628             :  * This API is typically used by a wallet.  Note that to ensure that
    1629             :  * no money is lost in case of hardware failures, the provided
    1630             :  * arguments should have been committed to persistent storage
    1631             :  * prior to calling this function.
    1632             :  *
    1633             :  * @param exchange the exchange handle; the exchange must be ready to operate
    1634             :  * @param refresh_data_length size of the @a refresh_data (returned
    1635             :  *        in the `res_size` argument from #TALER_EXCHANGE_refresh_prepare())
    1636             :  * @param refresh_data the refresh data as returned from
    1637             :           #TALER_EXCHANGE_refresh_prepare())
    1638             :  * @param noreveal_index response from the exchange to the
    1639             :  *        #TALER_EXCHANGE_refresh_melt() invocation
    1640             :  * @param reveal_cb the callback to call with the final result of the
    1641             :  *        refresh operation
    1642             :  * @param reveal_cb_cls closure for the above callback
    1643             :  * @return a handle for this request; NULL if the argument was invalid.
    1644             :  *         In this case, neither callback will be called.
    1645             :  */
    1646             : struct TALER_EXCHANGE_RefreshRevealHandle *
    1647           2 : TALER_EXCHANGE_refresh_reveal (struct TALER_EXCHANGE_Handle *exchange,
    1648             :                                size_t refresh_data_length,
    1649             :                                const char *refresh_data,
    1650             :                                uint16_t noreveal_index,
    1651             :                                TALER_EXCHANGE_RefreshRevealCallback reveal_cb,
    1652             :                                void *reveal_cb_cls)
    1653             : {
    1654             :   struct TALER_EXCHANGE_RefreshRevealHandle *rrh;
    1655             :   json_t *transfer_privs;
    1656             :   json_t *reveal_obj;
    1657             :   CURL *eh;
    1658             :   struct GNUNET_CURL_Context *ctx;
    1659             :   struct MeltData *md;
    1660             :   unsigned int j;
    1661             : 
    1662           2 :   GNUNET_assert (GNUNET_YES ==
    1663             :                  MAH_handle_is_ready (exchange));
    1664           2 :   md = deserialize_melt_data (refresh_data,
    1665             :                               refresh_data_length);
    1666           2 :   if (NULL == md)
    1667             :   {
    1668           0 :     GNUNET_break (0);
    1669           0 :     return NULL;
    1670             :   }
    1671           2 :   if (noreveal_index >= TALER_CNC_KAPPA)
    1672             :   {
    1673             :     /* We check this here, as it would be really bad to below just
    1674             :        disclose all the transfer keys. Note that this error should
    1675             :        have been caught way earlier when the exchange replied, but maybe
    1676             :        we had some internal corruption that changed the value... */
    1677           0 :     GNUNET_break (0);
    1678           0 :     return NULL;
    1679             :   }
    1680             : 
    1681             :   /* build array of transfer private keys */
    1682           2 :   transfer_privs = json_array ();
    1683           8 :   for (j=0;j<TALER_CNC_KAPPA;j++)
    1684             :   {
    1685           6 :     if (j == noreveal_index)
    1686             :     {
    1687             :       /* This is crucial: exclude the transfer key for the
    1688             :          noreval index! */
    1689           2 :       continue;
    1690             :     }
    1691           4 :     GNUNET_assert (0 ==
    1692             :                    json_array_append_new (transfer_privs,
    1693             :                                           GNUNET_JSON_from_data_auto (&md->melted_coin.transfer_priv[j])));
    1694             :   }
    1695             : 
    1696             :   /* build main JSON request */
    1697           2 :   reveal_obj = json_pack ("{s:o, s:o}",
    1698             :                           "session_hash",
    1699           2 :                           GNUNET_JSON_from_data_auto (&md->melt_session_hash),
    1700             :                           "transfer_privs",
    1701             :                           transfer_privs);
    1702           2 :   if (NULL == reveal_obj)
    1703             :   {
    1704           0 :     GNUNET_break (0);
    1705           0 :     return NULL;
    1706             :   }
    1707             : 
    1708             :   /* finally, we can actually issue the request */
    1709           2 :   rrh = GNUNET_new (struct TALER_EXCHANGE_RefreshRevealHandle);
    1710           2 :   rrh->exchange = exchange;
    1711           2 :   rrh->noreveal_index = noreveal_index;
    1712           2 :   rrh->reveal_cb = reveal_cb;
    1713           2 :   rrh->reveal_cb_cls = reveal_cb_cls;
    1714           2 :   rrh->md = md;
    1715           2 :   rrh->url = MAH_path_to_url (rrh->exchange,
    1716             :                               "/refresh/reveal");
    1717             : 
    1718           2 :   eh = curl_easy_init ();
    1719           2 :   GNUNET_assert (NULL != (rrh->json_enc =
    1720             :                           json_dumps (reveal_obj,
    1721             :                                       JSON_COMPACT)));
    1722           2 :   json_decref (reveal_obj);
    1723           2 :   GNUNET_assert (CURLE_OK ==
    1724             :                  curl_easy_setopt (eh,
    1725             :                                    CURLOPT_URL,
    1726             :                                    rrh->url));
    1727           2 :   GNUNET_assert (CURLE_OK ==
    1728             :                  curl_easy_setopt (eh,
    1729             :                                    CURLOPT_POSTFIELDS,
    1730             :                                    rrh->json_enc));
    1731           2 :   GNUNET_assert (CURLE_OK ==
    1732             :                  curl_easy_setopt (eh,
    1733             :                                    CURLOPT_POSTFIELDSIZE,
    1734             :                                    strlen (rrh->json_enc)));
    1735           2 :   ctx = MAH_handle_to_context (rrh->exchange);
    1736           2 :   rrh->job = GNUNET_CURL_job_add (ctx,
    1737             :                                   eh,
    1738             :                                   GNUNET_YES,
    1739             :                                   &handle_refresh_reveal_finished,
    1740             :                                   rrh);
    1741           2 :   return rrh;
    1742             : }
    1743             : 
    1744             : 
    1745             : /**
    1746             :  * Cancel a refresh reveal request.  This function cannot be used
    1747             :  * on a request handle if the callback was already invoked.
    1748             :  *
    1749             :  * @param rrh the refresh reval handle
    1750             :  */
    1751             : void
    1752           2 : TALER_EXCHANGE_refresh_reveal_cancel (struct TALER_EXCHANGE_RefreshRevealHandle *rrh)
    1753             : {
    1754           2 :   if (NULL != rrh->job)
    1755             :   {
    1756           0 :     GNUNET_CURL_job_cancel (rrh->job);
    1757           0 :     rrh->job = NULL;
    1758             :   }
    1759           2 :   GNUNET_free (rrh->url);
    1760           2 :   GNUNET_free (rrh->json_enc);
    1761           2 :   free_melt_data (rrh->md); /* does not free 'md' itself */
    1762           2 :   GNUNET_free (rrh->md);
    1763           2 :   GNUNET_free (rrh);
    1764           2 : }
    1765             : 
    1766             : 
    1767             : /* end of exchange_api_refresh.c */

Generated by: LCOV version 1.13