gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-exchange] branch master updated (a227ee6d -> 3249687b)


From: gnunet
Subject: [taler-exchange] branch master updated (a227ee6d -> 3249687b)
Date: Mon, 28 Mar 2022 18:18:15 +0200

This is an automated email from the git hooks/post-receive script.

grothoff pushed a change to branch master
in repository exchange.

    from a227ee6d -first cut at contract encryption and decryption
     new b25c9398 starting work on purse-create endpoint
     new 3249687b rename to avoid symbol conflict with musl

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/exchange/taler-exchange-httpd_purses_create.c | 609 ++++++++++++++++++++++
 src/include/taler_crypto_lib.h                    |   2 +-
 src/include/taler_exchange_service.h              |  23 +-
 src/lib/exchange_api_purse_create_with_deposit.c  |  12 +
 src/util/crypto_contract.c                        |  60 +--
 5 files changed, 667 insertions(+), 39 deletions(-)
 create mode 100644 src/exchange/taler-exchange-httpd_purses_create.c

diff --git a/src/exchange/taler-exchange-httpd_purses_create.c 
b/src/exchange/taler-exchange-httpd_purses_create.c
new file mode 100644
index 00000000..ee822b25
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_purses_create.c
@@ -0,0 +1,609 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2022 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU Affero General Public License as published by the Free 
Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
details.
+
+  You should have received a copy of the GNU Affero General Public License 
along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_purses_create.c
+ * @brief Handle /purses/$PID/create requests; parses the POST and JSON and
+ *        verifies the coin signature before handing things off
+ *        to the database.
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_json_lib.h>
+#include <jansson.h>
+#include <microhttpd.h>
+#include <pthread.h>
+#include "taler_json_lib.h"
+#include "taler_mhd_lib.h"
+#include "taler-exchange-httpd_purses_create.h"
+#include "taler-exchange-httpd_responses.h"
+#include "taler_exchangedb_lib.h"
+#include "taler-exchange-httpd_keys.h"
+
+
+/**
+ * Information about an individual coin being deposited.
+ */
+struct Coin
+{
+  /**
+   * Public information about the coin.
+   */
+  struct TALER_CoinPublicInfo cpi;
+
+  /**
+   * Signature affirming spending the coin.
+   */
+  struct TALER_CoinSpendSignatureP coin_sig;
+
+  /**
+   * Amount to be put into the purse from this coin.
+   */
+  struct TALER_Amount amount;
+
+  /**
+   * Deposit fee applicable for this coin.
+   */
+  struct TALER_Amount deposit_fee;
+};
+
+
+/**
+ * Closure for #create_transaction.
+ */
+struct PurseCreateContext
+{
+  /**
+   * Public key of the purse we are creating.
+   */
+  const struct TALER_PurseContractPublicKeyP *purse_pub;
+
+  /**
+   * Total amount to be put into the purse.
+   */
+  struct TALER_Amount amount;
+
+  /**
+   * Total actually deposited by all the coins.
+   */
+  struct TALER_Amount deposit_total;
+
+  /**
+   * When should the purse expire.
+   */
+  struct GNUNET_TIME_Timestamp purse_expiration;
+
+  /**
+   * Our current time.
+   */
+  struct GNUNET_TIME_Timestamp exchange_timestamp;
+
+  /**
+   * Merge key for the purse.
+   */
+  struct TALER_PurseMergePublicKeyP merge_pub;
+
+  /**
+   * Contract decryption key for the purse.
+   */
+  struct TALER_ContractDiffiePublicP contract_pub;
+
+  /**
+   * Signature of the client affiming this request.
+   */
+  struct TALER_PurseContractSignatureP purse_sig;
+
+  /**
+   * Hash of the contract terms of the purse.
+   */
+  struct TALER_PrivateContractHashP h_contract_terms;
+
+  /**
+   * Array of coins being deposited.
+   */
+  struct Coin *coins;
+
+  /**
+   * Encrypted contract, can be NULL.
+   */
+  void *econtract;
+
+  /**
+   * Number of bytes in @e econtract.
+   */
+  size_t econtract_size;
+
+  /**
+   * Length of the @e coins array.
+   */
+  unsigned int num_coins;
+
+};
+
+
+/**
+ * Send confirmation of purse creation success to client.
+ *
+ * @param connection connection to the client
+ * @param pcc details about the request that succeeded
+ * @return MHD result code
+ */
+static MHD_RESULT
+reply_create_success (struct MHD_Connection *connection,
+                      const struct PurseCreateContext *pcc)
+{
+  struct TALER_ExchangePublicKeyP pub;
+  struct TALER_ExchangeSignatureP sig;
+  // FIXME: define what exactly we sign over!
+  struct TALER_DepositConfirmationPS dc = {
+    .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_CREATION),
+    .purpose.size = htonl (sizeof (dc)),
+    .h_contract_terms = pcc->h_contract_terms,
+    .purse_pub = *pcc->purse_pub
+  };
+  enum TALER_ErrorCode ec;
+
+  TALER_amount_hton (&dc.amount_without_fee,
+                     &pcc->amount);
+  if (TALER_EC_NONE !=
+      (ec = TEH_keys_exchange_sign (&dc,
+                                    &pub,
+                                    &sig)))
+  {
+    return TALER_MHD_reply_with_ec (connection,
+                                    ec,
+                                    NULL);
+  }
+  return TALER_MHD_REPLY_JSON_PACK (
+    connection,
+    MHD_HTTP_OK,
+    // GNUNET_JSON_pack_timestamp ("exchange_timestamp",
+    // pcc->exchange_timestamp),
+    GNUNET_JSON_pack_data_auto ("exchange_sig",
+                                &sig),
+    GNUNET_JSON_pack_data_auto ("exchange_pub",
+                                &pub));
+}
+
+
+/**
+ * Execute database transaction for /purses/$PID/create.  Runs the transaction
+ * logic; IF it returns a non-error code, the transaction logic MUST NOT queue
+ * a MHD response.  IF it returns an hard error, the transaction logic MUST
+ * queue a MHD response and set @a mhd_ret.  IF it returns the soft error
+ * code, the function MAY be called again to retry and MUST not queue a MHD
+ * response.
+ *
+ * @param cls a `struct PurseCreateContext`
+ * @param connection MHD request context
+ * @param[out] mhd_ret set to MHD status on error
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+create_transaction (void *cls,
+                    struct MHD_Connection *connection,
+                    MHD_RESULT *mhd_ret)
+{
+  struct PurseCreateContext *pcc = cls;
+  enum GNUNET_DB_QueryStatus qs;
+  bool balance_ok;
+  bool in_conflict;
+
+  // 1) create purse
+  // 2) deposit all coins
+  // 3) if present, persist contract
+  // Also: nicely report errors...
+  qs = TEH_plugin->XXX (TEH_plugin->cls, ...);
+  if (qs < 0)
+  {
+    if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+      return qs;
+    TALER_LOG_WARNING ("Failed to store purse information in database\n");
+    *mhd_ret = TALER_MHD_reply_with_error (connection,
+                                           MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                           TALER_EC_GENERIC_DB_STORE_FAILED,
+                                           "purse create");
+    return qs;
+  }
+  if (in_conflict)
+  {
+    TEH_plugin->rollback (TEH_plugin->cls);
+    *mhd_ret
+      = TEH_RESPONSE_reply_coin_insufficient_funds (
+          connection,
+          TALER_EC_EXCHANGE_PURSE_CREATE_CONFLICTING_CONTRACT,
+          &coin->pci.coin_pub);
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  }
+  if (! balance_ok)
+  {
+    TEH_plugin->rollback (TEH_plugin->cls);
+    *mhd_ret
+      = TEH_RESPONSE_reply_coin_insufficient_funds (
+          connection,
+          TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS,
+          &coin->pci.coin_pub);
+    return GNUNET_DB_STATUS_HARD_ERROR;
+  }
+  return qs;
+}
+
+
+/**
+ * Parse a coin and check signature of the coin and the denomination
+ * signature over the coin.
+ *
+ * @param[in,out] our HTTP connection
+ * @param[in,out] request context
+ * @param[out] coin coin to initialize
+ * @param jcoin coin to parse
+ * @return #GNUNET_OK on success, #GNUNET_NO if an error was returned,
+ *         #GNUNET_SYSERR on failure and no error could be returned
+ */
+static enum GNUNET_GenericReturnValue
+parse_coin (struct MHD_Connection *connection,
+            struct PurseCreateContext *pcc,
+            struct Coin *coin,
+            const json_t *jcoin)
+{
+  struct GNUNET_JSON_Specification spec[] = {
+    TALER_JSON_spec_amount ("amount",
+                            TEH_currency,
+                            &coin->amount),
+    GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
+                                 &coin->cpi.denom_pub_hash),
+    TALER_JSON_spec_denom_sig ("ub_sig",
+                               &coin->cpi.denom_sig),
+    GNUNET_JSON_spec_mark_optional (
+      GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
+                                   &coin->cpi.h_age_commitment)),
+    &coin->cpi.no_age_commitment),
+    GNUNET_JSON_spec_fixed_auto ("coin_sig",
+                                 &coin->coin_sig),
+    GNUNET_JSON_spec_fixed_auto ("coin_pub",
+                                 &coin->cpi.coin_pub),
+    GNUNET_JSON_spec_end ()
+  };
+
+  {
+    enum GNUNET_GenericReturnValue res;
+
+    res = TALER_MHD_parse_json_data (connection,
+                                     jcoin,
+                                     spec);
+    if (GNUNET_OK != res)
+      return res;
+  }
+
+  if (GNUNET_OK !=
+      TALER_wallet_purse_deposit_verify ("http://FIXME-URL";,
+                                         &pcc->purse_pub,
+                                         &pcc->amount,
+                                         &coin->coin_pub,
+                                         &coin->csig))
+  {
+    TALER_LOG_WARNING ("Invalid signature on /purses/$PID/create request\n");
+    GNUNET_JSON_parse_free (spec);
+    return (MHD_YES ==
+            TALER_MHD_reply_with_error (connection,
+                                        MHD_HTTP_UNAUTHORIZED,
+                                        
TALER_EC_EXCHANGE_PURSE_CREATE_COIN_SIGNATURE_INVALID,
+                                        NULL))
+           ? GNUNET_NO : GNUNET_SYSERR;
+  }
+  /* check denomination exists and is valid */
+  {
+    struct TEH_DenominationKey *dk;
+    MHD_RESULT mret;
+
+    dk = TEH_keys_denomination_by_hash (&coin->denom_pub_hash,
+                                        connection,
+                                        &mret);
+    if (NULL == dk)
+    {
+      GNUNET_JSON_parse_free (spec);
+      return (MHD_YES == mret) ? GNUNET_NO : GNUNET_SYSERR:
+    }
+    if (GNUNET_TIME_absolute_is_past (dk->meta.expire_deposit.abs_time))
+    {
+      /* This denomination is past the expiration time for deposits */
+      GNUNET_JSON_parse_free (spec);
+      return (MHD_YES ==
+              TEH_RESPONSE_reply_expired_denom_pub_hash (
+                connection,
+                &coin->denom_pub_hash,
+                TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
+                "PURSE CREATE"))
+             ? GNUNET_NO : GNUNET_SYSERR:
+    }
+    if (GNUNET_TIME_absolute_is_future (dk->meta.start.abs_time))
+    {
+      /* This denomination is not yet valid */
+      GNUNET_JSON_parse_free (spec);
+      return (MHD_YES ==
+              TEH_RESPONSE_reply_expired_denom_pub_hash (
+                connection,
+                &coin->denom_pub_hash,
+                TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE,
+                "PURSE CREATE"))
+             ? GNUNET_NO : GNUNET_SYSERR;
+    }
+    if (dk->recoup_possible)
+    {
+      /* This denomination has been revoked */
+      GNUNET_JSON_parse_free (spec);
+      return (MHD_YES ==
+              TEH_RESPONSE_reply_expired_denom_pub_hash (
+                connection,
+                &deposit.coin.denom_pub_hash,
+                TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED,
+                "PURSE CREATE"))
+             ? GNUNET_NO : GNUNET_SYSERR;
+    }
+    if (dk->denom_pub.cipher != deposit.coin.denom_sig.cipher)
+    {
+      /* denomination cipher and denomination signature cipher not the same */
+      GNUNET_JSON_parse_free (spec);
+      return (MHD_YES ==
+              TALER_MHD_reply_with_error (connection,
+                                          MHD_HTTP_BAD_REQUEST,
+                                          
TALER_EC_EXCHANGE_GENERIC_CIPHER_MISMATCH,
+                                          NULL))
+             ? GNUNET_NO : GNUNET_SYSERR;
+    }
+
+    coin->deposit_fee = dk->meta.fees.deposit;
+    /* check coin signature */
+    switch (dk->denom_pub.cipher)
+    {
+    case TALER_DENOMINATION_RSA:
+      TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_RSA]++;
+      break;
+    case TALER_DENOMINATION_CS:
+      TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_CS]++;
+      break;
+    default:
+      break;
+    }
+    if (GNUNET_YES !=
+        TALER_test_coin_valid (&deposit.coin,
+                               &dk->denom_pub))
+    {
+      TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
+      GNUNET_JSON_parse_free (spec);
+      return (MHD_YES ==
+              TALER_MHD_reply_with_error (connection,
+                                          MHD_HTTP_UNAUTHORIZED,
+                                          
TALER_EC_EXCHANGE_DENOMINATION_SIGNATURE_INVALID,
+                                          NULL))
+             ? GNUNET_NO : GNUNET_SYSERR;
+    }
+  }
+  {
+    MHD_RESULT mhd_ret = MHD_NO;
+    enum GNUNET_DB_QueryStatus qs;
+
+    /* make sure coin is 'known' in database */
+    for (unsigned int tries = 0; tries<MAX_TRANSACTION_COMMIT_RETRIES; tries++)
+    {
+      qs = TEH_make_coin_known (&deposit.coin,
+                                connection,
+                                &pcc.known_coin_id,
+                                &mhd_ret);
+      /* no transaction => no serialization failures should be possible */
+      if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
+        break;
+    }
+    if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+    {
+      GNUNET_break (0);
+      return (MHD_YES ==
+              TALER_MHD_reply_with_error (connection,
+                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                          TALER_EC_GENERIC_DB_COMMIT_FAILED,
+                                          "make_coin_known"))
+             ? GNUNET_NO : GNUNET_SYSERR;
+    }
+    if (qs < 0)
+      return (MHD_YES == mhd_ret) ? GNUNET_NO : GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+MHD_RESULT
+TEH_handler_purses_create (struct MHD_Connection *connection,
+                           const struct
+                           TALER_PurseContractPublicKeyP *purse_pub,
+                           const json_t *root)
+{
+  struct PurseCreateContext pcc = {
+    .purse_pub = purse_pub,
+    .exchange_timestamp = GNUNET_TIME_timestamp_get ();
+  };
+  json_t *deposits;
+  json_t *deposit;
+  unsigned int idx;
+  struct GNUNET_JSON_Specification spec[] = {
+    TALER_JSON_spec_amount ("amount",
+                            TEH_currency,
+                            &pcc.amount),
+    GNUNET_JSON_spec_uint32 ("min_age",
+                             &pcc.min_age),
+    GNUNET_JSON_spec_mark_optional (
+      GNUNET_JSON_spec_var_size ("econtract",
+                                 &pcc.econtract,
+                                 &pcc.ecotract_size)),
+    GNUNET_JSON_spec_fixed_auto ("contract_pub",
+                                 &pcc.contract_pub),
+    GNUNET_JSON_spec_fixed_auto ("merge_pub",
+                                 &pcc.merge_pub),
+    GNUNET_JSON_spec_fixed_auto ("purse_sig",
+                                 &pcc.purse_sig),
+    GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
+                                 &pcc.h_contract_terms),
+    GNUNET_JSON_spec_json ("deposits",
+                           &deposits),
+    GNUNET_JSON_spec_timestamp ("purse_expiration",
+                                &pcc.purse_expiration),
+    GNUNET_JSON_spec_end ()
+  };
+
+  {
+    enum GNUNET_GenericReturnValue res;
+
+    res = TALER_MHD_parse_json_data (connection,
+                                     root,
+                                     spec);
+    if (GNUNET_SYSERR == res)
+    {
+      GNUNET_break (0);
+      return MHD_NO; /* hard failure */
+    }
+    if (GNUNET_NO == res)
+    {
+      GNUNET_break_op (0);
+      return MHD_YES; /* failure */
+    }
+  }
+
+  if (GNUNET_TIME_timestamp_cmp (pcc.purse_expiration,
+                                 <,
+                                 pcc.exchange_timestamp))
+  {
+    GNUNET_break_op (0);
+    GNUNET_JSON_parse_free (spec);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       
TALER_EC_EXCHANGE_PURSE_CREATE_EXPIRATION_BEFORE_NOW,
+                                       NULL);
+  }
+  if (GNUNET_TIME_absolute_is_never (pcc.purse_expiration.abs_time))
+  {
+    GNUNET_break_op (0);
+    GNUNET_JSON_parse_free (spec);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       
TALER_EC_EXCHANGE_PURSE_CREATE_EXPIRATION_IS_NEVER,
+                                       NULL);
+  }
+  pcc.num_coins = json_array_size (deposits);
+  if ( (0 == pcc.num_coins) ||
+       (pcc.num_coins > TALER_MAX_FRESH_COINS) )
+  {
+    GNUNET_break_op (0);
+    GNUNET_JSON_parse_free (spec);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       
TALER_EC_EXCHANGE_GENERIC_PARAMETER_MALFORMED,
+                                       "deposits");
+  }
+  /* parse deposits */
+  pcc.coins = GNUNET_new_array (struct Coin,
+                                pcc.num_coins);
+  json_array_foreach (deposits, idx, deposit)
+  {
+    enum GNUNET_GenericReturnValue res;
+    struct Coin *coin = &pcc.coins[idx];
+
+    res = parse_coin (connection,
+                      &pcc,
+                      coin,
+                      deposit);
+    if (GNUNET_OK != res)
+    {
+      GNUNET_JSON_parse_free (spec);
+      GNUNET_free (pcc.coins);
+      return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+    }
+  }
+
+  // FIXME: get purse_fee!
+  if (0 < TALER_amount_cmp (&purse_fee,
+                            &pcc.deposit_total))
+  {
+    GNUNET_break_op (0);
+    GNUNET_JSON_parse_free (spec);
+    GNUNET_free (pcc.coins);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       
TALER_EC_EXCHANGE_CREATE_PURSE_NEGATIVE_VALUE_AFTER_FEE,
+                                       NULL);
+  }
+
+  TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
+
+  if (GNUNET_OK !=
+      TALER_wallet_purse_create_verify (&pcc.purse_expiration,
+                                        &pcc.h_contract_terms,
+                                        &pcc.merge_pub,
+                                        pcc.min_age,
+                                        &pcc.amount,
+                                        &pcc.purse_pub,
+                                        &pcc.purse_sig))
+  {
+    TALER_LOG_WARNING ("Invalid signature on /purses/$PID/create request\n");
+    GNUNET_JSON_parse_free (spec);
+    GNUNET_free (pcc.coins);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_UNAUTHORIZED,
+                                       
TALER_EC_EXCHANGE_PURSE_CREATE_COIN_SIGNATURE_INVALID,
+                                       NULL);
+  }
+
+  if (GNUNET_SYSERR ==
+      TEH_plugin->preflight (TEH_plugin->cls))
+  {
+    GNUNET_break (0);
+    GNUNET_free (pcc.coins);
+    return TALER_MHD_reply_with_error (connection,
+                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                       TALER_EC_GENERIC_DB_START_FAILED,
+                                       "preflight failure");
+  }
+
+  /* execute transaction */
+  {
+    MHD_RESULT mhd_ret;
+
+    if (GNUNET_OK !=
+        TEH_DB_run_transaction (connection,
+                                "execute purse create",
+                                TEH_MT_REQUEST_PURSE_CREATE,
+                                &mhd_ret,
+                                &create_transaction,
+                                &pcc))
+    {
+      GNUNET_JSON_parse_free (spec);
+      GNUNET_free (pcc.coins);
+      return mhd_ret;
+    }
+  }
+
+  /* generate regular response */
+  {
+    MHD_RESULT res;
+
+    res = reply_create_success (connection,
+                                &pcc);
+    GNUNET_free (pcc.coins);
+    GNUNET_JSON_parse_free (spec);
+    return res;
+  }
+}
+
+
+/* end of taler-exchange-httpd_purses_create.c */
diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h
index 179c6266..cc489e2c 100644
--- a/src/include/taler_crypto_lib.h
+++ b/src/include/taler_crypto_lib.h
@@ -29,7 +29,7 @@
 
 
 /**
- * Maximum number of fresh coins we allow per refresh operation.
+ * Maximum number of coins we allow per operation.
  */
 #define TALER_MAX_FRESH_COINS 256
 
