From ee4077ef8001e0570a0333ed6b24c69eb2504760 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 28 Mar 2022 13:19:21 +0200 Subject: [PATCH] starting with purse creation client API --- src/include/taler_crypto_lib.h | 60 ++- src/include/taler_exchange_service.h | 220 +++++++++- src/lib/Makefile.am | 1 + .../exchange_api_purse_create_with_deposit.c | 410 ++++++++++++++++++ src/util/Makefile.am | 1 + src/util/crypto_contract.c | 47 ++ 6 files changed, 716 insertions(+), 23 deletions(-) create mode 100644 src/lib/exchange_api_purse_create_with_deposit.c create mode 100644 src/util/crypto_contract.c diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h index ef5096405..179c62662 100644 --- a/src/include/taler_crypto_lib.h +++ b/src/include/taler_crypto_lib.h @@ -25,6 +25,7 @@ #include #include "taler_error_codes.h" #include +#include /** @@ -2183,6 +2184,48 @@ TALER_refresh_get_commitment (struct TALER_RefreshCommitmentP *rc, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_Amount *amount_with_fee); + +/** + * Encrypt contract for transmission to a party that will + * merge it into a reserve. + * + * @param purse_pub public key of the purse + * @param contract_priv private key of the contract + * @param merge_priv merge capability to include + * @param contract_terms contract terms to encrypt + * @param[out] econtract set to encrypted contract + * @param[out] econtract_size set to number of bytes in @a econtract + */ +void +TALER_CRYPTO_contract_encrypt_for_merge ( + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_ContractDiffiePrivateP *contract_priv, + const struct TALER_PurseMergePrivateKeyP *merge_priv, + const json_t *contract_terms, + void **econtract, + size_t *econtract_size); + + +/** + * Encrypt contract for the party that will + * merge it into a reserve. + * + * @param purse_pub public key of the purse + * @param contract_priv private key of the contract + * @param econtract encrypted contract + * @param econtract_size number of bytes in @a econtract + * @param[out] merge_priv set to merge capability + * @return decrypted contract terms, or NULL on failure + */ +json_t * +TALER_CRYPTO_contract_decrypt_for_merge ( + const struct TALER_ContractDiffiePrivateP *contract_priv, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const void *econtract, + size_t econtract_size, + struct TALER_PurseMergePrivateKeyP *merge_priv); + + /* **************** Helper-based RSA operations **************** */ /** @@ -4050,7 +4093,8 @@ struct TALER_AgeCommitmentProof struct TALER_AgeProof proof; }; -/* + +/** * @brief Generates a hash of the public keys in the age commitment. * * @param commitment the age commitment - one public key per age group @@ -4061,14 +4105,15 @@ TALER_age_commitment_hash ( const struct TALER_AgeCommitment *commitment, struct TALER_AgeCommitmentHash *hash); -/* + +/** * @brief Generates an age commitent for the given age. * * @param mask The age mask the defines the age groups * @param age The actual age for which an age commitment is generated * @param salt The salt that goes into the key generation. MUST be choosen uniformly random. * @param comm_proof[out] The generated age commitment, ->priv and ->pub allocated via GNUNET_malloc on success - * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise */ enum GNUNET_GenericReturnValue TALER_age_restriction_commit ( @@ -4077,13 +4122,14 @@ TALER_age_restriction_commit ( const uint64_t salt, struct TALER_AgeCommitmentProof *comm_proof); -/* + +/** * @brief Derives another, equivalent age commitment for a given one. * * @param orig Original age commitment * @param salt Salt to randomly move the points on the elliptic curve in order to generate another, equivalent commitment. * @param[out] derived The resulting age commitment, ->priv and ->pub allocated via GNUNET_malloc on success. - * @return GNUNET_OK on success, GNUNET_SYSERR otherwise + * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise */ enum GNUNET_GenericReturnValue TALER_age_commitment_derive ( @@ -4092,13 +4138,13 @@ TALER_age_commitment_derive ( struct TALER_AgeCommitmentProof *derived); -/* +/** * @brief Provide attestation for a given age, from a given age commitment, if possible. * * @param comm_proof The age commitment to be used for attestation. For successful attestation, it must contain the private key for the corresponding age group. * @param age Age (not age group) for which the an attestation should be done * @param[out] attest Signature of the age with the appropriate key from the age commitment for the corresponding age group, if applicaple. - * @return GNUNET_OK on success, GNUNET_NO when no attestation can be made for that age with the given commitment, GNUNET_SYSERR otherwise + * @return #GNUNET_OK on success, #GNUNET_NO when no attestation can be made for that age with the given commitment, #GNUNET_SYSERR otherwise */ enum GNUNET_GenericReturnValue TALER_age_commitment_attest ( diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index 2c52e366c..cf4624252 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -3977,6 +3977,126 @@ TALER_EXCHANGE_add_auditor_denomination_cancel ( /* ********************* W2W API ****************** */ +/** + * Response generated for a contract get request. + */ +struct TALER_EXCHANGE_ContractGetResponse +{ + /** + * Full HTTP response. + */ + struct TALER_EXCHANGE_HttpResponse *hr; + + union + { + struct + { + + /** + * What is the type of the transaction? + */ + enum + { + /** + * This is a request for payment. + */ + TALER_EXCHANGE_CONTRACT_PAYMENT_REQUEST, + + /** + * This is a payment, the receiver needs to + * accepts the terms. + */ + TALER_EXCHANGE_CONTRACT_PAYMENT_OFFER + } type; + + /** + * Key material, depending on @e type. + */ + union + { + /** + * Set if @e type is #TALER_EXCHANGE_CONTRACT_PAYMENT_REQUEST. + */ + struct TALER_PurseContractPublicKeyP purse_pub; + + /** + * Set if @e type is #TALER_EXCHANGE_CONTRACT_PAYMENT_OFFER. + */ + struct TALER_PurseMergePrivateKeyP merge_priv; + } keys; + + /** + * Total value of the purse. + */ + struct TALER_Amount amount; + + /** + * Contract terms. + */ + json_t *contract_terms; + + /** + * Minimum age required to pay for the contract. + */ + uint8_t min_age; + + /** + * When will the purse expire? + */ + struct GNUNET_TIME_Timestamp purse_expiration; + + } success; + } details; + +}; + +/** + * Function called with information about the a purse. + * + * @param cls closure + * @param pgr HTTP response data + */ +typedef void +(*TALER_EXCHANGE_ContractGetCallback) ( + void *cls, + const struct TALER_EXCHANGE_ContractGetResponse *pgr); + + +/** + * @brief Handle for a GET /contracts/$CPUB request. + */ +struct TALER_EXCHANGE_ContractsGetHandle; + + +/** + * Request information about a contract from the exchange. + * + * @param ctx the context + * @param url HTTP base URL for the exchange + * @param contract_priv private key of the contract + * @param cb function to call with the exchange's result + * @param cb_cls closure for @a cb + * @return the request handle; NULL upon error + */ +struct TALER_EXCHANGE_ContractGetHandle * +TALER_EXCHANGE_contract_get ( + struct GNUNET_CURL_Context *ctx, + const char *url, + const struct TALER_ContractDiffiePrivateP *contract_priv, + TALER_EXCHANGE_ContractGetCallback cb, + void *cb_cls); + + +/** + * Cancel #TALER_EXCHANGE_contract_get() operation. + * + * @param cgh handle of the operation to cancel + */ +void +TALER_EXCHANGE_contract_get_cancel ( + struct TALER_EXCHANGE_ContractGetHandle *cgh); + + /** * Response generated for a purse get request. */ @@ -3987,12 +4107,36 @@ struct TALER_EXCHANGE_PurseGetResponse */ struct TALER_EXCHANGE_HttpResponse *hr; + /** + * Details depending on the HTTP status. + */ union { + /** + * Response on #MHD_HTTP_OK. + */ + struct + { + /** + * Time when the purse was merged (or zero if it + * was not merged). + */ + struct GNUNET_TIME_Timestamp merge_timestamp; + + /** + * Time when the full amount was deposited into + * the purse (or zero if a sufficient amount + * was not yet deposited). + */ + struct GNUNET_TIME_Timestamp deposit_timestamp; + + } success; + } details; }; + /** * Function called with information about the a purse. * @@ -4016,10 +4160,9 @@ struct TALER_EXCHANGE_PurseGetHandle; * * @param ctx the context * @param url HTTP base URL for the exchange - * @param purse_priv private key of the purse to check + * @param purse_priv private key of the purse * @param merge_timeout how long to wait for a merge to happen * @param deposit_timeout how long to wait for a deposit to happen - * @param return_contract true if we should return the contract (if available) * @param cb function to call with the exchange's result * @param cb_cls closure for @a cb * @return the request handle; NULL upon error @@ -4031,7 +4174,6 @@ TALER_EXCHANGE_purse_get ( const struct TALER_PurseContractPrivateKeyP *purse_priv, struct GNUNET_TIME_Relative merge_timeout, struct GNUNET_TIME_Relative deposit_timeout, - bool return_contract, TALER_EXCHANGE_PurseGetCallback cb, void *cb_cls); @@ -4054,10 +4196,27 @@ struct TALER_EXCHANGE_PurseCreateDepositResponse /** * Full HTTP response. */ - struct TALER_EXCHANGE_HttpResponse *hr; + struct TALER_EXCHANGE_HttpResponse hr; + /** + * Details depending on the HTTP status. + */ union { + + /** + * Detailed returned on #MHD_HTTP_OK. + */ + struct + { + + /** + * Private key that can be used to obtain the contract. + */ + struct TALER_ContractDiffiePrivateP contract_priv; + + } success; + } details; }; @@ -4086,10 +4245,12 @@ struct TALER_EXCHANGE_PurseCreateDepositHandle; */ struct TALER_EXCHANGE_PurseDeposit { +#if FIXME_OEC /** * Age commitment data. */ struct TALER_AgeCommitment age_commitment; +#endif /** * Private key of the coin. @@ -4118,14 +4279,12 @@ struct TALER_EXCHANGE_PurseDeposit * Inform the exchange that a purse should be created * and coins deposited into it. * - * @param ctx the context - * @param url HTTP base URL for the exchange + * @param exchange the exchange to interact with * @param purse_priv private key of the purse - * @param merge_pub identifies merge credential + * @param merge_priv the merge credential + * @param contract_priv key needed to obtain and decrypt the contract * @param contract_terms contract the purse is about - * @param min_age minimum age we need to prove for the purse * @param purse_expiration when will the unmerged purse expire - * @param purse_value_after_fees target amount in the purse * @param num_deposits length of the @a deposits array * @param deposits array of deposits to make into the purse * @param cb function to call with the exchange's result @@ -4134,14 +4293,12 @@ struct TALER_EXCHANGE_PurseDeposit */ struct TALER_EXCHANGE_PurseCreateDepositHandle * TALER_EXCHANGE_purse_create_with_deposit ( - struct GNUNET_CURL_Context *ctx, - const char *url, + struct TALER_EXCHANGE_Handle *exchange, const struct TALER_PurseContractPrivateKeyP *purse_priv, - const struct TALER_PurseMergePublicKeyP *merge_pub, + const struct TALER_PurseMergePrivateKeyP *merge_priv, + const struct TALER_ContractDiffiePrivateP *contract_priv, const json_t *contract_terms, - uint32_t min_age, struct GNUNET_TIME_Timestamp purse_expiration, - const struct TALER_Amount *purse_value_after_fees, unsigned int num_deposits, const struct TALER_EXCHANGE_PurseDeposit *deposits, TALER_EXCHANGE_PurseCreateDepositCallback cb, @@ -4168,8 +4325,19 @@ struct TALER_EXCHANGE_AccountMergeResponse */ struct TALER_EXCHANGE_HttpResponse *hr; + /** + * Details depending on the HTTP status. + */ union { + /** + * Detailed returned on #MHD_HTTP_OK. + */ + struct + { + + } success; + } details; }; @@ -4241,8 +4409,18 @@ struct TALER_EXCHANGE_PurseCreateMergeResponse */ struct TALER_EXCHANGE_HttpResponse *hr; + /** + * Details depending on the HTTP status. + */ union { + /** + * Detailed returned on #MHD_HTTP_OK. + */ + struct + { + + } success; } details; }; @@ -4290,7 +4468,7 @@ TALER_EXCHANGE_purse_create_with_merge ( const struct TALER_ReservePrivateKeyP *reserve_priv, const struct TALER_PurseContractPrivateKeyP *purse_priv, const json_t *contract_terms, - uint32_t min_age, + uint8_t min_age, struct GNUNET_TIME_Timestamp purse_expiration, struct GNUNET_TIME_Timestamp merge_timestamp, const struct TALER_Amount *purse_value_after_fees, @@ -4318,8 +4496,18 @@ struct TALER_EXCHANGE_PurseDepositResponse */ struct TALER_EXCHANGE_HttpResponse *hr; + /** + * Details depending on the HTTP status. + */ union { + /** + * Detailed returned on #MHD_HTTP_OK. + */ + struct + { + + } success; } details; }; @@ -4364,7 +4552,7 @@ TALER_EXCHANGE_purse_deposit ( const char *url, const char *purse_exchange_url, const struct TALER_PurseContractPublicKeyP *purse_pub, - uint32_t min_age, + uint8_t min_age, unsigned int num_deposits, const struct TALER_EXCHANGE_PurseDeposit *deposits, TALER_EXCHANGE_PurseDepositCallback cb, diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 730c833d7..52ef2d2a0 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -45,6 +45,7 @@ libtalerexchange_la_SOURCES = \ exchange_api_management_wire_disable.c \ exchange_api_management_wire_enable.c \ exchange_api_melt.c \ + exchange_api_purse_create_with_deposit.c \ exchange_api_recoup.c \ exchange_api_recoup_refresh.c \ exchange_api_refresh_common.c exchange_api_refresh_common.h \ diff --git a/src/lib/exchange_api_purse_create_with_deposit.c b/src/lib/exchange_api_purse_create_with_deposit.c new file mode 100644 index 000000000..6765b7771 --- /dev/null +++ b/src/lib/exchange_api_purse_create_with_deposit.c @@ -0,0 +1,410 @@ +/* + 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 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see + + */ +/** + * @file lib/exchange_api_purse_create_with_deposit.c + * @brief Implementation of the client to create a purse with + * an initial set of deposits (and a contract) + * @author Christian Grothoff + */ +#include "platform.h" +#include +#include /* just for HTTP status codes */ +#include +#include +#include +#include "taler_json_lib.h" +#include "taler_exchange_service.h" +#include "exchange_api_handle.h" +#include "taler_signatures.h" +#include "exchange_api_curl_defaults.h" + + +/** + * @brief A purse create with deposit handle + */ +struct TALER_EXCHANGE_PurseCreateDepositHandle +{ + + /** + * The connection to exchange this request handle will use + */ + struct TALER_EXCHANGE_Handle *exchange; + + /** + * The url for this request. + */ + char *url; + + /** + * Context for #TEH_curl_easy_post(). Keeps the data that must + * persist for Curl to make the upload. + */ + struct TALER_CURL_PostContext ctx; + + /** + * Handle for the request. + */ + struct GNUNET_CURL_Job *job; + + /** + * Function to call with the result. + */ + TALER_EXCHANGE_PurseCreateDepositCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; + +}; + + +/** + * Function called when we're done processing the + * HTTP /deposit request. + * + * @param cls the `struct TALER_EXCHANGE_DepositHandle` + * @param response_code HTTP response code, 0 on error + * @param response parsed JSON result, NULL on error + */ +static void +handle_purse_create_deposit_finished (void *cls, + long response_code, + const void *response) +{ + struct TALER_EXCHANGE_PurseCreateDepositHandle *pch = cls; + const json_t *j = response; + struct TALER_EXCHANGE_PurseCreateDepositResponse dr = { + .hr.reply = j, + .hr.http_status = (unsigned int) response_code + }; + + pch->job = NULL; + switch (response_code) + { + case 0: + dr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + break; + case MHD_HTTP_OK: + { + const struct TALER_EXCHANGE_Keys *key_state; + struct GNUNET_JSON_Specification spec[] = { +#if 0 + GNUNET_JSON_spec_fixed_auto ("exchange_sig", + &pch->exchange_sig), + GNUNET_JSON_spec_fixed_auto ("exchange_pub", + &pch->exchange_pub), +#endif + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (j, + spec, + NULL, NULL)) + { + GNUNET_break_op (0); + dr.hr.http_status = 0; + dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + break; + } + key_state = TALER_EXCHANGE_get_keys (pch->exchange); +#if 0 + if (GNUNET_OK != + TALER_EXCHANGE_test_signing_key (key_state, + &exchange_pub)) + { + GNUNET_break_op (0); + dr.hr.http_status = 0; + dr.hr.ec = + TALER_EC_EXCHANGE_PURSE_CREATE_WITH_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE; + break; + } +#endif + // FIXME: validate reply... + (void) key_state; + } + break; + case MHD_HTTP_BAD_REQUEST: + /* This should never happen, either us or the exchange is buggy + (or API version conflict); just pass JSON reply to the application */ + dr.hr.ec = TALER_JSON_get_error_code (j); + dr.hr.hint = TALER_JSON_get_error_hint (j); + break; + case MHD_HTTP_FORBIDDEN: + dr.hr.ec = TALER_JSON_get_error_code (j); + dr.hr.hint = TALER_JSON_get_error_hint (j); + /* Nothing really to verify, exchange says one of the signatures is + invalid; as we checked them, this should never happen, we + should pass the JSON reply to the application */ + break; + case MHD_HTTP_NOT_FOUND: + dr.hr.ec = TALER_JSON_get_error_code (j); + dr.hr.hint = TALER_JSON_get_error_hint (j); + /* Nothing really to verify, this should never + happen, we should pass the JSON reply to the application */ + break; + case MHD_HTTP_CONFLICT: + // FIXME: check reply? + break; + case MHD_HTTP_GONE: + /* could happen if denomination was revoked */ + /* Note: one might want to check /keys for revocation + signature here, alas tricky in case our /keys + is outdated => left to clients */ + dr.hr.ec = TALER_JSON_get_error_code (j); + dr.hr.hint = TALER_JSON_get_error_hint (j); + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + dr.hr.ec = TALER_JSON_get_error_code (j); + dr.hr.hint = TALER_JSON_get_error_hint (j); + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + break; + default: + /* unexpected response code */ + dr.hr.ec = TALER_JSON_get_error_code (j); + dr.hr.hint = TALER_JSON_get_error_hint (j); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u/%d for exchange deposit\n", + (unsigned int) response_code, + dr.hr.ec); + GNUNET_break_op (0); + break; + } + pch->cb (pch->cb_cls, + &dr); + TALER_EXCHANGE_purse_create_with_deposit_cancel (pch); +} + + +struct TALER_EXCHANGE_PurseCreateDepositHandle * +TALER_EXCHANGE_purse_create_with_deposit ( + struct TALER_EXCHANGE_Handle *exchange, + const struct TALER_PurseContractPrivateKeyP *purse_priv, + const struct TALER_PurseMergePrivateKeyP *merge_priv, + const struct TALER_ContractDiffiePrivateP *contract_priv, + const json_t *contract_terms, + struct GNUNET_TIME_Timestamp purse_expiration, + unsigned int num_deposits, + const struct TALER_EXCHANGE_PurseDeposit *deposits, + TALER_EXCHANGE_PurseCreateDepositCallback cb, + void *cb_cls) +{ + struct TALER_EXCHANGE_PurseCreateDepositHandle *pch; + struct GNUNET_CURL_Context *ctx; + json_t *create_obj; + json_t *deposit_arr; + CURL *eh; + struct TALER_PurseMergePublicKeyP merge_pub; + struct TALER_PurseContractPublicKeyP purse_pub; + struct TALER_ContractDiffiePublicP contract_pub; + struct TALER_PrivateContractHashP h_contract_terms; + char arg_str[sizeof (purse_pub) * 2 + 32]; + char *url; + uint32_t min_age; + struct TALER_Amount purse_value_after_fees; + struct GNUNET_JSON_Specification spec[] = { + TALER_JSON_spec_amount_any ("amount", + &purse_value_after_fees), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_uint32 ("minimum_age", + &min_age)), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (contract_terms, + spec, + NULL, NULL)) + { + GNUNET_break (0); + return NULL; + } + GNUNET_assert (GNUNET_YES == + TEAH_handle_is_ready (exchange)); + if (GNUNET_OK != + TALER_JSON_contract_hash (contract_terms, + &h_contract_terms)) + { + GNUNET_break (0); + return NULL; + } + GNUNET_CRYPTO_eddsa_key_get_public (&purse_priv->eddsa_priv, + &purse_pub.eddsa_pub); + { + char pub_str[sizeof (purse_pub) * 2]; + char *end; + + end = GNUNET_STRINGS_data_to_string ( + &purse_pub, + sizeof (purse_pub), + pub_str, + sizeof (pub_str)); + *end = '\0'; + GNUNET_snprintf (arg_str, + sizeof (arg_str), + "/purses/%s/create", + pub_str); + } + pch = GNUNET_new (struct TALER_EXCHANGE_PurseCreateDepositHandle); + pch->exchange = exchange; + pch->cb = cb; + pch->cb_cls = cb_cls; + GNUNET_CRYPTO_ecdhe_key_get_public (&contract_priv->ecdhe_priv, + &contract_pub.ecdhe_pub); + GNUNET_CRYPTO_eddsa_key_get_public (&merge_priv->eddsa_priv, + &merge_pub.eddsa_pub); + pch->url = TEAH_path_to_url (exchange, + arg_str); + if (NULL == pch->url) + { + GNUNET_break (0); + GNUNET_free (pch); + return NULL; + } + deposit_arr = json_array (); + GNUNET_assert (NULL != deposit_arr); + url = TEAH_path_to_url (exchange, + "/"); + for (unsigned int i = 0; iage_commitment, + &agh); + aghp = &agh; + if (GNUNET_OK != + TALER_age_commitment_attest (&deposit->age_proof, + min_age, + &attest)) + { + GNUNET_break (0); + json_decref (deposit_arr); + GNUNET_free (url); + GNUNET_free (pch); + return NULL; + } +#endif + TALER_wallet_purse_deposit_sign ( + url, + &purse_pub, + &deposit->amount, + &deposit->coin_priv, + &coin_sig); + jdeposit = GNUNET_JSON_PACK ( +#if FIXME_OEC + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_data_auto ("h_age_commitment", + aghp)), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_data_auto ("age_attestation", + &attest)), +#endif + TALER_JSON_pack_amount ("amount", + &deposit->amount), + GNUNET_JSON_pack_data_auto ("denom_pub_hash", + &deposit->h_denom_pub), + TALER_JSON_pack_denom_sig ("ub_sig", + &deposit->denom_sig), + GNUNET_JSON_pack_data_auto ("coin_sig", + &coin_sig)); + GNUNET_assert (0 == + json_array_append_new (deposit_arr, + jdeposit)); + } + GNUNET_free (url); + { + void *econtract; + size_t econtract_size; + + TALER_CRYPTO_contract_encrypt_for_merge (&purse_pub, + contract_priv, + merge_priv, + contract_terms, + &econtract, + &econtract_size); + create_obj = GNUNET_JSON_PACK ( + TALER_JSON_pack_amount ("amount", + &purse_value_after_fees), + GNUNET_JSON_pack_uint64 ("min_age", + min_age), + GNUNET_JSON_pack_data_varsize ("econtract", + econtract, + econtract_size), + GNUNET_JSON_pack_data_auto ("contract_pub", + &contract_pub), + GNUNET_JSON_pack_data_auto ("merge_pub", + &merge_pub), + GNUNET_JSON_pack_data_auto ("h_contract_terms", + &h_contract_terms), + GNUNET_JSON_pack_array_steal ("deposits", + deposit_arr)); + GNUNET_free (econtract); + } + GNUNET_assert (NULL != create_obj); + eh = TALER_EXCHANGE_curl_easy_get_ (pch->url); + if ( (NULL == eh) || + (GNUNET_OK != + TALER_curl_easy_post (&pch->ctx, + eh, + create_obj)) ) + { + GNUNET_break (0); + if (NULL != eh) + curl_easy_cleanup (eh); + json_decref (create_obj); + GNUNET_free (pch->url); + GNUNET_free (pch); + return NULL; + } + json_decref (create_obj); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "URL for purse create with deposit: `%s'\n", + pch->url); + ctx = TEAH_handle_to_context (exchange); + pch->job = GNUNET_CURL_job_add2 (ctx, + eh, + pch->ctx.headers, + &handle_purse_create_deposit_finished, + pch); + return pch; +} + + +void +TALER_EXCHANGE_purse_create_with_deposit_cancel ( + struct TALER_EXCHANGE_PurseCreateDepositHandle *pch) +{ + if (NULL != pch->job) + { + GNUNET_CURL_job_cancel (pch->job); + pch->job = NULL; + } + GNUNET_free (pch->url); + TALER_curl_easy_post_finished (&pch->ctx); + GNUNET_free (pch); +} + + +/* end of exchange_api_purse_create_with_deposit.c */ diff --git a/src/util/Makefile.am b/src/util/Makefile.am index a24f081b5..8ef9e146d 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -80,6 +80,7 @@ libtalerutil_la_SOURCES = \ auditor_signatures.c \ config.c \ crypto.c \ + crypto_contract.c \ crypto_helper_common.c crypto_helper_common.h \ crypto_helper_rsa.c \ crypto_helper_cs.c \ diff --git a/src/util/crypto_contract.c b/src/util/crypto_contract.c new file mode 100644 index 000000000..7f684d80a --- /dev/null +++ b/src/util/crypto_contract.c @@ -0,0 +1,47 @@ +/* + 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 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 General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see +*/ +/** + * @file util/crypto_contract.c + * @brief functions for encrypting and decrypting contracts for P2P payments + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_util.h" + + +void +TALER_CRYPTO_contract_encrypt_for_merge ( + const struct TALER_PurseContractPublicKeyP *purse_pub, + const struct TALER_ContractDiffiePrivateP *contract_priv, + const struct TALER_PurseMergePrivateKeyP *merge_priv, + const json_t *contract_terms, + void **econtract, + + size_t *econtract_size) +{ +} + + +json_t * +TALER_CRYPTO_contract_decrypt_for_merge ( + const struct TALER_ContractDiffiePrivateP *contract_priv, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const void *econtract, + size_t econtract_size, + struct TALER_PurseMergePrivateKeyP *merge_priv) +{ + return NULL; +}