diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index aa53d4493..844ca52fc 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -25,7 +25,7 @@ libtalerexchange_la_SOURCES = \ exchange_api_batch_withdraw.c \ exchange_api_batch_withdraw2.c \ exchange_api_curl_defaults.c exchange_api_curl_defaults.h \ - exchange_api_common.c \ + exchange_api_common.c exchange_api_common.h \ exchange_api_contracts_get.c \ exchange_api_csr_melt.c \ exchange_api_csr_withdraw.c \ diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c index 9cbcdeb26..567239eed 100644 --- a/src/lib/exchange_api_common.c +++ b/src/lib/exchange_api_common.c @@ -1414,4 +1414,232 @@ TALER_EXCHANGE_get_signing_key_info ( } +enum GNUNET_GenericReturnValue +TALER_EXCHANGE_check_purse_create_conflict_ ( + const struct TALER_PurseContractSignatureP *cpurse_sig, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const json_t *proof) +{ + struct TALER_Amount amount; + uint32_t min_age; + struct GNUNET_TIME_Timestamp purse_expiration; + struct TALER_PurseContractSignatureP purse_sig; + struct TALER_PrivateContractHashP h_contract_terms; + struct TALER_PurseMergePublicKeyP merge_pub; + struct GNUNET_JSON_Specification spec[] = { + TALER_JSON_spec_amount_any ("amount", + &amount), + GNUNET_JSON_spec_uint32 ("min_age", + &min_age), + GNUNET_JSON_spec_timestamp ("purse_expiration", + &purse_expiration), + GNUNET_JSON_spec_fixed_auto ("purse_sig", + &purse_sig), + GNUNET_JSON_spec_fixed_auto ("h_contract_terms", + &h_contract_terms), + GNUNET_JSON_spec_fixed_auto ("merge_pub", + &merge_pub), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (proof, + spec, + NULL, NULL)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + TALER_wallet_purse_create_verify (purse_expiration, + &h_contract_terms, + &merge_pub, + min_age, + &amount, + purse_pub, + &purse_sig)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (0 == + GNUNET_memcmp (&purse_sig, + cpurse_sig)) + { + /* Must be the SAME data, not a conflict! */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +static char * +make_payto (const char *exchange_url, + const struct TALER_ReservePublicKeyP *reserve_pub) +{ + char pub_str[sizeof (*reserve_pub) * 2]; + char *end; + bool is_http; + char *reserve_url; + + end = GNUNET_STRINGS_data_to_string ( + reserve_pub, + sizeof (*reserve_pub), + pub_str, + sizeof (pub_str)); + *end = '\0'; + if (0 == strncmp (exchange_url, + "http://", + strlen ("http://"))) + { + is_http = true; + exchange_url = &exchange_url[strlen ("http://")]; + } + else if (0 == strncmp (exchange_url, + "https://", + strlen ("https://"))) + { + is_http = false; + exchange_url = &exchange_url[strlen ("https://")]; + } + else + { + GNUNET_break (0); + return NULL; + } + /* exchange_url includes trailing '/' */ + GNUNET_asprintf (&reserve_url, + "payto://%s/%s%s", + is_http ? "taler+http" : "taler", + exchange_url, + pub_str); + return reserve_url; +} + + +enum GNUNET_GenericReturnValue +TALER_EXCHANGE_check_purse_merge_conflict_ ( + const struct TALER_PurseMergeSignatureP *cmerge_sig, + const struct TALER_PurseMergePublicKeyP *merge_pub, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const char *exchange_url, + const json_t *proof) +{ + struct TALER_PurseMergeSignatureP merge_sig; + struct GNUNET_TIME_Timestamp merge_timestamp; + const char *partner_url = exchange_url; + struct TALER_ReservePublicKeyP reserve_pub; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_mark_optional ( + // FIXME: partner_url or partner_base_url? + GNUNET_JSON_spec_string ("partner_url", + &partner_url), + NULL), + GNUNET_JSON_spec_timestamp ("merge_timestamp", + &merge_timestamp), + GNUNET_JSON_spec_fixed_auto ("merge_sig", + &merge_sig), + GNUNET_JSON_spec_fixed_auto ("reserve_pub", + &reserve_pub), + GNUNET_JSON_spec_end () + }; + char *payto_uri; + + if (GNUNET_OK != + GNUNET_JSON_parse (proof, + spec, + NULL, NULL)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + payto_uri = make_payto (partner_url, + &reserve_pub); + if (GNUNET_OK != + TALER_wallet_purse_merge_verify ( + payto_uri, + merge_timestamp, + purse_pub, + merge_pub, + &merge_sig)) + { + GNUNET_break_op (0); + GNUNET_free (payto_uri); + return GNUNET_SYSERR; + } + GNUNET_free (payto_uri); + if (0 == + GNUNET_memcmp (&merge_sig, + cmerge_sig)) + { + /* Must be the SAME data, not a conflict! */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Check proof of a contract conflict. + * + * DESIGN-FIXME: this 'proof' doesn't really proof a conflict! + * + * @param ccontract_sig conflicting signature (must + * not match the signature from the proof) + * @param purse_pub public key of the purse + * @param exchange_url the base URL of this exchange + * @param proof the proof to check + * @return #GNUNET_OK if the @a proof is OK for @a purse_pub and conflicts with @a purse_sig + */ +enum GNUNET_GenericReturnValue +TALER_EXCHANGE_check_purse_econtract_conflict_ ( + const struct TALER_PurseContractSignatureP *ccontract_sig, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const json_t *proof) +{ + struct TALER_ContractDiffiePublicP contract_pub; + struct TALER_PurseContractSignatureP contract_sig; + struct GNUNET_HashCode h_econtract; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("h_econtract", + &h_econtract), + GNUNET_JSON_spec_fixed_auto ("econtract_sig", + &contract_sig), + GNUNET_JSON_spec_fixed_auto ("contract_pub", + &contract_pub), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (proof, + spec, + NULL, NULL)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + TALER_wallet_econtract_upload_verify2 ( + &h_econtract, + &contract_pub, + purse_pub, + &contract_sig)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (0 == + GNUNET_memcmp (&contract_sig, + ccontract_sig)) + { + /* Must be the SAME data, not a conflict! */ + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + /* end of exchange_api_common.c */ diff --git a/src/lib/exchange_api_common.h b/src/lib/exchange_api_common.h new file mode 100644 index 000000000..9c6d45029 --- /dev/null +++ b/src/lib/exchange_api_common.h @@ -0,0 +1,84 @@ +/* + This file is part of TALER + Copyright (C) 2015-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_common.h + * @brief common functions for the exchange API + * @author Christian Grothoff + */ +#ifndef EXCHANGE_API_COMMON_H +#define EXCHANGE_API_COMMON_H + +#include "taler_json_lib.h" + + +/** + * Check proof of a purse creation conflict. + * + * @param cpurse_sig conflicting signature (must + * not match the signature from the proof) + * @param purse_pub the public key (must match + * the signature from the proof) + * @param proof the proof to check + * @return #GNUNET_OK if the @a proof is OK for @a purse_pub and conflicts with @a purse_sig + */ +enum GNUNET_GenericReturnValue +TALER_EXCHANGE_check_purse_create_conflict_ ( + const struct TALER_PurseContractSignatureP *cpurse_sig, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const json_t *proof); + + +/** + * Check proof of a purse merge conflict. + * + * @param cmerge_sig conflicting signature (must + * not match the signature from the proof) + * @param merge_pub the public key (must match + * the signature from the proof) + * @param exchange_url the base URL of this exchange + * @param proof the proof to check + * @return #GNUNET_OK if the @a proof is OK for @a purse_pub and conflicts with @a purse_sig + */ +enum GNUNET_GenericReturnValue +TALER_EXCHANGE_check_purse_merge_conflict_ ( + const struct TALER_PurseMergeSignatureP *cmerge_sig, + const struct TALER_PurseMergePublicKeyP *merge_pub, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const char *exchange_url, + const json_t *proof); + + +/** + * Check proof of a contract conflict. + * + * DESIGN-FIXME: this 'proof' doesn't really proof a conflict! + * + * @param ccontract_sig conflicting signature (must + * not match the signature from the proof) + * @param purse_pub public key of the purse + * @param exchange_url the base URL of this exchange + * @param proof the proof to check + * @return #GNUNET_OK if the @a proof is OK for @a purse_pub and conflicts with @a purse_sig + */ +enum GNUNET_GenericReturnValue +TALER_EXCHANGE_check_purse_econtract_conflict_ ( + const struct TALER_PurseContractSignatureP *ccontract_sig, + const struct TALER_PurseContractPublicKeyP *purse_pub, + const json_t *proof); + + +#endif diff --git a/src/lib/exchange_api_handle.h b/src/lib/exchange_api_handle.h index 569c723c4..7ef88489e 100644 --- a/src/lib/exchange_api_handle.h +++ b/src/lib/exchange_api_handle.h @@ -19,7 +19,9 @@ * @brief Internal interface to the handle part of the exchange's HTTP API * @author Christian Grothoff */ -#include "platform.h" +#ifndef EXCHANGE_API_HANDLE_H +#define EXCHANGE_API_HANDLE_H + #include #include "taler_auditor_service.h" #include "taler_exchange_service.h" @@ -254,3 +256,4 @@ TEAH_path_to_url (struct TALER_EXCHANGE_Handle *h, const char *path); /* end of exchange_api_handle.h */ +#endif diff --git a/src/lib/exchange_api_purse_create_with_deposit.c b/src/lib/exchange_api_purse_create_with_deposit.c index cace73249..f21b7d312 100644 --- a/src/lib/exchange_api_purse_create_with_deposit.c +++ b/src/lib/exchange_api_purse_create_with_deposit.c @@ -29,6 +29,7 @@ #include "taler_json_lib.h" #include "taler_exchange_service.h" #include "exchange_api_handle.h" +#include "exchange_api_common.h" #include "taler_signatures.h" #include "exchange_api_curl_defaults.h" @@ -75,6 +76,11 @@ struct TALER_EXCHANGE_PurseCreateDepositHandle */ struct TALER_Amount purse_value_after_fees; + /** + * Our encryped contract (if we had any). + */ + struct TALER_EncryptedContract econtract; + /** * Public key of the merge capability. */ @@ -86,7 +92,12 @@ struct TALER_EXCHANGE_PurseCreateDepositHandle struct TALER_PurseContractPublicKeyP purse_pub; /** - * Hash over the purse's contrac terms. + * Signature with the purse key on the request. + */ + struct TALER_PurseContractSignatureP purse_sig; + + /** + * Hash over the purse's contract terms. */ struct TALER_PrivateContractHashP h_contract_terms; @@ -94,6 +105,7 @@ struct TALER_EXCHANGE_PurseCreateDepositHandle * When does the purse expire. */ struct GNUNET_TIME_Timestamp purse_expiration; + }; @@ -201,7 +213,85 @@ handle_purse_create_deposit_finished (void *cls, happen, we should pass the JSON reply to the application */ break; case MHD_HTTP_CONFLICT: - // FIXME: check reply! + { + dr.hr.ec = TALER_JSON_get_error_code (j); + switch (dr.hr.ec) + { + case TALER_EC_EXCHANGE_PURSE_CREATE_CONFLICTING_META_DATA: + if (GNUNET_OK != + TALER_EXCHANGE_check_purse_create_conflict_ ( + &pch->purse_sig, + &pch->purse_pub, + j)) + { + GNUNET_break_op (0); + dr.hr.http_status = 0; + dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + break; + } + break; + case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS: + { +#if FIXME + struct TALER_Amount total; + struct TALER_DenominationHashP h_denom_pub; + const struct TALER_EXCHANGE_DenomPublicKey *dk = NULL; + + // FIXME: parse coin_pub + // FIXME: lookup dk for that coin from our deposits array! + + if (NULL == dk) + { + /* not one of our coins */ + GNUNET_break_op (0); + dr.hr.http_status = 0; + dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + break; + } + if (GNUNET_OK != + TALER_EXCHANGE_verify_coin_history (dk, + pch->exchange->currency, + &coin_pub, + history, + &h_denom_pub, + &total)) + { + GNUNET_break_op (0); + dr.hr.http_status = 0; + dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + break; + } + // FIXME: check total is too high for the request... +#endif + break; + } + case TALER_EC_EXCHANGE_PURSE_DEPOSIT_CONFLICTING_META_DATA: + { + // FIXME! + break; + } + case TALER_EC_EXCHANGE_PURSE_ECONTRACT_CONFLICTING_META_DATA: + if (GNUNET_OK != + TALER_EXCHANGE_check_purse_econtract_conflict_ ( + &pch->econtract.econtract_sig, + &pch->purse_pub, + j)) + { + GNUNET_break_op (0); + dr.hr.http_status = 0; + dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + break; + } + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected error code %d for conflcting deposit\n", + dr.hr.ec); + GNUNET_break_op (0); + dr.hr.http_status = 0; + dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + } + } break; case MHD_HTTP_GONE: /* could happen if denomination was revoked */ @@ -252,8 +342,6 @@ TALER_EXCHANGE_purse_create_with_deposit ( json_t *create_obj; json_t *deposit_arr; CURL *eh; - struct TALER_PurseContractSignatureP purse_sig; - struct TALER_EncryptedContract econtract; char arg_str[sizeof (pch->purse_pub) * 2 + 32]; char *url; uint32_t min_age = 0; @@ -391,22 +479,22 @@ TALER_EXCHANGE_purse_create_with_deposit ( min_age, &pch->purse_value_after_fees, purse_priv, - &purse_sig); + &pch->purse_sig); if (upload_contract) { TALER_CRYPTO_contract_encrypt_for_merge (&pch->purse_pub, contract_priv, merge_priv, contract_terms, - &econtract.econtract, - &econtract.econtract_size); + &pch->econtract.econtract, + &pch->econtract.econtract_size); GNUNET_CRYPTO_ecdhe_key_get_public (&contract_priv->ecdhe_priv, - &econtract.contract_pub.ecdhe_pub); - TALER_wallet_econtract_upload_sign (econtract.econtract, - econtract.econtract_size, - &econtract.contract_pub, + &pch->econtract.contract_pub.ecdhe_pub); + TALER_wallet_econtract_upload_sign (pch->econtract.econtract, + pch->econtract.econtract_size, + &pch->econtract.contract_pub, purse_priv, - &econtract.econtract_sig); + &pch->econtract.econtract_sig); } create_obj = GNUNET_JSON_PACK ( TALER_JSON_pack_amount ("amount", @@ -416,10 +504,10 @@ TALER_EXCHANGE_purse_create_with_deposit ( GNUNET_JSON_pack_allow_null ( TALER_JSON_pack_econtract ("econtract", upload_contract - ? &econtract + ? &pch->econtract : NULL)), GNUNET_JSON_pack_data_auto ("purse_sig", - &purse_sig), + &pch->purse_sig), GNUNET_JSON_pack_data_auto ("merge_pub", &pch->merge_pub), GNUNET_JSON_pack_data_auto ("h_contract_terms", @@ -429,7 +517,6 @@ TALER_EXCHANGE_purse_create_with_deposit ( GNUNET_JSON_pack_array_steal ("deposits", deposit_arr)); GNUNET_assert (NULL != create_obj); - GNUNET_free (econtract.econtract); eh = TALER_EXCHANGE_curl_easy_get_ (pch->url); if ( (NULL == eh) || (GNUNET_OK != @@ -441,6 +528,7 @@ TALER_EXCHANGE_purse_create_with_deposit ( if (NULL != eh) curl_easy_cleanup (eh); json_decref (create_obj); + GNUNET_free (pch->econtract.econtract); GNUNET_free (pch->url); GNUNET_free (pch); return NULL; @@ -468,6 +556,7 @@ TALER_EXCHANGE_purse_create_with_deposit_cancel ( GNUNET_CURL_job_cancel (pch->job); pch->job = NULL; } + GNUNET_free (pch->econtract.econtract); GNUNET_free (pch->url); TALER_curl_easy_post_finished (&pch->ctx); GNUNET_free (pch); diff --git a/src/lib/exchange_api_purse_create_with_merge.c b/src/lib/exchange_api_purse_create_with_merge.c index e726b712f..4ca633360 100644 --- a/src/lib/exchange_api_purse_create_with_merge.c +++ b/src/lib/exchange_api_purse_create_with_merge.c @@ -29,6 +29,7 @@ #include "taler_json_lib.h" #include "taler_exchange_service.h" #include "exchange_api_handle.h" +#include "exchange_api_common.h" #include "taler_signatures.h" #include "exchange_api_curl_defaults.h" @@ -235,173 +236,48 @@ handle_purse_create_with_merge_finished (void *cls, switch (dr.hr.ec) { case TALER_EC_EXCHANGE_RESERVES_PURSE_CREATE_CONFLICTING_META_DATA: + if (GNUNET_OK != + TALER_EXCHANGE_check_purse_create_conflict_ ( + &pcm->purse_sig, + &pcm->purse_pub, + j)) { - struct TALER_Amount amount; - uint32_t min_age; - struct GNUNET_TIME_Timestamp purse_expiration; - struct TALER_PurseContractSignatureP purse_sig; - struct TALER_PrivateContractHashP h_contract_terms; - struct TALER_PurseMergePublicKeyP merge_pub; - struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_amount_any ("amount", - &amount), - GNUNET_JSON_spec_uint32 ("min_age", - &min_age), - GNUNET_JSON_spec_timestamp ("purse_expiration", - &purse_expiration), - GNUNET_JSON_spec_fixed_auto ("purse_sig", - &purse_sig), - GNUNET_JSON_spec_fixed_auto ("h_contract_terms", - &h_contract_terms), - GNUNET_JSON_spec_fixed_auto ("merge_pub", - &merge_pub), - 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; - } - if (GNUNET_OK != - TALER_wallet_purse_create_verify (purse_expiration, - &h_contract_terms, - &merge_pub, - min_age, - &amount, - &pcm->purse_pub, - &purse_sig)) - { - GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - if (0 == - GNUNET_memcmp (&purse_sig, - &pcm->purse_sig)) - { - /* Must be the SAME data, not a conflict! */ - GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } + dr.hr.http_status = 0; + dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } + break; case TALER_EC_EXCHANGE_RESERVES_PURSE_MERGE_CONFLICTING_META_DATA: + if (GNUNET_OK != + TALER_EXCHANGE_check_purse_merge_conflict_ ( + &pcm->merge_sig, + &pcm->merge_pub, + &pcm->purse_pub, + pcm->exchange->url, + j)) { - struct TALER_PurseMergeSignatureP merge_sig; - struct GNUNET_TIME_Timestamp merge_timestamp; - const char *partner_url = pcm->exchange->url; - struct TALER_ReservePublicKeyP reserve_pub; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("partner_url", - &partner_url), - NULL), - GNUNET_JSON_spec_timestamp ("merge_timestamp", - &merge_timestamp), - GNUNET_JSON_spec_fixed_auto ("merge_sig", - &merge_sig), - GNUNET_JSON_spec_fixed_auto ("reserve_pub", - &reserve_pub), - 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; - } - if (GNUNET_OK != - TALER_wallet_purse_merge_verify ( - partner_url, - merge_timestamp, - &pcm->purse_pub, - &pcm->merge_pub, - &merge_sig)) - { - GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - if (0 == - GNUNET_memcmp (&merge_sig, - &pcm->merge_sig)) - { - /* Must be the SAME data, not a conflict! */ - GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } + GNUNET_break_op (0); + dr.hr.http_status = 0; + dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + break; } break; case TALER_EC_EXCHANGE_RESERVES_PURSE_CREATE_INSUFFICIENT_FUNDS: /* nothing to verify */ break; case TALER_EC_EXCHANGE_PURSE_ECONTRACT_CONFLICTING_META_DATA: + if (GNUNET_OK != + TALER_EXCHANGE_check_purse_econtract_conflict_ ( + &pcm->econtract.econtract_sig, + &pcm->purse_pub, + j)) { - struct TALER_ContractDiffiePublicP contract_pub; - struct TALER_PurseContractSignatureP contract_sig; - struct GNUNET_HashCode h_econtract; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ("h_econtract", - &h_econtract), - GNUNET_JSON_spec_fixed_auto ("econtract_sig", - &contract_sig), - GNUNET_JSON_spec_fixed_auto ("contract_pub", - &contract_pub), - 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; - } - if (GNUNET_OK != - TALER_wallet_econtract_upload_verify2 ( - &h_econtract, - &contract_pub, - &pcm->purse_pub, - &contract_sig)) - { - GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - if (0 == - GNUNET_memcmp (&contract_sig, - &pcm->econtract.econtract_sig)) - { - /* Must be the SAME data, not a conflict! */ - GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - + GNUNET_break_op (0); + dr.hr.http_status = 0; + dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } + break; default: /* unexpected EC! */ GNUNET_break_op (0); diff --git a/src/lib/exchange_api_purse_merge.c b/src/lib/exchange_api_purse_merge.c index 0812fdadf..4b65e97f1 100644 --- a/src/lib/exchange_api_purse_merge.c +++ b/src/lib/exchange_api_purse_merge.c @@ -29,6 +29,7 @@ #include "taler_json_lib.h" #include "taler_exchange_service.h" #include "exchange_api_handle.h" +#include "exchange_api_common.h" #include "taler_signatures.h" #include "exchange_api_curl_defaults.h" @@ -75,6 +76,11 @@ struct TALER_EXCHANGE_AccountMergeHandle */ char *provider_url; + /** + * Signature for our operation. + */ + struct TALER_PurseMergeSignatureP merge_sig; + /** * Expected value in the purse after fees. */ @@ -266,58 +272,25 @@ handle_purse_merge_finished (void *cls, break; case MHD_HTTP_CONFLICT: { - struct TALER_PurseMergeSignatureP merge_sig; - struct GNUNET_TIME_Timestamp merge_timestamp; - const char *partner_url = NULL; - struct TALER_ReservePublicKeyP reserve_pub; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ("reserve_pub", - &reserve_pub), - GNUNET_JSON_spec_fixed_auto ("merge_sig", - &merge_sig), - GNUNET_JSON_spec_timestamp ("merge_timestamp", - &merge_timestamp), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("partner_base_url", - &partner_url), - NULL), - GNUNET_JSON_spec_end () - }; struct TALER_PurseMergePublicKeyP merge_pub; - char *payto_uri; - 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; - } GNUNET_CRYPTO_eddsa_key_get_public (&pch->merge_priv.eddsa_priv, &merge_pub.eddsa_pub); - if (NULL == partner_url) - partner_url = pch->provider_url; - payto_uri = make_payto (partner_url, - &reserve_pub); + if (GNUNET_OK != - TALER_wallet_purse_merge_verify ( - payto_uri, - merge_timestamp, - &pch->purse_pub, + TALER_EXCHANGE_check_purse_merge_conflict_ ( + &pch->merge_sig, &merge_pub, - &merge_sig)) + &pch->purse_pub, + pch->provider_url, + j)) { GNUNET_break_op (0); dr.hr.http_status = 0; dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - GNUNET_free (payto_uri); break; } - GNUNET_free (payto_uri); - /* conflict is real */ + break; } break; case MHD_HTTP_GONE: @@ -370,7 +343,6 @@ TALER_EXCHANGE_account_merge ( struct GNUNET_CURL_Context *ctx; json_t *merge_obj; CURL *eh; - struct TALER_PurseMergeSignatureP merge_sig; char arg_str[sizeof (pch->purse_pub) * 2 + 32]; char *reserve_url; @@ -430,7 +402,7 @@ TALER_EXCHANGE_account_merge ( merge_timestamp, purse_pub, merge_priv, - &merge_sig); + &pch->merge_sig); { struct TALER_Amount zero_purse_fee; @@ -451,7 +423,7 @@ TALER_EXCHANGE_account_merge ( GNUNET_JSON_pack_string ("payto_uri", reserve_url), GNUNET_JSON_pack_data_auto ("merge_sig", - &merge_sig), + &pch->merge_sig), GNUNET_JSON_pack_data_auto ("reserve_sig", &pch->reserve_sig), GNUNET_JSON_pack_timestamp ("merge_timestamp",