diff --git a/src/include/taler_exchange_service.h 
b/src/include/taler_exchange_service.h
index 00c8c101..20e7943f 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -3985,10 +3985,16 @@ struct TALER_EXCHANGE_ContractGetResponse
   /**
    * Full HTTP response.
    */
-  struct TALER_EXCHANGE_HttpResponse *hr;
+  struct TALER_EXCHANGE_HttpResponse hr;
 
+  /**
+   * Details depending on the HTTP status code.
+   */
   union
   {
+    /**
+     * Information returned on #MHD_HTTP_OK.
+     */
     struct
     {
 
@@ -4000,13 +4006,13 @@ struct TALER_EXCHANGE_ContractGetResponse
         /**
          * This is a request for payment.
          */
-        TALER_EXCHANGE_CONTRACT_PAYMENT_REQUEST,
+        TALER_EXCHANGE_CONTRACT_PAYMENT_REQUEST = 0,
 
         /**
          * This is a payment, the receiver needs to
          * accepts the terms.
          */
-        TALER_EXCHANGE_CONTRACT_PAYMENT_OFFER
+        TALER_EXCHANGE_CONTRACT_PAYMENT_OFFER = 1
       } type;
 
       /**
@@ -4026,7 +4032,7 @@ struct TALER_EXCHANGE_ContractGetResponse
       } keys;
 
       /**
-       * Total value of the purse.
+       * Total value of the contract/purse.
        */
       struct TALER_Amount amount;
 
@@ -4046,6 +4052,7 @@ struct TALER_EXCHANGE_ContractGetResponse
       struct GNUNET_TIME_Timestamp purse_expiration;
 
     } success;
