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

Generated by: LCOV version 1.13