LCOV - code coverage report
Current view: top level - lib - exchange_api_deposit.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 145 253 57.3 %
Date: 2021-08-30 06:43:37 Functions: 8 9 88.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014-2021 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_deposit.c
      19             :  * @brief Implementation of the /deposit request of the exchange's HTTP API
      20             :  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
      21             :  * @author Christian Grothoff
      22             :  */
      23             : #include "platform.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_auditor_service.h"
      31             : #include "taler_exchange_service.h"
      32             : #include "exchange_api_handle.h"
      33             : #include "taler_signatures.h"
      34             : #include "exchange_api_curl_defaults.h"
      35             : 
      36             : 
      37             : /**
      38             :  * 1:#AUDITOR_CHANCE is the probability that we report deposits
      39             :  * to the auditor.
      40             :  *
      41             :  * 20==5% of going to auditor. This is possibly still too high, but set
      42             :  * deliberately this high for testing
      43             :  */
      44             : #define AUDITOR_CHANCE 20
      45             : 
      46             : /**
      47             :  * @brief A Deposit Handle
      48             :  */
      49             : struct TALER_EXCHANGE_DepositHandle
      50             : {
      51             : 
      52             :   /**
      53             :    * The connection to exchange this request handle will use
      54             :    */
      55             :   struct TALER_EXCHANGE_Handle *exchange;
      56             : 
      57             :   /**
      58             :    * The url for this request.
      59             :    */
      60             :   char *url;
      61             : 
      62             :   /**
      63             :    * Context for #TEH_curl_easy_post(). Keeps the data that must
      64             :    * persist for Curl to make the upload.
      65             :    */
      66             :   struct TALER_CURL_PostContext ctx;
      67             : 
      68             :   /**
      69             :    * Handle for the request.
      70             :    */
      71             :   struct GNUNET_CURL_Job *job;
      72             : 
      73             :   /**
      74             :    * Function to call with the result.
      75             :    */
      76             :   TALER_EXCHANGE_DepositResultCallback cb;
      77             : 
      78             :   /**
      79             :    * Closure for @a cb.
      80             :    */
      81             :   void *cb_cls;
      82             : 
      83             :   /**
      84             :    * Information the exchange should sign in response.
      85             :    */
      86             :   struct TALER_DepositConfirmationPS depconf;
      87             : 
      88             :   /**
      89             :    * Exchange signature, set for #auditor_cb.
      90             :    */
      91             :   struct TALER_ExchangeSignatureP exchange_sig;
      92             : 
      93             :   /**
      94             :    * Exchange signing public key, set for #auditor_cb.
      95             :    */
      96             :   struct TALER_ExchangePublicKeyP exchange_pub;
      97             : 
      98             :   /**
      99             :    * Value of the /deposit transaction, including fee.
     100             :    */
     101             :   struct TALER_Amount amount_with_fee;
     102             : 
     103             :   /**
     104             :    * @brief Public information about the coin's denomination key.
     105             :    * Note that the "key" field itself has been zero'ed out.
     106             :    */
     107             :   struct TALER_EXCHANGE_DenomPublicKey dki;
     108             : 
     109             :   /**
     110             :    * Chance that we will inform the auditor about the deposit
     111             :    * is 1:n, where the value of this field is "n".
     112             :    */
     113             :   unsigned int auditor_chance;
     114             : 
     115             : };
     116             : 
     117             : 
     118             : /**
     119             :  * Function called for each auditor to give us a chance to possibly
     120             :  * launch a deposit confirmation interaction.
     121             :  *
     122             :  * @param cls closure
     123             :  * @param ah handle to the auditor
     124             :  * @param auditor_pub public key of the auditor
     125             :  * @return NULL if no deposit confirmation interaction was launched
     126             :  */
     127             : static struct TEAH_AuditorInteractionEntry *
     128          17 : auditor_cb (void *cls,
     129             :             struct TALER_AUDITOR_Handle *ah,
     130             :             const struct TALER_AuditorPublicKeyP *auditor_pub)
     131             : {
     132          17 :   struct TALER_EXCHANGE_DepositHandle *dh = cls;
     133             :   const struct TALER_EXCHANGE_Keys *key_state;
     134             :   const struct TALER_EXCHANGE_SigningPublicKey *spk;
     135             :   struct TALER_Amount amount_without_fee;
     136             :   struct TEAH_AuditorInteractionEntry *aie;
     137             : 
     138          17 :   if (0 != GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
     139             :                                      dh->auditor_chance))
     140             :   {
     141          17 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     142             :                 "Not providing deposit confirmation to auditor\n");
     143          17 :     return NULL;
     144             :   }
     145           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     146             :               "Will provide deposit confirmation to auditor `%s'\n",
     147             :               TALER_B2S (auditor_pub));
     148           0 :   key_state = TALER_EXCHANGE_get_keys (dh->exchange);
     149           0 :   spk = TALER_EXCHANGE_get_signing_key_info (key_state,
     150           0 :                                              &dh->exchange_pub);
     151           0 :   if (NULL == spk)
     152             :   {
     153           0 :     GNUNET_break_op (0);
     154           0 :     return NULL;
     155             :   }
     156           0 :   TALER_amount_ntoh (&amount_without_fee,
     157           0 :                      &dh->depconf.amount_without_fee);
     158           0 :   aie = GNUNET_new (struct TEAH_AuditorInteractionEntry);
     159           0 :   aie->dch = TALER_AUDITOR_deposit_confirmation (
     160             :     ah,
     161           0 :     &dh->depconf.h_wire,
     162           0 :     &dh->depconf.h_contract_terms,
     163             :     GNUNET_TIME_absolute_ntoh (dh->depconf.exchange_timestamp),
     164             :     GNUNET_TIME_absolute_ntoh (dh->depconf.refund_deadline),
     165             :     &amount_without_fee,
     166           0 :     &dh->depconf.coin_pub,
     167           0 :     &dh->depconf.merchant,
     168           0 :     &dh->exchange_pub,
     169           0 :     &dh->exchange_sig,
     170             :     &key_state->master_pub,
     171             :     spk->valid_from,
     172             :     spk->valid_until,
     173             :     spk->valid_legal,
     174             :     &spk->master_sig,
     175             :     &TEAH_acc_confirmation_cb,
     176             :     aie);
     177           0 :   return aie;
     178             : }
     179             : 
     180             : 
     181             : /**
     182             :  * Verify that the signature on the "200 OK" response
     183             :  * from the exchange is valid.
     184             :  *
     185             :  * @param dh deposit handle
     186             :  * @param json json reply with the signature
     187             :  * @param[out] exchange_sig set to the exchange's signature
     188             :  * @param[out] exchange_pub set to the exchange's public key
     189             :  * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
     190             :  */
     191             : static int
     192          33 : verify_deposit_signature_ok (struct TALER_EXCHANGE_DepositHandle *dh,
     193             :                              const json_t *json,
     194             :                              struct TALER_ExchangeSignatureP *exchange_sig,
     195             :                              struct TALER_ExchangePublicKeyP *exchange_pub)
     196             : {
     197             :   const struct TALER_EXCHANGE_Keys *key_state;
     198             :   struct GNUNET_JSON_Specification spec[] = {
     199          33 :     GNUNET_JSON_spec_fixed_auto ("exchange_sig", exchange_sig),
     200          33 :     GNUNET_JSON_spec_fixed_auto ("exchange_pub", exchange_pub),
     201          33 :     TALER_JSON_spec_absolute_time_nbo ("exchange_timestamp",
     202             :                                        &dh->depconf.exchange_timestamp),
     203          33 :     GNUNET_JSON_spec_end ()
     204             :   };
     205             : 
     206          33 :   if (GNUNET_OK !=
     207          33 :       GNUNET_JSON_parse (json,
     208             :                          spec,
     209             :                          NULL, NULL))
     210             :   {
     211           0 :     GNUNET_break_op (0);
     212           0 :     return GNUNET_SYSERR;
     213             :   }
     214          33 :   key_state = TALER_EXCHANGE_get_keys (dh->exchange);
     215          33 :   if (GNUNET_OK !=
     216          33 :       TALER_EXCHANGE_test_signing_key (key_state,
     217             :                                        exchange_pub))
     218             :   {
     219           0 :     GNUNET_break_op (0);
     220           0 :     return GNUNET_SYSERR;
     221             :   }
     222          33 :   if (GNUNET_OK !=
     223          33 :       GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT,
     224             :                                   &dh->depconf,
     225             :                                   &exchange_sig->eddsa_signature,
     226             :                                   &exchange_pub->eddsa_pub))
     227             :   {
     228           0 :     GNUNET_break_op (0);
     229           0 :     return GNUNET_SYSERR;
     230             :   }
     231          33 :   dh->exchange_sig = *exchange_sig;
     232          33 :   dh->exchange_pub = *exchange_pub;
     233          33 :   TEAH_get_auditors_for_dc (dh->exchange,
     234             :                             &auditor_cb,
     235             :                             dh);
     236          33 :   return GNUNET_OK;
     237             : }
     238             : 
     239             : 
     240             : /**
     241             :  * Verify that the signatures on the "403 FORBIDDEN" response from the
     242             :  * exchange demonstrating customer double-spending are valid.
     243             :  *
     244             :  * @param dh deposit handle
     245             :  * @param json json reply with the signature(s) and transaction history
     246             :  * @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not
     247             :  */
     248             : static int
     249           6 : verify_deposit_signature_conflict (
     250             :   const struct TALER_EXCHANGE_DepositHandle *dh,
     251             :   const json_t *json)
     252             : {
     253             :   json_t *history;
     254             :   struct TALER_Amount total;
     255             :   enum TALER_ErrorCode ec;
     256             :   struct GNUNET_HashCode h_denom_pub;
     257             : 
     258           6 :   memset (&h_denom_pub,
     259             :           0,
     260             :           sizeof (h_denom_pub));
     261           6 :   history = json_object_get (json,
     262             :                              "history");
     263           6 :   if (GNUNET_OK !=
     264           6 :       TALER_EXCHANGE_verify_coin_history (&dh->dki,
     265           6 :                                           dh->dki.value.currency,
     266             :                                           &dh->depconf.coin_pub,
     267             :                                           history,
     268             :                                           &h_denom_pub,
     269             :                                           &total))
     270             :   {
     271           0 :     GNUNET_break_op (0);
     272           0 :     return GNUNET_SYSERR;
     273             :   }
     274           6 :   ec = TALER_JSON_get_error_code (json);
     275           6 :   switch (ec)
     276             :   {
     277           5 :   case TALER_EC_EXCHANGE_DEPOSIT_INSUFFICIENT_FUNDS:
     278           5 :     if (0 >
     279           5 :         TALER_amount_add (&total,
     280             :                           &total,
     281             :                           &dh->amount_with_fee))
     282             :     {
     283             :       /* clearly not OK if our transaction would have caused
     284             :          the overflow... */
     285           0 :       return GNUNET_OK;
     286             :     }
     287             : 
     288           5 :     if (0 >= TALER_amount_cmp (&total,
     289             :                                &dh->dki.value))
     290             :     {
     291             :       /* transaction should have still fit */
     292           0 :       GNUNET_break (0);
     293           0 :       return GNUNET_SYSERR;
     294             :     }
     295             :     /* everything OK, proof of double-spending was provided */
     296           5 :     return GNUNET_OK;
     297           1 :   case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
     298           1 :     if (0 != GNUNET_memcmp (&dh->dki.h_key,
     299             :                             &h_denom_pub))
     300           1 :       return GNUNET_OK; /* indeed, proof with different denomination key provided */
     301             :     /* invalid proof provided */
     302           0 :     return GNUNET_SYSERR;
     303           0 :   default:
     304             :     /* unexpected error code */
     305           0 :     GNUNET_break_op (0);
     306           0 :     return GNUNET_SYSERR;
     307             :   }
     308             : }
     309             : 
     310             : 
     311             : /**
     312             :  * Function called when we're done processing the
     313             :  * HTTP /deposit request.
     314             :  *
     315             :  * @param cls the `struct TALER_EXCHANGE_DepositHandle`
     316             :  * @param response_code HTTP response code, 0 on error
     317             :  * @param response parsed JSON result, NULL on error
     318             :  */
     319             : static void
     320          41 : handle_deposit_finished (void *cls,
     321             :                          long response_code,
     322             :                          const void *response)
     323             : {
     324          41 :   struct TALER_EXCHANGE_DepositHandle *dh = cls;
     325             :   struct TALER_ExchangeSignatureP exchange_sig;
     326             :   struct TALER_ExchangePublicKeyP exchange_pub;
     327          41 :   struct TALER_ExchangeSignatureP *es = NULL;
     328          41 :   struct TALER_ExchangePublicKeyP *ep = NULL;
     329          41 :   const json_t *j = response;
     330          41 :   struct TALER_EXCHANGE_HttpResponse hr = {
     331             :     .reply = j,
     332          41 :     .http_status = (unsigned int) response_code
     333             :   };
     334             : 
     335          41 :   dh->job = NULL;
     336          41 :   switch (response_code)
     337             :   {
     338           0 :   case 0:
     339           0 :     hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     340           0 :     break;
     341          33 :   case MHD_HTTP_OK:
     342          33 :     if (GNUNET_OK !=
     343          33 :         verify_deposit_signature_ok (dh,
     344             :                                      j,
     345             :                                      &exchange_sig,
     346             :                                      &exchange_pub))
     347             :     {
     348           0 :       GNUNET_break_op (0);
     349           0 :       hr.http_status = 0;
     350           0 :       hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE;
     351             :     }
     352             :     else
     353             :     {
     354          33 :       es = &exchange_sig;
     355          33 :       ep = &exchange_pub;
     356             :     }
     357          33 :     break;
     358           0 :   case MHD_HTTP_BAD_REQUEST:
     359             :     /* This should never happen, either us or the exchange is buggy
     360             :        (or API version conflict); just pass JSON reply to the application */
     361           0 :     hr.ec = TALER_JSON_get_error_code (j);
     362           0 :     hr.hint = TALER_JSON_get_error_hint (j);
     363           0 :     break;
     364           0 :   case MHD_HTTP_FORBIDDEN:
     365           0 :     hr.ec = TALER_JSON_get_error_code (j);
     366           0 :     hr.hint = TALER_JSON_get_error_hint (j);
     367             :     /* Nothing really to verify, exchange says one of the signatures is
     368             :        invalid; as we checked them, this should never happen, we
     369             :        should pass the JSON reply to the application */
     370           0 :     break;
     371           0 :   case MHD_HTTP_NOT_FOUND:
     372           0 :     hr.ec = TALER_JSON_get_error_code (j);
     373           0 :     hr.hint = TALER_JSON_get_error_hint (j);
     374             :     /* Nothing really to verify, this should never
     375             :      happen, we should pass the JSON reply to the application */
     376           0 :     break;
     377           6 :   case MHD_HTTP_CONFLICT:
     378             :     /* Double spending; check signatures on transaction history */
     379           6 :     if (GNUNET_OK !=
     380           6 :         verify_deposit_signature_conflict (dh,
     381             :                                            j))
     382             :     {
     383           0 :       GNUNET_break_op (0);
     384           0 :       hr.http_status = 0;
     385           0 :       hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE;
     386             :     }
     387             :     else
     388             :     {
     389           6 :       hr.ec = TALER_JSON_get_error_code (j);
     390           6 :       hr.hint = TALER_JSON_get_error_hint (j);
     391             :     }
     392           6 :     break;
     393           2 :   case MHD_HTTP_GONE:
     394             :     /* could happen if denomination was revoked */
     395             :     /* Note: one might want to check /keys for revocation
     396             :        signature here, alas tricky in case our /keys
     397             :        is outdated => left to clients */
     398           2 :     hr.ec = TALER_JSON_get_error_code (j);
     399           2 :     hr.hint = TALER_JSON_get_error_hint (j);
     400           2 :     break;
     401           0 :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     402           0 :     hr.ec = TALER_JSON_get_error_code (j);
     403           0 :     hr.hint = TALER_JSON_get_error_hint (j);
     404             :     /* Server had an internal issue; we should retry, but this API
     405             :        leaves this to the application */
     406           0 :     break;
     407           0 :   default:
     408             :     /* unexpected response code */
     409           0 :     hr.ec = TALER_JSON_get_error_code (j);
     410           0 :     hr.hint = TALER_JSON_get_error_hint (j);
     411           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     412             :                 "Unexpected response code %u/%d for exchange deposit\n",
     413             :                 (unsigned int) response_code,
     414             :                 hr.ec);
     415           0 :     GNUNET_break_op (0);
     416           0 :     break;
     417             :   }
     418          41 :   dh->cb (dh->cb_cls,
     419             :           &hr,
     420             :           GNUNET_TIME_absolute_ntoh (dh->depconf.exchange_timestamp),
     421             :           es,
     422             :           ep);
     423          41 :   TALER_EXCHANGE_deposit_cancel (dh);
     424          41 : }
     425             : 
     426             : 
     427             : /**
     428             :  * Verify signature information about the deposit.
     429             :  *
     430             :  * @param dki public key information
     431             :  * @param amount the amount to be deposited
     432             :  * @param h_wire hash of the merchant’s account details
     433             :  * @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the exchange)
     434             :  * @param coin_pub coin’s public key
     435             :  * @param denom_pub denomination key with which the coin is signed
     436             :  * @param denom_pub_hash hash of @a denom_pub
     437             :  * @param denom_sig exchange’s unblinded signature of the coin
     438             :  * @param timestamp timestamp when the deposit was finalized
     439             :  * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests)
     440             :  * @param refund_deadline date until which the merchant can issue a refund to the customer via the exchange (can be zero if refunds are not allowed)
     441             :  * @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s private key.
     442             :  * @return #GNUNET_OK if signatures are OK, #GNUNET_SYSERR if not
     443             :  */
     444             : static int
     445          41 : verify_signatures (const struct TALER_EXCHANGE_DenomPublicKey *dki,
     446             :                    const struct TALER_Amount *amount,
     447             :                    const struct GNUNET_HashCode *h_wire,
     448             :                    const struct GNUNET_HashCode *h_contract_terms,
     449             :                    const struct TALER_CoinSpendPublicKeyP *coin_pub,
     450             :                    const struct TALER_DenominationSignature *denom_sig,
     451             :                    const struct TALER_DenominationPublicKey *denom_pub,
     452             :                    const struct GNUNET_HashCode *denom_pub_hash,
     453             :                    struct GNUNET_TIME_Absolute timestamp,
     454             :                    const struct TALER_MerchantPublicKeyP *merchant_pub,
     455             :                    struct GNUNET_TIME_Absolute refund_deadline,
     456             :                    const struct TALER_CoinSpendSignatureP *coin_sig)
     457             : {
     458             :   {
     459          82 :     struct TALER_DepositRequestPS dr = {
     460          41 :       .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT),
     461          41 :       .purpose.size = htonl (sizeof (dr)),
     462             :       .h_contract_terms = *h_contract_terms,
     463             :       .h_wire = *h_wire,
     464             :       .h_denom_pub = *denom_pub_hash,
     465          41 :       .wallet_timestamp = GNUNET_TIME_absolute_hton (timestamp),
     466          41 :       .refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline),
     467             :       .merchant = *merchant_pub,
     468             :       .coin_pub = *coin_pub
     469             :     };
     470             : 
     471          41 :     TALER_amount_hton (&dr.amount_with_fee,
     472             :                        amount);
     473          41 :     TALER_amount_hton (&dr.deposit_fee,
     474             :                        &dki->fee_deposit);
     475          41 :     if (GNUNET_OK !=
     476          41 :         GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT,
     477             :                                     &dr,
     478             :                                     &coin_sig->eddsa_signature,
     479             :                                     &coin_pub->eddsa_pub))
     480             :     {
     481           0 :       GNUNET_break_op (0);
     482           0 :       TALER_LOG_WARNING ("Invalid coin signature on /deposit request!\n");
     483             :       {
     484           0 :         TALER_LOG_DEBUG ("... amount_with_fee was %s\n",
     485             :                          TALER_amount2s (amount));
     486           0 :         TALER_LOG_DEBUG ("... deposit_fee was %s\n",
     487             :                          TALER_amount2s (&dki->fee_deposit));
     488             :       }
     489           0 :       return GNUNET_SYSERR;
     490             :     }
     491             :   }
     492             : 
     493             :   /* check coin signature */
     494             :   {
     495          41 :     struct TALER_CoinPublicInfo coin_info = {
     496             :       .coin_pub = *coin_pub,
     497             :       .denom_pub_hash = *denom_pub_hash,
     498             :       .denom_sig = *denom_sig
     499             :     };
     500             : 
     501          41 :     if (GNUNET_YES !=
     502          41 :         TALER_test_coin_valid (&coin_info,
     503             :                                denom_pub))
     504             :     {
     505           0 :       GNUNET_break_op (0);
     506           0 :       TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
     507           0 :       return GNUNET_SYSERR;
     508             :     }
     509             :   }
     510             : 
     511             :   /* Check coin does make a contribution */
     512          41 :   if (0 < TALER_amount_cmp (&dki->fee_deposit,
     513             :                             amount))
     514             :   {
     515           0 :     GNUNET_break_op (0);
     516           0 :     TALER_LOG_WARNING ("Deposit amount smaller than fee\n");
     517           0 :     return GNUNET_SYSERR;
     518             :   }
     519          41 :   return GNUNET_OK;
     520             : }
     521             : 
     522             : 
     523             : void
     524          41 : TALER_EXCHANGE_deposit_permission_sign (
     525             :   const struct TALER_Amount *amount,
     526             :   const struct TALER_Amount *deposit_fee,
     527             :   const struct GNUNET_HashCode *h_wire,
     528             :   const struct GNUNET_HashCode *h_contract_terms,
     529             :   const struct GNUNET_HashCode *h_denom_pub,
     530             :   const struct TALER_CoinSpendPrivateKeyP *coin_priv,
     531             :   struct GNUNET_TIME_Absolute wallet_timestamp,
     532             :   const struct TALER_MerchantPublicKeyP *merchant_pub,
     533             :   struct GNUNET_TIME_Absolute refund_deadline,
     534             :   struct TALER_CoinSpendSignatureP *coin_sig)
     535             : {
     536          82 :   struct TALER_DepositRequestPS dr = {
     537          41 :     .purpose.size = htonl
     538             :                       (sizeof (dr)),
     539          41 :     .purpose.purpose = htonl
     540             :                          (TALER_SIGNATURE_WALLET_COIN_DEPOSIT),
     541             :     .h_contract_terms = *h_contract_terms,
     542             :     .h_wire = *h_wire,
     543             :     .h_denom_pub = *h_denom_pub,
     544          41 :     .wallet_timestamp = GNUNET_TIME_absolute_hton (wallet_timestamp),
     545          41 :     .refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline),
     546             :     .merchant = *merchant_pub
     547             :   };
     548             : 
     549          41 :   GNUNET_assert (GNUNET_OK ==
     550             :                  GNUNET_TIME_round_abs (&wallet_timestamp));
     551          41 :   GNUNET_assert (GNUNET_OK ==
     552             :                  GNUNET_TIME_round_abs (&refund_deadline));
     553          41 :   GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
     554             :                                       &dr.coin_pub.eddsa_pub);
     555          41 :   TALER_amount_hton (&dr.amount_with_fee,
     556             :                      amount);
     557          41 :   TALER_amount_hton (&dr.deposit_fee,
     558             :                      deposit_fee);
     559          41 :   GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv,
     560             :                             &dr,
     561             :                             &coin_sig->eddsa_signature);
     562          41 : }
     563             : 
     564             : 
     565             : struct TALER_EXCHANGE_DepositHandle *
     566          41 : TALER_EXCHANGE_deposit (struct TALER_EXCHANGE_Handle *exchange,
     567             :                         const struct TALER_Amount *amount,
     568             :                         struct GNUNET_TIME_Absolute wire_deadline,
     569             :                         json_t *wire_details,
     570             :                         const struct GNUNET_HashCode *h_contract_terms,
     571             :                         const struct TALER_CoinSpendPublicKeyP *coin_pub,
     572             :                         const struct TALER_DenominationSignature *denom_sig,
     573             :                         const struct TALER_DenominationPublicKey *denom_pub,
     574             :                         struct GNUNET_TIME_Absolute timestamp,
     575             :                         const struct TALER_MerchantPublicKeyP *merchant_pub,
     576             :                         struct GNUNET_TIME_Absolute refund_deadline,
     577             :                         const struct TALER_CoinSpendSignatureP *coin_sig,
     578             :                         TALER_EXCHANGE_DepositResultCallback cb,
     579             :                         void *cb_cls,
     580             :                         enum TALER_ErrorCode *ec)
     581             : {
     582             :   const struct TALER_EXCHANGE_Keys *key_state;
     583             :   const struct TALER_EXCHANGE_DenomPublicKey *dki;
     584             :   struct TALER_EXCHANGE_DepositHandle *dh;
     585             :   struct GNUNET_CURL_Context *ctx;
     586             :   json_t *deposit_obj;
     587             :   CURL *eh;
     588             :   struct GNUNET_HashCode h_wire;
     589             :   struct GNUNET_HashCode denom_pub_hash;
     590             :   struct TALER_Amount amount_without_fee;
     591             :   char arg_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2 + 32];
     592             : 
     593             :   {
     594             :     char pub_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2];
     595             :     char *end;
     596             : 
     597          41 :     end = GNUNET_STRINGS_data_to_string (
     598             :       coin_pub,
     599             :       sizeof (struct TALER_CoinSpendPublicKeyP),
     600             :       pub_str,
     601             :       sizeof (pub_str));
     602          41 :     *end = '\0';
     603          41 :     GNUNET_snprintf (arg_str,
     604             :                      sizeof (arg_str),
     605             :                      "/coins/%s/deposit",
     606             :                      pub_str);
     607             :   }
     608          41 :   (void) GNUNET_TIME_round_abs (&wire_deadline);
     609          41 :   (void) GNUNET_TIME_round_abs (&refund_deadline);
     610          41 :   if (refund_deadline.abs_value_us > wire_deadline.abs_value_us)
     611             :   {
     612           0 :     GNUNET_break_op (0);
     613           0 :     *ec = TALER_EC_EXCHANGE_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE;
     614           0 :     return NULL;
     615             :   }
     616          41 :   GNUNET_assert (GNUNET_YES ==
     617             :                  TEAH_handle_is_ready (exchange));
     618             :   /* initialize h_wire */
     619          41 :   if (GNUNET_OK !=
     620          41 :       TALER_JSON_merchant_wire_signature_hash (wire_details,
     621             :                                                &h_wire))
     622             :   {
     623           0 :     GNUNET_break (0);
     624           0 :     *ec = TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH;
     625           0 :     return NULL;
     626             :   }
     627          41 :   key_state = TALER_EXCHANGE_get_keys (exchange);
     628          41 :   dki = TALER_EXCHANGE_get_denomination_key (key_state,
     629             :                                              denom_pub);
     630          41 :   if (NULL == dki)
     631             :   {
     632           0 :     *ec = TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
     633           0 :     GNUNET_break_op (0);
     634           0 :     return NULL;
     635             :   }
     636          41 :   if (0 >
     637          41 :       TALER_amount_subtract (&amount_without_fee,
     638             :                              amount,
     639             :                              &dki->fee_deposit))
     640             :   {
     641           0 :     *ec = TALER_EC_EXCHANGE_DEPOSIT_FEE_ABOVE_AMOUNT;
     642           0 :     GNUNET_break_op (0);
     643           0 :     return NULL;
     644             :   }
     645          41 :   GNUNET_CRYPTO_rsa_public_key_hash (denom_pub->rsa_public_key,
     646             :                                      &denom_pub_hash);
     647          41 :   if (GNUNET_OK !=
     648          41 :       verify_signatures (dki,
     649             :                          amount,
     650             :                          &h_wire,
     651             :                          h_contract_terms,
     652             :                          coin_pub,
     653             :                          denom_sig,
     654             :                          denom_pub,
     655             :                          &denom_pub_hash,
     656             :                          timestamp,
     657             :                          merchant_pub,
     658             :                          refund_deadline,
     659             :                          coin_sig))
     660             :   {
     661           0 :     *ec = TALER_EC_EXCHANGE_DEPOSIT_COIN_SIGNATURE_INVALID;
     662           0 :     GNUNET_break_op (0);
     663           0 :     return NULL;
     664             :   }
     665             : 
     666          41 :   deposit_obj = GNUNET_JSON_PACK (
     667             :     TALER_JSON_pack_amount ("contribution",
     668             :                             amount),
     669             :     GNUNET_JSON_pack_object_incref ("wire",
     670             :                                     wire_details),
     671             :     GNUNET_JSON_pack_data_auto ("h_wire",
     672             :                                 &h_wire),
     673             :     GNUNET_JSON_pack_data_auto ("h_contract_terms",
     674             :                                 h_contract_terms),
     675             :     GNUNET_JSON_pack_data_auto ("denom_pub_hash",
     676             :                                 &denom_pub_hash),
     677             :     TALER_JSON_pack_denomination_signature ("ub_sig",
     678             :                                             denom_sig),
     679             :     GNUNET_JSON_pack_time_abs ("timestamp",
     680             :                                timestamp),
     681             :     GNUNET_JSON_pack_data_auto ("merchant_pub",
     682             :                                 merchant_pub),
     683             :     GNUNET_JSON_pack_allow_null (
     684             :       GNUNET_JSON_pack_time_abs ("refund_deadline",
     685             :                                  refund_deadline)),
     686             :     GNUNET_JSON_pack_time_abs ("wire_transfer_deadline",
     687             :                                wire_deadline),
     688             :     GNUNET_JSON_pack_data_auto ("coin_sig",
     689             :                                 coin_sig));
     690          41 :   dh = GNUNET_new (struct TALER_EXCHANGE_DepositHandle);
     691          41 :   dh->auditor_chance = AUDITOR_CHANCE;
     692          41 :   dh->exchange = exchange;
     693          41 :   dh->cb = cb;
     694          41 :   dh->cb_cls = cb_cls;
     695          41 :   dh->url = TEAH_path_to_url (exchange,
     696             :                               arg_str);
     697          41 :   if (NULL == dh->url)
     698             :   {
     699           0 :     GNUNET_break (0);
     700           0 :     *ec = TALER_EC_GENERIC_ALLOCATION_FAILURE;
     701           0 :     GNUNET_free (dh);
     702           0 :     json_decref (deposit_obj);
     703           0 :     return NULL;
     704             :   }
     705          41 :   dh->depconf.purpose.size = htonl (sizeof (struct
     706             :                                             TALER_DepositConfirmationPS));
     707          41 :   dh->depconf.purpose.purpose = htonl (
     708             :     TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT);
     709          41 :   dh->depconf.h_contract_terms = *h_contract_terms;
     710          41 :   dh->depconf.h_wire = h_wire;
     711             :   /* dh->depconf.exchange_timestamp; -- initialized later from exchange reply! */
     712          41 :   dh->depconf.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
     713          41 :   TALER_amount_hton (&dh->depconf.amount_without_fee,
     714             :                      &amount_without_fee);
     715          41 :   dh->depconf.coin_pub = *coin_pub;
     716          41 :   dh->depconf.merchant = *merchant_pub;
     717          41 :   dh->amount_with_fee = *amount;
     718          41 :   dh->dki = *dki;
     719          41 :   dh->dki.key.rsa_public_key = NULL; /* lifetime not warranted, so better
     720             :                                         not copy the pointer */
     721             : 
     722          41 :   eh = TALER_EXCHANGE_curl_easy_get_ (dh->url);
     723          82 :   if ( (NULL == eh) ||
     724             :        (GNUNET_OK !=
     725          41 :         TALER_curl_easy_post (&dh->ctx,
     726             :                               eh,
     727             :                               deposit_obj)) )
     728             :   {
     729           0 :     *ec = TALER_EC_GENERIC_CURL_ALLOCATION_FAILURE;
     730           0 :     GNUNET_break (0);
     731           0 :     if (NULL != eh)
     732           0 :       curl_easy_cleanup (eh);
     733           0 :     json_decref (deposit_obj);
     734           0 :     GNUNET_free (dh->url);
     735           0 :     GNUNET_free (dh);
     736           0 :     return NULL;
     737             :   }
     738          41 :   json_decref (deposit_obj);
     739          41 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     740             :               "URL for deposit: `%s'\n",
     741             :               dh->url);
     742          41 :   ctx = TEAH_handle_to_context (exchange);
     743          82 :   dh->job = GNUNET_CURL_job_add2 (ctx,
     744             :                                   eh,
     745          41 :                                   dh->ctx.headers,
     746             :                                   &handle_deposit_finished,
     747             :                                   dh);
     748          41 :   return dh;
     749             : }
     750             : 
     751             : 
     752             : void
     753           0 : TALER_EXCHANGE_deposit_force_dc (struct TALER_EXCHANGE_DepositHandle *deposit)
     754             : {
     755           0 :   deposit->auditor_chance = 1;
     756           0 : }
     757             : 
     758             : 
     759             : void
     760          41 : TALER_EXCHANGE_deposit_cancel (struct TALER_EXCHANGE_DepositHandle *deposit)
     761             : {
     762          41 :   if (NULL != deposit->job)
     763             :   {
     764           0 :     GNUNET_CURL_job_cancel (deposit->job);
     765           0 :     deposit->job = NULL;
     766             :   }
     767          41 :   GNUNET_free (deposit->url);
     768          41 :   TALER_curl_easy_post_finished (&deposit->ctx);
     769          41 :   GNUNET_free (deposit);
     770          41 : }
     771             : 
     772             : 
     773             : /* end of exchange_api_deposit.c */

Generated by: LCOV version 1.14