+
   } details;
 
 };
@@ -4105,7 +4112,7 @@ struct TALER_EXCHANGE_PurseGetResponse
   /**
    * Full HTTP response.
    */
-  struct TALER_EXCHANGE_HttpResponse *hr;
+  struct TALER_EXCHANGE_HttpResponse hr;
 
   /**
    * Details depending on the HTTP status.
@@ -4327,7 +4334,7 @@ struct TALER_EXCHANGE_AccountMergeResponse
   /**
    * Full HTTP response.
    */
-  struct TALER_EXCHANGE_HttpResponse *hr;
+  struct TALER_EXCHANGE_HttpResponse hr;
 
   /**
    * Details depending on the HTTP status.
@@ -4411,7 +4418,7 @@ struct TALER_EXCHANGE_PurseCreateMergeResponse
   /**
    * Full HTTP response.
    */
-  struct TALER_EXCHANGE_HttpResponse *hr;
+  struct TALER_EXCHANGE_HttpResponse hr;
 
   /**
    * Details depending on the HTTP status.
@@ -4498,7 +4505,7 @@ struct TALER_EXCHANGE_PurseDepositResponse
   /**
    * Full HTTP response.
    */
-  struct TALER_EXCHANGE_HttpResponse *hr;
+  struct TALER_EXCHANGE_HttpResponse hr;
 
   /**
    * Details depending on the HTTP status.
diff --git a/src/lib/exchange_api_purse_create_with_deposit.c 
b/src/lib/exchange_api_purse_create_with_deposit.c
index e39cb076..5ce91e0e 100644
--- a/src/lib/exchange_api_purse_create_with_deposit.c
+++ b/src/lib/exchange_api_purse_create_with_deposit.c
@@ -212,6 +212,7 @@ TALER_EXCHANGE_purse_create_with_deposit (
   json_t *deposit_arr;
   CURL *eh;
   struct TALER_PurseMergePublicKeyP merge_pub;
+  struct TALER_PurseContractSignatureP purse_sig;
   struct TALER_PurseContractPublicKeyP purse_pub;
   struct TALER_ContractDiffiePublicP contract_pub;
   struct TALER_PrivateContractHashP h_contract_terms;
@@ -335,6 +336,13 @@ TALER_EXCHANGE_purse_create_with_deposit (
                                           jdeposit));
   }
   GNUNET_free (url);
+  TALER_wallet_purse_create_sign (purse_expiration,
+                                  &h_contract_terms,
+                                  &merge_pub,
+                                  min_age,
+                                  &purse_value_after_fees,
+                                  purse_priv,
+                                  &purse_sig);
   {
     void *econtract = NULL;
     size_t econtract_size = 0;
@@ -357,10 +365,14 @@ TALER_EXCHANGE_purse_create_with_deposit (
                                        econtract_size)),
       GNUNET_JSON_pack_data_auto ("contract_pub",
                                   &contract_pub),
+      GNUNET_JSON_pack_data_auto ("purse_sig",
+                                  &purse_sig),
       GNUNET_JSON_pack_data_auto ("merge_pub",
                                   &merge_pub),
       GNUNET_JSON_pack_data_auto ("h_contract_terms",
                                   &h_contract_terms),
+      GNUNET_JSON_pack_timestamp ("purse_expiration",
+                                  purse_expiration),
       GNUNET_JSON_pack_array_steal ("deposits",
                                     deposit_arr));
     GNUNET_free (econtract);
diff --git a/src/util/crypto_contract.c b/src/util/crypto_contract.c
index 5117712e..026eec31 100644
--- a/src/util/crypto_contract.c
+++ b/src/util/crypto_contract.c
@@ -90,14 +90,14 @@ derive_key (const void *key_material,
  * @param[out] res_size size of the ciphertext
  */
 static void
