LCOV - code coverage report
Current view: top level - lib - exchange_api_batch_withdraw.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 0 154 0.0 %
Date: 2022-08-25 06:15:09 Functions: 0 5 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014-2022 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU General Public License as published by the Free Software
       7             :   Foundation; either version 3, or (at your option) any later version.
       8             : 
       9             :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10             :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11             :   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU General Public License along with
      14             :   TALER; see the file COPYING.  If not, see
      15             :   <http://www.gnu.org/licenses/>
      16             : */
      17             : /**
      18             :  * @file lib/exchange_api_batch_withdraw.c
      19             :  * @brief Implementation of /reserves/$RESERVE_PUB/batch-withdraw requests with blinding/unblinding
      20             :  * @author Christian Grothoff
      21             :  */
      22             : #include "platform.h"
      23             : #include <jansson.h>
      24             : #include <microhttpd.h> /* just for HTTP status codes */
      25             : #include <gnunet/gnunet_util_lib.h>
      26             : #include <gnunet/gnunet_json_lib.h>
      27             : #include <gnunet/gnunet_curl_lib.h>
      28             : #include "taler_exchange_service.h"
      29             : #include "taler_json_lib.h"
      30             : #include "exchange_api_handle.h"
      31             : #include "taler_signatures.h"
      32             : #include "exchange_api_curl_defaults.h"
      33             : 
      34             : 
      35             : /**
      36             :  * Data we keep per coin in the batch.
      37             :  */
      38             : struct CoinData
      39             : {
      40             : 
      41             :   /**
      42             :    * Denomination key we are withdrawing.
      43             :    */
      44             :   struct TALER_EXCHANGE_DenomPublicKey pk;
      45             : 
      46             :   /**
      47             :    * Master key material for the coin.
      48             :    */
      49             :   struct TALER_PlanchetMasterSecretP ps;
      50             : 
      51             :   /**
      52             :    * Age commitment for the coin.
      53             :    */
      54             :   const struct TALER_AgeCommitmentHash *ach;
      55             : 
      56             :   /**
      57             :    *  blinding secret
      58             :    */
      59             :   union TALER_DenominationBlindingKeyP bks;
      60             : 
      61             :   /**
      62             :    * Private key of the coin we are withdrawing.
      63             :    */
      64             :   struct TALER_CoinSpendPrivateKeyP priv;
      65             : 
      66             :   /**
      67             :    * Details of the planchet.
      68             :    */
      69             :   struct TALER_PlanchetDetail pd;
      70             : 
      71             :   /**
      72             :    * Values of the @cipher selected
      73             :    */
      74             :   struct TALER_ExchangeWithdrawValues alg_values;
      75             : 
      76             :   /**
      77             :    * Hash of the public key of the coin we are signing.
      78             :    */
      79             :   struct TALER_CoinPubHashP c_hash;
      80             : 
      81             :   /**
      82             :    * Handler for the CS R request (only used for TALER_DENOMINATION_CS denominations)
      83             :    */
      84             :   struct TALER_EXCHANGE_CsRWithdrawHandle *csrh;
      85             : 
      86             :   /**
      87             :    * Batch withdraw this coin is part of.
      88             :    */
      89             :   struct TALER_EXCHANGE_BatchWithdrawHandle *wh;
      90             : };
      91             : 
      92             : 
      93             : /**
      94             :  * @brief A batch withdraw handle
      95             :  */
      96             : struct TALER_EXCHANGE_BatchWithdrawHandle
      97             : {
      98             : 
      99             :   /**
     100             :    * The connection to exchange this request handle will use
     101             :    */
     102             :   struct TALER_EXCHANGE_Handle *exchange;
     103             : 
     104             :   /**
     105             :    * Handle for the actual (internal) batch withdraw operation.
     106             :    */
     107             :   struct TALER_EXCHANGE_BatchWithdraw2Handle *wh2;
     108             : 
     109             :   /**
     110             :    * Function to call with the result.
     111             :    */
     112             :   TALER_EXCHANGE_BatchWithdrawCallback cb;
     113             : 
     114             :   /**
     115             :    * Closure for @a cb.
     116             :    */
     117             :   void *cb_cls;
     118             : 
     119             :   /**
     120             :    * Reserve private key.
     121             :    */
     122             :   const struct TALER_ReservePrivateKeyP *reserve_priv;
     123             : 
     124             :   /**
     125             :    * Array of per-coin data.
     126             :    */
     127             :   struct CoinData *coins;
     128             : 
     129             :   /**
     130             :    * Length of the @e coins array.
     131             :    */
     132             :   unsigned int num_coins;
     133             : 
     134             :   /**
     135             :    * Number of CS requests still pending.
     136             :    */
     137             :   unsigned int cs_pending;
     138             : 
     139             : };
     140             : 
     141             : 
     142             : /**
     143             :  * Function called when we're done processing the
     144             :  * HTTP /reserves/$RESERVE_PUB/batch-withdraw request.
     145             :  *
     146             :  * @param cls the `struct TALER_EXCHANGE_BatchWithdrawHandle`
     147             :  * @param hr HTTP response data
     148             :  * @param blind_sigs array of blind signatures over the coins, NULL on error
     149             :  * @param blind_sigs_length length of the @a blind_sigs array
     150             :  */
     151             : static void
     152           0 : handle_reserve_batch_withdraw_finished (
     153             :   void *cls,
     154             :   const struct TALER_EXCHANGE_HttpResponse *hr,
     155             :   const struct TALER_BlindedDenominationSignature *blind_sigs,
     156             :   unsigned int blind_sigs_length)
     157           0 : {
     158           0 :   struct TALER_EXCHANGE_BatchWithdrawHandle *wh = cls;
     159           0 :   struct TALER_EXCHANGE_BatchWithdrawResponse wr = {
     160             :     .hr = *hr
     161             :   };
     162           0 :   struct TALER_EXCHANGE_PrivateCoinDetails coins[wh->num_coins];
     163             : 
     164           0 :   wh->wh2 = NULL;
     165           0 :   memset (coins,
     166             :           0,
     167             :           sizeof (coins));
     168           0 :   if (blind_sigs_length != wh->num_coins)
     169             :   {
     170           0 :     GNUNET_break_op (0);
     171           0 :     wr.hr.http_status = 0;
     172           0 :     wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     173             :   }
     174           0 :   switch (hr->http_status)
     175             :   {
     176           0 :   case MHD_HTTP_OK:
     177             :     {
     178           0 :       for (unsigned int i = 0; i<wh->num_coins; i++)
     179             :       {
     180           0 :         struct CoinData *cd = &wh->coins[i];
     181           0 :         struct TALER_EXCHANGE_PrivateCoinDetails *coin = &coins[i];
     182             :         struct TALER_FreshCoin fc;
     183             : 
     184           0 :         if (GNUNET_OK !=
     185           0 :             TALER_planchet_to_coin (&cd->pk.key,
     186           0 :                                     &blind_sigs[i],
     187           0 :                                     &cd->bks,
     188           0 :                                     &cd->priv,
     189             :                                     cd->ach,
     190           0 :                                     &cd->c_hash,
     191           0 :                                     &cd->alg_values,
     192             :                                     &fc))
     193             :         {
     194           0 :           wr.hr.http_status = 0;
     195           0 :           wr.hr.ec = TALER_EC_EXCHANGE_WITHDRAW_UNBLIND_FAILURE;
     196           0 :           break;
     197             :         }
     198           0 :         coin->coin_priv = cd->priv;
     199           0 :         coin->bks = cd->bks;
     200           0 :         coin->sig = fc.sig;
     201           0 :         coin->exchange_vals = cd->alg_values;
     202             :       }
     203           0 :       wr.details.success.coins = coins;
     204           0 :       wr.details.success.num_coins = wh->num_coins;
     205           0 :       break;
     206             :     }
     207           0 :   case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
     208             :     {
     209             :       struct GNUNET_JSON_Specification spec[] = {
     210           0 :         GNUNET_JSON_spec_fixed_auto (
     211             :           "h_payto",
     212             :           &wr.details.unavailable_for_legal_reasons.h_payto),
     213           0 :         GNUNET_JSON_spec_uint64 (
     214             :           "requirement_row",
     215             :           &wr.details.unavailable_for_legal_reasons.requirement_row),
     216           0 :         GNUNET_JSON_spec_end ()
     217             :       };
     218             : 
     219           0 :       if (GNUNET_OK !=
     220           0 :           GNUNET_JSON_parse (hr->reply,
     221             :                              spec,
     222             :                              NULL, NULL))
     223             :       {
     224           0 :         GNUNET_break_op (0);
     225           0 :         wr.hr.http_status = 0;
     226           0 :         wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     227           0 :         break;
     228             :       }
     229             :     }
     230           0 :     break;
     231           0 :   default:
     232           0 :     break;
     233             :   }
     234           0 :   wh->cb (wh->cb_cls,
     235             :           &wr);
     236           0 :   for (unsigned int i = 0; i<wh->num_coins; i++)
     237           0 :     TALER_denom_sig_free (&coins[i].sig);
     238           0 :   TALER_EXCHANGE_batch_withdraw_cancel (wh);
     239           0 : }
     240             : 
     241             : 
     242             : /**
     243             :  * Runs phase two, the actual withdraw operation.
     244             :  * Started once the preparation for CS-denominations is
     245             :  * done.
     246             :  *
     247             :  * @param[in,out] wh batch withdraw to start phase 2 for
     248             :  */
     249             : static void
     250           0 : phase_two (struct TALER_EXCHANGE_BatchWithdrawHandle *wh)
     251           0 : {
     252           0 :   struct TALER_PlanchetDetail pds[wh->num_coins];
     253             : 
     254           0 :   for (unsigned int i = 0; i<wh->num_coins; i++)
     255             :   {
     256           0 :     struct CoinData *cd = &wh->coins[i];
     257             : 
     258           0 :     pds[i] = cd->pd;
     259             :   }
     260           0 :   wh->wh2 = TALER_EXCHANGE_batch_withdraw2 (
     261             :     wh->exchange,
     262             :     wh->reserve_priv,
     263             :     pds,
     264             :     wh->num_coins,
     265             :     &handle_reserve_batch_withdraw_finished,
     266             :     wh);
     267           0 : }
     268             : 
     269             : 
     270             : /**
     271             :  * Function called when stage 1 of CS withdraw is finished (request r_pub's)
     272             :  *
     273             :  * @param cls the `struct CoinData *`
     274             :  * @param csrr replies from the /csr-withdraw request
     275             :  */
     276             : static void
     277           0 : withdraw_cs_stage_two_callback (
     278             :   void *cls,
     279             :   const struct TALER_EXCHANGE_CsRWithdrawResponse *csrr)
     280             : {
     281           0 :   struct CoinData *cd = cls;
     282           0 :   struct TALER_EXCHANGE_BatchWithdrawHandle *wh = cd->wh;
     283           0 :   struct TALER_EXCHANGE_BatchWithdrawResponse wr = {
     284             :     .hr = csrr->hr
     285             :   };
     286             : 
     287           0 :   cd->csrh = NULL;
     288           0 :   GNUNET_assert (TALER_DENOMINATION_CS == cd->pk.key.cipher);
     289           0 :   switch (csrr->hr.http_status)
     290             :   {
     291           0 :   case MHD_HTTP_OK:
     292           0 :     cd->alg_values = csrr->details.success.alg_values;
     293           0 :     TALER_planchet_setup_coin_priv (&cd->ps,
     294           0 :                                     &cd->alg_values,
     295             :                                     &cd->priv);
     296           0 :     TALER_planchet_blinding_secret_create (&cd->ps,
     297           0 :                                            &cd->alg_values,
     298             :                                            &cd->bks);
     299             :     /* This initializes the 2nd half of the
     300             :        wh->pd.blinded_planchet! */
     301           0 :     if (GNUNET_OK !=
     302           0 :         TALER_planchet_prepare (&cd->pk.key,
     303           0 :                                 &cd->alg_values,
     304           0 :                                 &cd->bks,
     305           0 :                                 &cd->priv,
     306             :                                 cd->ach,
     307             :                                 &cd->c_hash,
     308             :                                 &cd->pd))
     309             :     {
     310           0 :       GNUNET_break (0);
     311           0 :       TALER_EXCHANGE_batch_withdraw_cancel (wh);
     312             :     }
     313           0 :     wh->cs_pending--;
     314           0 :     if (0 == wh->cs_pending)
     315           0 :       phase_two (wh);
     316           0 :     return;
     317           0 :   default:
     318           0 :     break;
     319             :   }
     320           0 :   wh->cb (wh->cb_cls,
     321             :           &wr);
     322           0 :   TALER_EXCHANGE_batch_withdraw_cancel (wh);
     323             : }
     324             : 
     325             : 
     326             : struct TALER_EXCHANGE_BatchWithdrawHandle *
     327           0 : TALER_EXCHANGE_batch_withdraw (
     328             :   struct TALER_EXCHANGE_Handle *exchange,
     329             :   const struct TALER_ReservePrivateKeyP *reserve_priv,
     330             :   const struct TALER_EXCHANGE_WithdrawCoinInput *wcis,
     331             :   unsigned int wci_length,
     332             :   TALER_EXCHANGE_BatchWithdrawCallback res_cb,
     333             :   void *res_cb_cls)
     334             : {
     335             :   struct TALER_EXCHANGE_BatchWithdrawHandle *wh;
     336             : 
     337           0 :   wh = GNUNET_new (struct TALER_EXCHANGE_BatchWithdrawHandle);
     338           0 :   wh->exchange = exchange;
     339           0 :   wh->cb = res_cb;
     340           0 :   wh->cb_cls = res_cb_cls;
     341           0 :   wh->reserve_priv = reserve_priv;
     342           0 :   wh->num_coins = wci_length;
     343           0 :   wh->coins = GNUNET_new_array (wh->num_coins,
     344             :                                 struct CoinData);
     345           0 :   for (unsigned int i = 0; i<wci_length; i++)
     346             :   {
     347           0 :     struct CoinData *cd = &wh->coins[i];
     348           0 :     const struct TALER_EXCHANGE_WithdrawCoinInput *wci = &wcis[i];
     349             : 
     350           0 :     cd->wh = wh;
     351           0 :     cd->ps = *wci->ps;
     352           0 :     cd->ach = wci->ach;
     353           0 :     cd->pk = *wci->pk;
     354           0 :     TALER_denom_pub_deep_copy (&cd->pk.key,
     355           0 :                                &wci->pk->key);
     356           0 :     switch (wci->pk->key.cipher)
     357             :     {
     358           0 :     case TALER_DENOMINATION_RSA:
     359             :       {
     360           0 :         cd->alg_values.cipher = TALER_DENOMINATION_RSA;
     361           0 :         TALER_planchet_setup_coin_priv (&cd->ps,
     362           0 :                                         &cd->alg_values,
     363             :                                         &cd->priv);
     364           0 :         TALER_planchet_blinding_secret_create (&cd->ps,
     365           0 :                                                &cd->alg_values,
     366             :                                                &cd->bks);
     367           0 :         if (GNUNET_OK !=
     368           0 :             TALER_planchet_prepare (&cd->pk.key,
     369           0 :                                     &cd->alg_values,
     370           0 :                                     &cd->bks,
     371           0 :                                     &cd->priv,
     372             :                                     cd->ach,
     373             :                                     &cd->c_hash,
     374             :                                     &cd->pd))
     375             :         {
     376           0 :           GNUNET_break (0);
     377           0 :           TALER_EXCHANGE_batch_withdraw_cancel (wh);
     378           0 :           return NULL;
     379             :         }
     380           0 :         break;
     381             :       }
     382           0 :     case TALER_DENOMINATION_CS:
     383             :       {
     384           0 :         TALER_cs_withdraw_nonce_derive (
     385           0 :           &cd->ps,
     386             :           &cd->pd.blinded_planchet.details.cs_blinded_planchet.nonce);
     387             :         /* Note that we only initialize the first half
     388             :            of the blinded_planchet here; the other part
     389             :            will be done after the /csr-withdraw request! */
     390           0 :         cd->pd.blinded_planchet.cipher = TALER_DENOMINATION_CS;
     391           0 :         cd->csrh = TALER_EXCHANGE_csr_withdraw (
     392             :           exchange,
     393           0 :           &cd->pk,
     394           0 :           &cd->pd.blinded_planchet.details.cs_blinded_planchet.nonce,
     395             :           &withdraw_cs_stage_two_callback,
     396             :           cd);
     397           0 :         if (NULL == cd->csrh)
     398             :         {
     399           0 :           GNUNET_break (0);
     400           0 :           TALER_EXCHANGE_batch_withdraw_cancel (wh);
     401           0 :           return NULL;
     402             :         }
     403           0 :         wh->cs_pending++;
     404           0 :         break;
     405             :       }
     406           0 :     default:
     407           0 :       GNUNET_break (0);
     408           0 :       TALER_EXCHANGE_batch_withdraw_cancel (wh);
     409           0 :       return NULL;
     410             :     }
     411             :   }
     412           0 :   if (0 == wh->cs_pending)
     413           0 :     phase_two (wh);
     414           0 :   return wh;
     415             : }
     416             : 
     417             : 
     418             : void
     419           0 : TALER_EXCHANGE_batch_withdraw_cancel (
     420             :   struct TALER_EXCHANGE_BatchWithdrawHandle *wh)
     421             : {
     422           0 :   for (unsigned int i = 0; i<wh->num_coins; i++)
     423             :   {
     424           0 :     struct CoinData *cd = &wh->coins[i];
     425             : 
     426           0 :     if (NULL != cd->csrh)
     427             :     {
     428           0 :       TALER_EXCHANGE_csr_withdraw_cancel (cd->csrh);
     429           0 :       cd->csrh = NULL;
     430             :     }
     431           0 :     TALER_blinded_planchet_free (&cd->pd.blinded_planchet);
     432           0 :     TALER_denom_pub_free (&cd->pk.key);
     433             :   }
     434           0 :   GNUNET_free (wh->coins);
     435           0 :   if (NULL != wh->wh2)
     436             :   {
     437           0 :     TALER_EXCHANGE_batch_withdraw2_cancel (wh->wh2);
     438           0 :     wh->wh2 = NULL;
     439             :   }
     440           0 :   GNUNET_free (wh);
     441           0 : }

Generated by: LCOV version 1.14