diff options
Diffstat (limited to 'src/lib/exchange_api_purse_create_with_merge.c')
-rw-r--r-- | src/lib/exchange_api_purse_create_with_merge.c | 241 |
1 files changed, 166 insertions, 75 deletions
diff --git a/src/lib/exchange_api_purse_create_with_merge.c b/src/lib/exchange_api_purse_create_with_merge.c index 35d52b915..0c8878342 100644 --- a/src/lib/exchange_api_purse_create_with_merge.c +++ b/src/lib/exchange_api_purse_create_with_merge.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2022 Taler Systems SA + Copyright (C) 2022-2023 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 @@ -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" @@ -40,9 +41,9 @@ struct TALER_EXCHANGE_PurseCreateMergeHandle { /** - * The connection to exchange this request handle will use + * The keys of the exchange this request handle will use */ - struct TALER_EXCHANGE_Handle *exchange; + struct TALER_EXCHANGE_Keys *keys; /** * The url for this request. @@ -50,6 +51,11 @@ struct TALER_EXCHANGE_PurseCreateMergeHandle char *url; /** + * The exchange base URL. + */ + char *exchange_url; + + /** * Context for #TEH_curl_easy_post(). Keeps the data that must * persist for Curl to make the upload. */ @@ -71,6 +77,11 @@ struct TALER_EXCHANGE_PurseCreateMergeHandle void *cb_cls; /** + * The encrypted contract (if any). + */ + struct TALER_EncryptedContract econtract; + + /** * Expected value in the purse after fees. */ struct TALER_Amount purse_value_after_fees; @@ -81,11 +92,31 @@ struct TALER_EXCHANGE_PurseCreateMergeHandle struct TALER_ReservePublicKeyP reserve_pub; /** + * Reserve signature affirming our merge. + */ + struct TALER_ReserveSignatureP reserve_sig; + + /** + * Merge capability key. + */ + struct TALER_PurseMergePublicKeyP merge_pub; + + /** + * Our merge signature (if any). + */ + struct TALER_PurseMergeSignatureP merge_sig; + + /** * Public key of the purse. */ struct TALER_PurseContractPublicKeyP purse_pub; /** + * Request data we signed over. + */ + struct TALER_PurseContractSignatureP purse_sig; + + /** * Hash over the purse's contrac terms. */ struct TALER_PrivateContractHashP h_contract_terms; @@ -119,7 +150,8 @@ handle_purse_create_with_merge_finished (void *cls, const json_t *j = response; struct TALER_EXCHANGE_PurseCreateMergeResponse dr = { .hr.reply = j, - .hr.http_status = (unsigned int) response_code + .hr.http_status = (unsigned int) response_code, + .reserve_sig = &pcm->reserve_sig }; pcm->job = NULL; @@ -130,13 +162,13 @@ handle_purse_create_with_merge_finished (void *cls, break; case MHD_HTTP_OK: { -#if FIXME - const struct TALER_EXCHANGE_Keys *key_state; struct GNUNET_TIME_Timestamp etime; struct TALER_Amount total_deposited; struct TALER_ExchangeSignatureP exchange_sig; struct TALER_ExchangePublicKeyP exchange_pub; struct GNUNET_JSON_Specification spec[] = { + TALER_JSON_spec_amount_any ("total_deposited", + &total_deposited), GNUNET_JSON_spec_fixed_auto ("exchange_sig", &exchange_sig), GNUNET_JSON_spec_fixed_auto ("exchange_pub", @@ -156,36 +188,31 @@ handle_purse_create_with_merge_finished (void *cls, dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } - key_state = TALER_EXCHANGE_get_keys (pcm->exchange); if (GNUNET_OK != - TALER_EXCHANGE_test_signing_key (key_state, + TALER_EXCHANGE_test_signing_key (pcm->keys, &exchange_pub)) { GNUNET_break_op (0); dr.hr.http_status = 0; - dr.hr.ec = - TALER_EC_EXCHANGE_PURSE_CREATE_WITH_MERGE_EXCHANGE_SIGNATURE_INVALID; + dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } if (GNUNET_OK != - TALER_exchange_online_purse_create_with_merged_verify ( + TALER_exchange_online_purse_created_verify ( etime, pcm->purse_expiration, &pcm->purse_value_after_fees, + &total_deposited, &pcm->purse_pub, &pcm->h_contract_terms, - &pcm->reserve_pub, - pcm->provider_url, &exchange_pub, &exchange_sig)) { GNUNET_break_op (0); dr.hr.http_status = 0; - dr.hr.ec = - TALER_EC_EXCHANGE_PURSE_CREATE_WITH_MERGE_EXCHANGE_SIGNATURE_INVALID; + dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } -#endif } break; case MHD_HTTP_BAD_REQUEST: @@ -208,7 +235,59 @@ handle_purse_create_with_merge_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_RESERVES_PURSE_CREATE_CONFLICTING_META_DATA: + if (GNUNET_OK != + TALER_EXCHANGE_check_purse_create_conflict_ ( + &pcm->purse_sig, + &pcm->purse_pub, + j)) + { + 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)) + { + 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)) + { + 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); + dr.hr.http_status = 0; + dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + break; + } /* end inner (EC) switch */ break; case MHD_HTTP_GONE: /* could happen if denomination was revoked */ @@ -218,6 +297,27 @@ handle_purse_create_with_merge_finished (void *cls, dr.hr.ec = TALER_JSON_get_error_code (j); dr.hr.hint = TALER_JSON_get_error_hint (j); break; + case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: + { + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_uint64 ( + "requirement_row", + &dr.details.unavailable_for_legal_reasons.requirement_row), + 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; + } + } + 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); @@ -243,7 +343,9 @@ handle_purse_create_with_merge_finished (void *cls, struct TALER_EXCHANGE_PurseCreateMergeHandle * TALER_EXCHANGE_purse_create_with_merge ( - struct TALER_EXCHANGE_Handle *exchange, + struct GNUNET_CURL_Context *ctx, + const char *url, + struct TALER_EXCHANGE_Keys *keys, const struct TALER_ReservePrivateKeyP *reserve_priv, const struct TALER_PurseContractPrivateKeyP *purse_priv, const struct TALER_PurseMergePrivateKeyP *merge_priv, @@ -256,24 +358,14 @@ TALER_EXCHANGE_purse_create_with_merge ( void *cb_cls) { struct TALER_EXCHANGE_PurseCreateMergeHandle *pcm; - struct GNUNET_CURL_Context *ctx; json_t *create_with_merge_obj; CURL *eh; - struct TALER_ReserveSignatureP reserve_sig; char arg_str[sizeof (pcm->reserve_pub) * 2 + 32]; uint32_t min_age = 0; - struct TALER_PurseMergePublicKeyP merge_pub; - struct TALER_PurseMergeSignatureP merge_sig; - struct TALER_ContractDiffiePublicP contract_pub; - struct TALER_PurseContractSignatureP contract_sig; - struct TALER_PurseContractSignatureP purse_sig; - void *econtract = NULL; - size_t econtract_size = 0; struct TALER_Amount purse_fee; enum TALER_WalletAccountMergeFlags flags; pcm = GNUNET_new (struct TALER_EXCHANGE_PurseCreateMergeHandle); - pcm->exchange = exchange; pcm->cb = cb; pcm->cb_cls = cb_cls; if (GNUNET_OK != @@ -284,16 +376,13 @@ TALER_EXCHANGE_purse_create_with_merge ( GNUNET_free (pcm); return NULL; } - pcm->h_contract_terms = pcm->h_contract_terms; pcm->merge_timestamp = merge_timestamp; GNUNET_CRYPTO_eddsa_key_get_public (&purse_priv->eddsa_priv, &pcm->purse_pub.eddsa_pub); GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv, &pcm->reserve_pub.eddsa_pub); GNUNET_CRYPTO_eddsa_key_get_public (&merge_priv->eddsa_priv, - &merge_pub.eddsa_pub); - GNUNET_CRYPTO_ecdhe_key_get_public (&contract_priv->ecdhe_priv, - &contract_pub.ecdhe_pub); + &pcm->merge_pub.eddsa_pub); { struct GNUNET_JSON_Specification spec[] = { @@ -323,20 +412,19 @@ TALER_EXCHANGE_purse_create_with_merge ( const struct TALER_EXCHANGE_GlobalFee *gf; gf = TALER_EXCHANGE_get_global_fee ( - TALER_EXCHANGE_get_keys (exchange), + keys, GNUNET_TIME_timestamp_get ()); purse_fee = gf->fees.purse; flags = TALER_WAMF_MODE_CREATE_WITH_PURSE_FEE; } else { - TALER_amount_set_zero (pcm->purse_value_after_fees.currency, - &purse_fee); + GNUNET_assert (GNUNET_OK == + TALER_amount_set_zero (pcm->purse_value_after_fees.currency, + &purse_fee)); flags = TALER_WAMF_MODE_CREATE_FROM_PURSE_QUOTA; } - GNUNET_assert (GNUNET_YES == - TEAH_handle_is_ready (exchange)); { char pub_str[sizeof (pcm->reserve_pub) * 2]; char *end; @@ -349,11 +437,12 @@ TALER_EXCHANGE_purse_create_with_merge ( *end = '\0'; GNUNET_snprintf (arg_str, sizeof (arg_str), - "/reserves/%s/purse", + "reserves/%s/purse", pub_str); } - pcm->url = TEAH_path_to_url (exchange, - arg_str); + pcm->url = TALER_url_join (url, + arg_str, + NULL); if (NULL == pcm->url) { GNUNET_break (0); @@ -362,16 +451,23 @@ TALER_EXCHANGE_purse_create_with_merge ( } TALER_wallet_purse_create_sign (pcm->purse_expiration, &pcm->h_contract_terms, - &merge_pub, + &pcm->merge_pub, min_age, &pcm->purse_value_after_fees, purse_priv, - &purse_sig); - TALER_wallet_purse_merge_sign (exchange->url, - merge_timestamp, - &pcm->purse_pub, - merge_priv, - &merge_sig); + &pcm->purse_sig); + { + char *payto_uri; + + payto_uri = TALER_reserve_make_payto (url, + &pcm->reserve_pub); + TALER_wallet_purse_merge_sign (payto_uri, + merge_timestamp, + &pcm->purse_pub, + merge_priv, + &pcm->merge_sig); + GNUNET_free (payto_uri); + } TALER_wallet_account_merge_sign (merge_timestamp, &pcm->purse_pub, pcm->purse_expiration, @@ -381,21 +477,23 @@ TALER_EXCHANGE_purse_create_with_merge ( min_age, flags, reserve_priv, - &reserve_sig); + &pcm->reserve_sig); if (upload_contract) { TALER_CRYPTO_contract_encrypt_for_deposit ( &pcm->purse_pub, contract_priv, contract_terms, - &econtract, - &econtract_size); + &pcm->econtract.econtract, + &pcm->econtract.econtract_size); + GNUNET_CRYPTO_ecdhe_key_get_public (&contract_priv->ecdhe_priv, + &pcm->econtract.contract_pub.ecdhe_pub); TALER_wallet_econtract_upload_sign ( - econtract, - econtract_size, - &contract_pub, + pcm->econtract.econtract, + pcm->econtract.econtract_size, + &pcm->econtract.contract_pub, purse_priv, - &contract_sig); + &pcm->econtract.econtract_sig); } create_with_merge_obj = GNUNET_JSON_PACK ( TALER_JSON_pack_amount ("purse_value", @@ -403,21 +501,10 @@ TALER_EXCHANGE_purse_create_with_merge ( GNUNET_JSON_pack_uint64 ("min_age", min_age), GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_data_varsize ("econtract", - econtract, - econtract_size)), - GNUNET_JSON_pack_allow_null ( - upload_contract - ? GNUNET_JSON_pack_data_auto ("econtract_sig", - &contract_sig) - : GNUNET_JSON_pack_string ("dummy", - NULL)), - GNUNET_JSON_pack_allow_null ( - upload_contract - ? GNUNET_JSON_pack_data_auto ("contract_pub", - &contract_pub) - : GNUNET_JSON_pack_string ("dummy", - NULL)), + TALER_JSON_pack_econtract ("econtract", + upload_contract + ? &pcm->econtract + : NULL)), GNUNET_JSON_pack_allow_null ( pay_for_purse ? TALER_JSON_pack_amount ("purse_fee", @@ -425,15 +512,15 @@ TALER_EXCHANGE_purse_create_with_merge ( : GNUNET_JSON_pack_string ("dummy2", NULL)), GNUNET_JSON_pack_data_auto ("merge_pub", - &merge_pub), + &pcm->merge_pub), GNUNET_JSON_pack_data_auto ("merge_sig", - &merge_sig), + &pcm->merge_sig), GNUNET_JSON_pack_data_auto ("reserve_sig", - &reserve_sig), + &pcm->reserve_sig), GNUNET_JSON_pack_data_auto ("purse_pub", &pcm->purse_pub), GNUNET_JSON_pack_data_auto ("purse_sig", - &purse_sig), + &pcm->purse_sig), GNUNET_JSON_pack_data_auto ("h_contract_terms", &pcm->h_contract_terms), GNUNET_JSON_pack_timestamp ("merge_timestamp", @@ -441,7 +528,6 @@ TALER_EXCHANGE_purse_create_with_merge ( GNUNET_JSON_pack_timestamp ("purse_expiration", pcm->purse_expiration)); GNUNET_assert (NULL != create_with_merge_obj); - GNUNET_free (econtract); eh = TALER_EXCHANGE_curl_easy_get_ (pcm->url); if ( (NULL == eh) || (GNUNET_OK != @@ -453,6 +539,7 @@ TALER_EXCHANGE_purse_create_with_merge ( if (NULL != eh) curl_easy_cleanup (eh); json_decref (create_with_merge_obj); + GNUNET_free (pcm->econtract.econtract); GNUNET_free (pcm->url); GNUNET_free (pcm); return NULL; @@ -461,7 +548,8 @@ TALER_EXCHANGE_purse_create_with_merge ( GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "URL for purse create_with_merge: `%s'\n", pcm->url); - ctx = TEAH_handle_to_context (exchange); + pcm->keys = TALER_EXCHANGE_keys_incref (keys); + pcm->exchange_url = GNUNET_strdup (url); pcm->job = GNUNET_CURL_job_add2 (ctx, eh, pcm->ctx.headers, @@ -481,7 +569,10 @@ TALER_EXCHANGE_purse_create_with_merge_cancel ( pcm->job = NULL; } GNUNET_free (pcm->url); + GNUNET_free (pcm->exchange_url); TALER_curl_easy_post_finished (&pcm->ctx); + TALER_EXCHANGE_keys_decref (pcm->keys); + GNUNET_free (pcm->econtract.econtract); GNUNET_free (pcm); } |