-encrypt (const struct NonceP *nonce,
-         const void *key,
-         size_t key_len,
-         const void *data,
-         size_t data_size,
-         const char *salt,
-         void **res,
-         size_t *res_size)
+contract_encrypt (const struct NonceP *nonce,
+                  const void *key,
+                  size_t key_len,
+                  const void *data,
+                  size_t data_size,
+                  const char *salt,
+                  void **res,
+                  size_t *res_size)
 {
   size_t ciphertext_size;
   struct SymKeyP skey;
@@ -134,13 +134,13 @@ encrypt (const struct NonceP *nonce,
  * @return #GNUNET_OK on success
  */
 static enum GNUNET_GenericReturnValue
-decrypt (const void *key,
-         size_t key_len,
-         const void *data,
-         size_t data_size,
-         const char *salt,
-         void **res,
-         size_t *res_size)
+contract_decrypt (const void *key,
+                  size_t key_len,
+                  const void *data,
+                  size_t data_size,
+                  const char *salt,
+                  void **res,
+                  size_t *res_size)
 {
   const struct NonceP *nonce;
   struct SymKeyP skey;
@@ -251,14 +251,14 @@ TALER_CRYPTO_contract_encrypt_for_merge (
   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
                               &nonce,
                               sizeof (nonce));
-  encrypt (&nonce,
-           &key,
-           sizeof (key),
-           hdr,
-           sizeof (*hdr) + cbuf_size,
-           MERGE_SALT,
-           econtract,
-           econtract_size);
+  contract_encrypt (&nonce,
+                    &key,
+                    sizeof (key),
+                    hdr,
+                    sizeof (*hdr) + cbuf_size,
+                    MERGE_SALT,
+                    econtract,
+                    econtract_size);
   GNUNET_free (hdr);
 }
 
@@ -289,13 +289,13 @@ TALER_CRYPTO_contract_decrypt_for_merge (
     return NULL;
   }
   if (GNUNET_OK !=
-      decrypt (&key,
-               sizeof (key),
-               econtract,
-               econtract_size,
-               MERGE_SALT,
-               &xhdr,
-               &hdr_size))
+      contract_decrypt (&key,
+                        sizeof (key),
+                        econtract,
+                        econtract_size,
+                        MERGE_SALT,
+                        &xhdr,
+                        &hdr_size))
   {
     GNUNET_break_op (0);
     return NULL;

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]