LCOV - code coverage report
Current view: top level - exchange - taler-exchange-httpd_refresh_reveal.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 162 245 66.1 %
Date: 2017-11-25 11:31:41 Functions: 7 8 87.5 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014-2017 Inria & GNUnet e.V.
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU Affero 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 Affero General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU Affero General Public License along with
      14             :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : /**
      17             :  * @file taler-exchange-httpd_refresh_reveal.c
      18             :  * @brief Handle /refresh/reveal requests
      19             :  * @author Florian Dold
      20             :  * @author Benedikt Mueller
      21             :  * @author Christian Grothoff
      22             :  */
      23             : #include "platform.h"
      24             : #include <gnunet/gnunet_util_lib.h>
      25             : #include <jansson.h>
      26             : #include <microhttpd.h>
      27             : #include "taler-exchange-httpd_parsing.h"
      28             : #include "taler-exchange-httpd_mhd.h"
      29             : #include "taler-exchange-httpd_refresh_reveal.h"
      30             : #include "taler-exchange-httpd_responses.h"
      31             : #include "taler-exchange-httpd_keystate.h"
      32             : 
      33             : 
      34             : /**
      35             :  * Send a response for "/refresh/reveal".
      36             :  *
      37             :  * @param connection the connection to send the response to
      38             :  * @param num_newcoins number of new coins for which we reveal data
      39             :  * @param sigs array of @a num_newcoins signatures revealed
      40             :  * @return a MHD result code
      41             :  */
      42             : static int
      43           2 : reply_refresh_reveal_success (struct MHD_Connection *connection,
      44             :                               unsigned int num_newcoins,
      45             :                               const struct TALER_DenominationSignature *sigs)
      46             : {
      47             :   json_t *root;
      48             :   json_t *obj;
      49             :   json_t *list;
      50             :   int ret;
      51             : 
      52           2 :   list = json_array ();
      53          38 :   for (unsigned int newcoin_index = 0;
      54             :        newcoin_index < num_newcoins;
      55          34 :        newcoin_index++)
      56             :   {
      57          34 :     obj = json_object ();
      58          34 :     json_object_set_new (obj,
      59             :                          "ev_sig",
      60          34 :                          GNUNET_JSON_from_rsa_signature (sigs[newcoin_index].rsa_signature));
      61          34 :     GNUNET_assert (0 ==
      62             :                    json_array_append_new (list,
      63             :                                           obj));
      64             :   }
      65           2 :   root = json_object ();
      66           2 :   json_object_set_new (root,
      67             :                        "ev_sigs",
      68             :                        list);
      69           2 :   ret = TEH_RESPONSE_reply_json (connection,
      70             :                                  root,
      71             :                                  MHD_HTTP_OK);
      72           2 :   json_decref (root);
      73           2 :   return ret;
      74             : }
      75             : 
      76             : 
      77             : /**
      78             :  * Send a response for a failed "/refresh/reveal", where the
      79             :  * revealed value(s) do not match the original commitment.
      80             :  *
      81             :  * @param connection the connection to send the response to
      82             :  * @param session info about session
      83             :  * @param commit_coins array of @a num_newcoins committed envelopes at offset @a gamma
      84             :  * @param denom_pubs array of @a num_newcoins denomination keys for the new coins
      85             :  * @param gamma_tp transfer public key at offset @a gamma
      86             :  * @return a MHD result code
      87             :  */
      88             : static int
      89           0 : reply_refresh_reveal_missmatch (struct MHD_Connection *connection,
      90             :                                 const struct TALER_EXCHANGEDB_RefreshSession *session,
      91             :                                 const struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins,
      92             :                                 const struct TALER_DenominationPublicKey *denom_pubs,
      93             :                                 const struct TALER_TransferPublicKeyP *gamma_tp)
      94             : {
      95             :   json_t *info_new;
      96             :   json_t *info_commit_k;
      97             : 
      98           0 :   info_new = json_array ();
      99           0 :   info_commit_k = json_array ();
     100           0 :   for (unsigned int i=0;i<session->num_newcoins;i++)
     101             :   {
     102             :     const struct TALER_EXCHANGEDB_RefreshCommitCoin *cc;
     103             :     json_t *cc_json;
     104             : 
     105           0 :     GNUNET_assert (0 ==
     106             :                    json_array_append_new (info_new,
     107             :                                           GNUNET_JSON_from_rsa_public_key (denom_pubs[i].rsa_public_key)));
     108             : 
     109           0 :     cc = &commit_coins[i];
     110           0 :     cc_json = json_pack ("{s:o}",
     111             :                          "coin_ev",
     112           0 :                          GNUNET_JSON_from_data (cc->coin_ev,
     113             :                                                 cc->coin_ev_size));
     114           0 :     GNUNET_assert (0 ==
     115             :                    json_array_append_new (info_commit_k,
     116             :                                           cc_json));
     117             :   }
     118           0 :   return TEH_RESPONSE_reply_json_pack (connection,
     119             :                                        MHD_HTTP_CONFLICT,
     120             :                                        "{s:s, s:I, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:i}",
     121             :                                        "error", "commitment violation",
     122             :                                        "code", (json_int_t) TALER_EC_REFRESH_REVEAL_COMMITMENT_VIOLATION,
     123           0 :                                        "coin_sig", GNUNET_JSON_from_data_auto (&session->melt.coin_sig),
     124           0 :                                        "coin_pub", GNUNET_JSON_from_data_auto (&session->melt.coin.coin_pub),
     125             :                                        "melt_amount_with_fee", TALER_JSON_from_amount (&session->melt.amount_with_fee),
     126             :                                        "melt_fee", TALER_JSON_from_amount (&session->melt.melt_fee),
     127             :                                        "newcoin_infos", info_new,
     128             :                                        "commit_infos", info_commit_k,
     129             :                                        "gamma_tp", GNUNET_JSON_from_data_auto (gamma_tp),
     130           0 :                                        "gamma", (int) session->noreveal_index);
     131             : }
     132             : 
     133             : 
     134             : /**
     135             :  * Check if the given @a transfer_privs correspond to an honest
     136             :  * commitment for the given session.
     137             :  * Checks that the transfer private keys match their commitments.
     138             :  * Then derives the shared secret for each #TALER_CNC_KAPPA, and check that they match.
     139             :  *
     140             :  * @param connection the MHD connection to handle
     141             :  * @param session database connection to use
     142             :  * @param session_hash hash of session to query
     143             :  * @param off commitment offset to check
     144             :  * @param transfer_priv private transfer key
     145             :  * @param melt information about the melted coin
     146             :  * @param num_newcoins number of newcoins being generated
     147             :  * @param denom_pubs array of @a num_newcoins keys for the new coins
     148             :  * @param hash_context hash context to update by hashing in the data
     149             :  *                     from this offset
     150             :  * @return #GNUNET_OK if the committment was honest,
     151             :  *         #GNUNET_NO if there was a problem and we generated an error message
     152             :  *         #GNUNET_SYSERR if we could not even generate an error message
     153             :  */
     154             : static int
     155           4 : check_commitment (struct MHD_Connection *connection,
     156             :                   struct TALER_EXCHANGEDB_Session *session,
     157             :                   const struct GNUNET_HashCode *session_hash,
     158             :                   unsigned int off,
     159             :                   const struct TALER_TransferPrivateKeyP *transfer_priv,
     160             :                   const struct TALER_EXCHANGEDB_RefreshMelt *melt,
     161             :                   unsigned int num_newcoins,
     162             :                   const struct TALER_DenominationPublicKey *denom_pubs,
     163             :                   struct GNUNET_HashContext *hash_context)
     164             : {
     165             :   struct TALER_TransferSecretP transfer_secret;
     166             : 
     167           4 :   TALER_link_reveal_transfer_secret (transfer_priv,
     168             :                                      &melt->coin.coin_pub,
     169             :                                      &transfer_secret);
     170             : 
     171             :   /* Check that the commitments for all new coins were correct */
     172          72 :   for (unsigned int j = 0; j < num_newcoins; j++)
     173             :   {
     174             :     struct TALER_PlanchetSecretsP fc;
     175             :     struct TALER_CoinSpendPublicKeyP coin_pub;
     176             :     struct GNUNET_HashCode h_msg;
     177             :     char *buf;
     178             :     size_t buf_len;
     179             : 
     180          68 :     TALER_planchet_setup_refresh (&transfer_secret,
     181             :                             j,
     182             :                             &fc);
     183          68 :     GNUNET_CRYPTO_eddsa_key_get_public (&fc.coin_priv.eddsa_priv,
     184             :                                         &coin_pub.eddsa_pub);
     185          68 :     GNUNET_CRYPTO_hash (&coin_pub,
     186             :                         sizeof (struct TALER_CoinSpendPublicKeyP),
     187             :                         &h_msg);
     188          68 :     if (GNUNET_YES !=
     189          68 :         GNUNET_CRYPTO_rsa_blind (&h_msg,
     190             :                                  &fc.blinding_key.bks,
     191          68 :                                  denom_pubs[j].rsa_public_key,
     192             :                                  &buf,
     193             :                                  &buf_len))
     194             :     {
     195           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     196             :                   "Blind failed (bad denomination key!?)\n");
     197             :       return (MHD_YES ==
     198           0 :               TEH_RESPONSE_reply_internal_error (connection,
     199             :                                                  TALER_EC_REFRESH_REVEAL_BLINDING_ERROR,
     200             :                                                  "Blinding error"))
     201           0 :         ? GNUNET_NO : GNUNET_SYSERR;
     202             :     }
     203          68 :     GNUNET_CRYPTO_hash_context_read (hash_context,
     204             :                                      buf,
     205             :                                      buf_len);
     206          68 :     GNUNET_free (buf);
     207             :   }
     208           4 :   return GNUNET_OK;
     209             : }
     210             : 
     211             : 
     212             : /**
     213             :  * State for a /refresh/reveal operation.
     214             :  */
     215             : struct RevealContext
     216             : {
     217             : 
     218             :   /**
     219             :    * Hash of the refresh session.
     220             :    */
     221             :   const struct GNUNET_HashCode *session_hash;
     222             : 
     223             :   /**
     224             :    * Database session used to execute the transaction.
     225             :    */
     226             :   struct TALER_EXCHANGEDB_Session *session;
     227             : 
     228             :   /**
     229             :    * Session state from the database.
     230             :    */
     231             :   struct TALER_EXCHANGEDB_RefreshSession refresh_session;
     232             : 
     233             :   /**
     234             :    * Array of denomination public keys used for the refresh.
     235             :    */
     236             :   struct TALER_DenominationPublicKey *denom_pubs;
     237             : 
     238             :   /**
     239             :    * Envelopes with the signatures to be returned.
     240             :    */
     241             :   struct TALER_DenominationSignature *ev_sigs;
     242             : 
     243             :   /**
     244             :    * Commitment data from the DB giving data about original
     245             :    * commitments, in particular the blinded envelopes (for
     246             :    * index gamma).
     247             :    */
     248             :   struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins;
     249             : 
     250             :   /**
     251             :    * Transfer public key associated with the gamma value
     252             :    * selected by the exchange.
     253             :    */
     254             :   struct TALER_TransferPublicKeyP gamma_tp;
     255             : 
     256             :   /**
     257             :    * Transfer private keys revealed to us.
     258             :    */
     259             :   struct TALER_TransferPrivateKeyP transfer_privs[TALER_CNC_KAPPA - 1];
     260             : 
     261             : };
     262             : 
     263             : 
     264             : /**
     265             :  * Exchange a coin as part of a refresh operation.  Obtains the
     266             :  * envelope from the database and performs the signing operation.
     267             :  *
     268             :  * @param connection the MHD connection to handle
     269             :  * @param session database connection to use
     270             :  * @param session_hash hash of session to query
     271             :  * @param key_state key state to lookup denomination pubs
     272             :  * @param denom_pub denomination key for the coin to create
     273             :  * @param commit_coin the coin that was committed
     274             :  * @param coin_off number of the coin
     275             :  * @param[out] ev_sig set to signature over the coin upon success
     276             :  * @return database transaction status
     277             :  */
     278             : static enum GNUNET_DB_QueryStatus
     279          34 : refresh_exchange_coin (struct MHD_Connection *connection,
     280             :                        struct TALER_EXCHANGEDB_Session *session,
     281             :                        const struct GNUNET_HashCode *session_hash,
     282             :                        struct TEH_KS_StateHandle *key_state,
     283             :                        const struct TALER_DenominationPublicKey *denom_pub,
     284             :                        const struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin,
     285             :                        unsigned int coin_off,
     286             :                        struct TALER_DenominationSignature *ev_sig)
     287             : {
     288             :   struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
     289             :   enum GNUNET_DB_QueryStatus qs;
     290             : 
     291          34 :   dki = TEH_KS_denomination_key_lookup (key_state,
     292             :                                         denom_pub,
     293             :                                         TEH_KS_DKU_WITHDRAW);
     294          34 :   if (NULL == dki)
     295             :   {
     296           0 :     GNUNET_break (0);
     297           0 :     ev_sig->rsa_signature = NULL;
     298           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
     299             :   }
     300          34 :   qs = TEH_plugin->get_refresh_out (TEH_plugin->cls,
     301             :                                     session,
     302             :                                     session_hash,
     303             :                                     coin_off,
     304             :                                     ev_sig);
     305          34 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
     306             :   {
     307          17 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     308             :                 "Returning cached reply for /refresh/reveal signature\n");
     309          17 :     return qs;
     310             :   }
     311          17 :   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs)
     312           0 :     return qs;
     313             : 
     314             :   ev_sig->rsa_signature
     315          34 :     = GNUNET_CRYPTO_rsa_sign_blinded (dki->denom_priv.rsa_private_key,
     316          17 :                                       commit_coin->coin_ev,
     317             :                                       commit_coin->coin_ev_size);
     318          17 :   if (NULL == ev_sig->rsa_signature)
     319             :   {
     320           0 :     GNUNET_break (0);
     321           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
     322             :   }
     323          17 :   qs = TEH_plugin->insert_refresh_out (TEH_plugin->cls,
     324             :                                        session,
     325             :                                        session_hash,
     326             :                                        coin_off,
     327             :                                        ev_sig);
     328          17 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
     329             :   {
     330           0 :     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
     331           0 :     if (NULL != ev_sig->rsa_signature)
     332             :     {
     333           0 :       GNUNET_CRYPTO_rsa_signature_free (ev_sig->rsa_signature);
     334           0 :       ev_sig->rsa_signature = NULL;
     335             :     }
     336             :   }
     337          17 :   return qs;
     338             : }
     339             : 
     340             : 
     341             : /**
     342             :  * Cleanup state of the transaction stored in @a rc.
     343             :  *
     344             :  * @param rc context to clean up
     345             :  */
     346             : static void
     347           2 : cleanup_rc (struct RevealContext *rc)
     348             : {
     349           2 :   if (NULL != rc->denom_pubs)
     350             :   {
     351          36 :     for (unsigned int i=0;i<rc->refresh_session.num_newcoins;i++)
     352          34 :       if (NULL != rc->denom_pubs[i].rsa_public_key)
     353          34 :         GNUNET_CRYPTO_rsa_public_key_free (rc->denom_pubs[i].rsa_public_key);
     354           2 :     GNUNET_free (rc->denom_pubs);
     355           2 :     rc->denom_pubs = NULL;
     356             :   }
     357           2 :   if (NULL != rc->commit_coins)
     358             :   {
     359          36 :     for (unsigned int j=0;j<rc->refresh_session.num_newcoins;j++)
     360          34 :       GNUNET_free_non_null (rc->commit_coins[j].coin_ev);
     361           2 :     GNUNET_free (rc->commit_coins);
     362           2 :     rc->commit_coins = NULL;
     363             :   }
     364           2 :   if (NULL != rc->ev_sigs)
     365             :   {
     366          36 :     for (unsigned int j=0;j<rc->refresh_session.num_newcoins;j++)
     367          34 :       if (NULL != rc->ev_sigs[j].rsa_signature)
     368          34 :         GNUNET_CRYPTO_rsa_signature_free (rc->ev_sigs[j].rsa_signature);
     369           2 :     GNUNET_free (rc->ev_sigs);
     370           2 :     rc->ev_sigs = NULL;
     371             :   }
     372           2 :   if (NULL != rc->refresh_session.melt.coin.denom_sig.rsa_signature)
     373             :   {
     374           2 :     GNUNET_CRYPTO_rsa_signature_free (rc->refresh_session.melt.coin.denom_sig.rsa_signature);
     375           2 :     rc->refresh_session.melt.coin.denom_sig.rsa_signature = NULL;
     376             :   }
     377           2 :   if (NULL != rc->refresh_session.melt.coin.denom_pub.rsa_public_key)
     378             :   {
     379           2 :     GNUNET_CRYPTO_rsa_public_key_free (rc->refresh_session.melt.coin.denom_pub.rsa_public_key);
     380           2 :     rc->refresh_session.melt.coin.denom_pub.rsa_public_key = NULL;
     381             :   }
     382           2 : }
     383             : 
     384             : 
     385             : /**
     386             :  * Execute a "/refresh/reveal".  The client is revealing to us the
     387             :  * transfer keys for @a #TALER_CNC_KAPPA-1 sets of coins.  Verify that the
     388             :  * revealed transfer keys would allow linkage to the blinded coins,
     389             :  * and if so, return the signed coins for corresponding to the set of
     390             :  * coins that was not chosen.
     391             :  *
     392             :  * IF it returns a non-error code, the transaction logic MUST
     393             :  * NOT queue a MHD response.  IF it returns an hard error, the
     394             :  * transaction logic MUST queue a MHD response and set @a mhd_ret.  IF
     395             :  * it returns the soft error code, the function MAY be called again to
     396             :  * retry and MUST not queue a MHD response.
     397             :  *
     398             :  * @param cls closure of type `struct RevealContext`
     399             :  * @param connection MHD request which triggered the transaction
     400             :  * @param session database session to use
     401             :  * @param[out] mhd_ret set to MHD response status for @a connection,
     402             :  *             if transaction failed (!)
     403             :  * @return transaction status
     404             :  */
     405             : static enum GNUNET_DB_QueryStatus
     406           2 : refresh_reveal_transaction (void *cls,
     407             :                             struct MHD_Connection *connection,
     408             :                             struct TALER_EXCHANGEDB_Session *session,
     409             :                             int *mhd_ret)
     410             : {
     411           2 :   struct RevealContext *rc = cls;
     412             :   unsigned int off;
     413             :   struct GNUNET_HashContext *hash_context;
     414             :   struct GNUNET_HashCode sh_check;
     415             :   enum GNUNET_DB_QueryStatus qs;
     416             : 
     417           2 :   rc->session = session;
     418           2 :   qs = TEH_plugin->get_refresh_session (TEH_plugin->cls,
     419             :                                         session,
     420             :                                         rc->session_hash,
     421             :                                         &rc->refresh_session);
     422           2 :   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
     423             :   {
     424           0 :     *mhd_ret = TEH_RESPONSE_reply_arg_invalid (connection,
     425             :                                                TALER_EC_REFRESH_REVEAL_SESSION_UNKNOWN,
     426             :                                                "session_hash");
     427           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
     428             :   }
     429           2 :   if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
     430           0 :     return qs;
     431           4 :   if ( (GNUNET_DB_STATUS_HARD_ERROR == qs) ||
     432           2 :        (rc->refresh_session.noreveal_index >= TALER_CNC_KAPPA) )
     433             :   {
     434           0 :     GNUNET_break (0);
     435           0 :     cleanup_rc (rc);
     436           0 :     *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
     437             :                                                      TALER_EC_REFRESH_REVEAL_DB_FETCH_SESSION_ERROR);
     438           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
     439             :   }
     440           2 :   rc->denom_pubs = GNUNET_new_array (rc->refresh_session.num_newcoins,
     441             :                                      struct TALER_DenominationPublicKey);
     442           4 :   qs = TEH_plugin->get_refresh_order (TEH_plugin->cls,
     443             :                                       session,
     444             :                                       rc->session_hash,
     445           2 :                                       rc->refresh_session.num_newcoins,
     446             :                                       rc->denom_pubs);
     447           2 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
     448             :   {
     449           0 :     cleanup_rc (rc);
     450           0 :     if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
     451           0 :       return qs;
     452           0 :     GNUNET_break (0);
     453           0 :     *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
     454             :                                                      TALER_EC_REFRESH_REVEAL_DB_FETCH_ORDER_ERROR);
     455           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
     456             :   }
     457             : 
     458           2 :   hash_context = GNUNET_CRYPTO_hash_context_start ();
     459             :   /* first, iterate over transfer public keys for hash_context */
     460           2 :   off = 0;
     461           8 :   for (unsigned int i=0;i<TALER_CNC_KAPPA;i++)
     462             :   {
     463           6 :     if (i == rc->refresh_session.noreveal_index)
     464             :     {
     465           2 :       off = 1;
     466             :       /* obtain gamma_tp from db */
     467           2 :       qs = TEH_plugin->get_refresh_transfer_public_key (TEH_plugin->cls,
     468             :                                                         session,
     469             :                                                         rc->session_hash,
     470             :                                                         &rc->gamma_tp);
     471           2 :       if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
     472             :       {
     473           0 :         GNUNET_CRYPTO_hash_context_abort (hash_context);
     474           0 :         cleanup_rc (rc);
     475           0 :         if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
     476           0 :           return qs;
     477           0 :         GNUNET_break (0);
     478           0 :         *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
     479             :                                                          TALER_EC_REFRESH_REVEAL_DB_FETCH_TRANSFER_ERROR);
     480           0 :         return GNUNET_DB_STATUS_HARD_ERROR;
     481             :       }
     482           2 :       GNUNET_CRYPTO_hash_context_read (hash_context,
     483           2 :                                        &rc->gamma_tp,
     484             :                                        sizeof (struct TALER_TransferPublicKeyP));
     485             :     }
     486             :     else
     487             :     {
     488             :       /* compute tp from private key */
     489             :       struct TALER_TransferPublicKeyP tp;
     490             : 
     491           4 :       GNUNET_CRYPTO_ecdhe_key_get_public (&rc->transfer_privs[i - off].ecdhe_priv,
     492             :                                           &tp.ecdhe_pub);
     493           4 :       GNUNET_CRYPTO_hash_context_read (hash_context,
     494             :                                        &tp,
     495             :                                        sizeof (struct TALER_TransferPublicKeyP));
     496             :     }
     497             :   }
     498             : 
     499             :   /* next, add all of the hashes from the denomination keys to the
     500             :      hash_context */
     501          36 :   for (unsigned int i=0;i<rc->refresh_session.num_newcoins;i++)
     502             :   {
     503             :     char *buf;
     504             :     size_t buf_size;
     505             : 
     506          34 :     buf_size = GNUNET_CRYPTO_rsa_public_key_encode (rc->denom_pubs[i].rsa_public_key,
     507             :                                                     &buf);
     508          34 :     GNUNET_CRYPTO_hash_context_read (hash_context,
     509             :                                      buf,
     510             :                                      buf_size);
     511          34 :     GNUNET_free (buf);
     512             :   }
     513             : 
     514             :   /* next, add public key of coin and amount being refreshed */
     515             :   {
     516             :     struct TALER_AmountNBO melt_amountn;
     517             : 
     518           2 :     GNUNET_CRYPTO_hash_context_read (hash_context,
     519           2 :                                      &rc->refresh_session.melt.coin.coin_pub,
     520             :                                      sizeof (struct TALER_CoinSpendPublicKeyP));
     521           2 :     TALER_amount_hton (&melt_amountn,
     522           2 :                        &rc->refresh_session.melt.amount_with_fee);
     523           2 :     GNUNET_CRYPTO_hash_context_read (hash_context,
     524             :                                      &melt_amountn,
     525             :                                      sizeof (struct TALER_AmountNBO));
     526             :   }
     527             : 
     528           2 :   rc->commit_coins = GNUNET_new_array (rc->refresh_session.num_newcoins,
     529             :                                        struct TALER_EXCHANGEDB_RefreshCommitCoin);
     530           2 :   off = 0;
     531           8 :   for (unsigned int i=0;i<TALER_CNC_KAPPA;i++)
     532             :   {
     533             :     int res;
     534             : 
     535           6 :     if (i == rc->refresh_session.noreveal_index)
     536             :     {
     537           2 :       off = 1;
     538             :       /* obtain commit_coins for the selected gamma value from DB */
     539           4 :       qs = TEH_plugin->get_refresh_commit_coins (TEH_plugin->cls,
     540             :                                                  session,
     541             :                                                  rc->session_hash,
     542           2 :                                                  rc->refresh_session.num_newcoins,
     543             :                                                  rc->commit_coins);
     544           2 :       if (0 >= qs)
     545             :       {
     546           0 :         cleanup_rc (rc);
     547           0 :         GNUNET_CRYPTO_hash_context_abort (hash_context);
     548           0 :         if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
     549           0 :           return qs;
     550           0 :         GNUNET_break (0);
     551           0 :         *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
     552             :                                                          TALER_EC_REFRESH_REVEAL_DB_FETCH_COMMIT_ERROR);
     553           0 :         return GNUNET_DB_STATUS_HARD_ERROR;
     554             :       }
     555             :       /* add envelopes to hash_context */
     556          36 :       for (unsigned int j=0;j<rc->refresh_session.num_newcoins;j++)
     557             :       {
     558          68 :         GNUNET_CRYPTO_hash_context_read (hash_context,
     559          34 :                                          rc->commit_coins[j].coin_ev,
     560          34 :                                          rc->commit_coins[j].coin_ev_size);
     561             :       }
     562           2 :       continue;
     563             :     }
     564           4 :     if (GNUNET_OK !=
     565           8 :         (res = check_commitment (connection,
     566             :                                  session,
     567             :                                  rc->session_hash,
     568             :                                  i,
     569           4 :                                  &rc->transfer_privs[i - off],
     570           4 :                                  &rc->refresh_session.melt,
     571           4 :                                  rc->refresh_session.num_newcoins,
     572           4 :                                  rc->denom_pubs,
     573             :                                  hash_context)))
     574             :     {
     575           0 :       GNUNET_break_op (0);
     576           0 :       cleanup_rc (rc);
     577           0 :       GNUNET_CRYPTO_hash_context_abort (hash_context);
     578           0 :       *mhd_ret = (GNUNET_NO == res) ? MHD_YES : MHD_NO;
     579           0 :       return GNUNET_DB_STATUS_HARD_ERROR;
     580             :     }
     581             :   }
     582             : 
     583             :   /* Check session hash matches */
     584           2 :   GNUNET_CRYPTO_hash_context_finish (hash_context,
     585             :                                      &sh_check);
     586           2 :   if (0 != memcmp (&sh_check,
     587           2 :                    rc->session_hash,
     588             :                    sizeof (struct GNUNET_HashCode)))
     589             :   {
     590           0 :     GNUNET_break_op (0);
     591           0 :     *mhd_ret = reply_refresh_reveal_missmatch (connection,
     592           0 :                                                &rc->refresh_session,
     593           0 :                                                rc->commit_coins,
     594           0 :                                                rc->denom_pubs,
     595           0 :                                                &rc->gamma_tp);
     596           0 :     cleanup_rc (rc);
     597           0 :     return GNUNET_DB_STATUS_HARD_ERROR;
     598             :   }
     599             : 
     600             :   /* Client request OK, sign coins */
     601           2 :   rc->ev_sigs = GNUNET_new_array (rc->refresh_session.num_newcoins,
     602             :                                   struct TALER_DenominationSignature);
     603             :   {
     604             :     struct TEH_KS_StateHandle *key_state;
     605             : 
     606           2 :     key_state = TEH_KS_acquire ();
     607           2 :     if (NULL == key_state)
     608             :     {
     609           0 :       TALER_LOG_ERROR ("Lacking keys to operate\n");
     610           0 :       cleanup_rc (rc);
     611           0 :       return GNUNET_DB_STATUS_HARD_ERROR;
     612             :     }
     613          36 :     for (unsigned int j=0;j<rc->refresh_session.num_newcoins;j++)
     614             :     {
     615          68 :       qs = refresh_exchange_coin (connection,
     616             :                                   session,
     617             :                                   rc->session_hash,
     618             :                                   key_state,
     619          34 :                                   &rc->denom_pubs[j],
     620          34 :                                   &rc->commit_coins[j],
     621             :                                   j,
     622          34 :                                   &rc->ev_sigs[j]);
     623          68 :       if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) ||
     624          34 :            (NULL == rc->ev_sigs[j].rsa_signature) )
     625             :       {
     626           0 :         *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
     627             :                                                          TALER_EC_REFRESH_REVEAL_SIGNING_ERROR);
     628           0 :         qs = GNUNET_DB_STATUS_HARD_ERROR;
     629           0 :         break;
     630             :       }
     631             :     }
     632           2 :     TEH_KS_release (key_state);
     633             :   }
     634           2 :   if (0 >= qs)
     635             :   {
     636           0 :     cleanup_rc (rc);
     637           0 :     return qs;
     638             :   }
     639           2 :   return qs;
     640             : }
     641             : 
     642             : 
     643             : /**
     644             :  * Handle a "/refresh/reveal" request.   Parses the given JSON
     645             :  * transfer private keys and if successful, passes everything to
     646             :  * #TEH_DB_execute_refresh_reveal() which will verify that the
     647             :  * revealed information is valid then returns the signed refreshed
     648             :  * coins.
     649             :  *
     650             :  * @param connection the MHD connection to handle
     651             :  * @param session_hash hash identifying the melting session
     652             :  * @param tp_json private transfer keys in JSON format
     653             :  * @return MHD result code
     654             :   */
     655             : static int
     656           2 : handle_refresh_reveal_json (struct MHD_Connection *connection,
     657             :                             const struct GNUNET_HashCode *session_hash,
     658             :                             const json_t *tp_json)
     659             : {
     660             :   struct RevealContext rc;
     661             :   int mhd_ret;
     662             : 
     663           2 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     664             :               "reveal request for session %s\n",
     665             :               GNUNET_h2s (session_hash));
     666           2 :   memset (&rc,
     667             :           0,
     668             :           sizeof (rc));
     669           2 :   rc.session_hash = session_hash;
     670           6 :   for (unsigned int i = 0; i < TALER_CNC_KAPPA - 1; i++)
     671             :   {
     672           4 :     struct GNUNET_JSON_Specification tp_spec[] = {
     673           4 :       GNUNET_JSON_spec_fixed_auto (NULL, &rc.transfer_privs[i]),
     674             :       GNUNET_JSON_spec_end ()
     675             :     };
     676             :     int res;
     677             : 
     678           4 :     res = TEH_PARSE_json_array (connection,
     679             :                                 tp_json,
     680             :                                 tp_spec,
     681             :                                 i,
     682             :                                 -1);
     683           4 :     GNUNET_break_op (GNUNET_OK == res);
     684           4 :     if (GNUNET_OK != res)
     685           0 :       return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
     686             :   }
     687           2 :   if (GNUNET_OK !=
     688           2 :       TEH_DB_run_transaction (connection,
     689             :                               &mhd_ret,
     690             :                               &refresh_reveal_transaction,
     691             :                               &rc))
     692             :   {
     693           0 :     cleanup_rc (&rc);
     694           0 :     return mhd_ret;
     695             :   }
     696           2 :   mhd_ret = reply_refresh_reveal_success (connection,
     697           2 :                                           rc.refresh_session.num_newcoins,
     698           2 :                                           rc.ev_sigs);
     699           2 :   cleanup_rc (&rc);
     700           2 :   return mhd_ret;
     701             : }
     702             : 
     703             : 
     704             : /**
     705             :  * Handle a "/refresh/reveal" request. This time, the client reveals
     706             :  * the private transfer keys except for the cut-and-choose value
     707             :  * returned from "/refresh/melt".  This function parses the revealed
     708             :  * keys and secrets and ultimately passes everything to
     709             :  * #TEH_DB_execute_refresh_reveal() which will verify that the
     710             :  * revealed information is valid then returns the signed refreshed
     711             :  * coins.
     712             :  *
     713             :  * @param rh context of the handler
     714             :  * @param connection the MHD connection to handle
     715             :  * @param[in,out] connection_cls the connection's closure (can be updated)
     716             :  * @param upload_data upload data
     717             :  * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
     718             :  * @return MHD result code
     719             :   */
     720             : int
     721           6 : TEH_REFRESH_handler_refresh_reveal (struct TEH_RequestHandler *rh,
     722             :                                     struct MHD_Connection *connection,
     723             :                                     void **connection_cls,
     724             :                                     const char *upload_data,
     725             :                                     size_t *upload_data_size)
     726             : {
     727             :   struct GNUNET_HashCode session_hash;
     728             :   int res;
     729             :   json_t *root;
     730             :   json_t *transfer_privs;
     731           6 :   struct GNUNET_JSON_Specification spec[] = {
     732             :     GNUNET_JSON_spec_fixed_auto ("session_hash", &session_hash),
     733             :     GNUNET_JSON_spec_json ("transfer_privs", &transfer_privs),
     734             :     GNUNET_JSON_spec_end ()
     735             :   };
     736             : 
     737           6 :   res = TEH_PARSE_post_json (connection,
     738             :                              connection_cls,
     739             :                              upload_data,
     740             :                              upload_data_size,
     741             :                              &root);
     742           6 :   if (GNUNET_SYSERR == res)
     743           0 :     return MHD_NO;
     744          12 :   if ( (GNUNET_NO == res) ||
     745           6 :        (NULL == root) )
     746           4 :     return MHD_YES;
     747             : 
     748           2 :   res = TEH_PARSE_json_data (connection,
     749             :                              root,
     750             :                              spec);
     751           2 :   json_decref (root);
     752           2 :   if (GNUNET_OK != res)
     753             :   {
     754           0 :     GNUNET_break_op (0);
     755           0 :     return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
     756             :   }
     757             :   /* Determine dimensionality of the request (kappa and #old coins) */
     758             :   /* Note we do +1 as 1 row (cut-and-choose!) is missing! */
     759           2 :   if (TALER_CNC_KAPPA != json_array_size (transfer_privs) + 1)
     760             :   {
     761           0 :     GNUNET_JSON_parse_free (spec);
     762           0 :     GNUNET_break_op (0);
     763           0 :     return TEH_RESPONSE_reply_arg_invalid (connection,
     764             :                                            TALER_EC_REFRESH_REVEAL_CNC_TRANSFER_ARRAY_SIZE_INVALID,
     765             :                                            "transfer_privs");
     766             :   }
     767           2 :   res = handle_refresh_reveal_json (connection,
     768             :                                     &session_hash,
     769             :                                     transfer_privs);
     770           2 :   GNUNET_JSON_parse_free (spec);
     771           2 :   return res;
     772             : }
     773             : 
     774             : 
     775             : /* end of taler-exchange-httpd_refresh_reveal.c */

Generated by: LCOV version 1.13