diff options
Diffstat (limited to 'src/lib/auditor_api_deposit_confirmation.c')
-rw-r--r-- | src/lib/auditor_api_deposit_confirmation.c | 294 |
1 files changed, 146 insertions, 148 deletions
diff --git a/src/lib/auditor_api_deposit_confirmation.c b/src/lib/auditor_api_deposit_confirmation.c index 9c13c3f0f..172a12ece 100644 --- a/src/lib/auditor_api_deposit_confirmation.c +++ b/src/lib/auditor_api_deposit_confirmation.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2021 Taler Systems SA + Copyright (C) 2014-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 @@ -25,9 +25,10 @@ #include <gnunet/gnunet_util_lib.h> #include <gnunet/gnunet_json_lib.h> #include <gnunet/gnunet_curl_lib.h> +#include "taler_util.h" +#include "taler_curl_lib.h" #include "taler_json_lib.h" #include "taler_auditor_service.h" -#include "auditor_api_handle.h" #include "taler_signatures.h" #include "auditor_api_curl_defaults.h" @@ -39,11 +40,6 @@ struct TALER_AUDITOR_DepositConfirmationHandle { /** - * The connection to auditor this request handle will use - */ - struct TALER_AUDITOR_Handle *auditor; - - /** * The url for this request. */ char *url; @@ -87,64 +83,64 @@ handle_deposit_confirmation_finished (void *cls, { const json_t *json = djson; struct TALER_AUDITOR_DepositConfirmationHandle *dh = cls; - struct TALER_AUDITOR_HttpResponse hr = { - .reply = json, - .http_status = (unsigned int) response_code + struct TALER_AUDITOR_DepositConfirmationResponse dcr = { + .hr.reply = json, + .hr.http_status = (unsigned int) response_code }; dh->job = NULL; switch (response_code) { case 0: - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + dcr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; break; case MHD_HTTP_OK: - hr.ec = TALER_EC_NONE; + dcr.hr.ec = TALER_EC_NONE; break; case MHD_HTTP_BAD_REQUEST: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + dcr.hr.ec = TALER_JSON_get_error_code (json); + dcr.hr.hint = TALER_JSON_get_error_hint (json); /* This should never happen, either us or the auditor is buggy (or API version conflict); just pass JSON reply to the application */ break; case MHD_HTTP_FORBIDDEN: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + dcr.hr.ec = TALER_JSON_get_error_code (json); + dcr.hr.hint = TALER_JSON_get_error_hint (json); /* Nothing really to verify, auditor 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: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + dcr.hr.ec = TALER_JSON_get_error_code (json); + dcr.hr.hint = TALER_JSON_get_error_hint (json); /* Nothing really to verify, this should never happen, we should pass the JSON reply to the application */ break; case MHD_HTTP_GONE: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + dcr.hr.ec = TALER_JSON_get_error_code (json); + dcr.hr.hint = TALER_JSON_get_error_hint (json); /* Nothing really to verify, auditor 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_INTERNAL_SERVER_ERROR: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + dcr.hr.ec = TALER_JSON_get_error_code (json); + dcr.hr.hint = TALER_JSON_get_error_hint (json); /* Server had an internal issue; we should retry, but this API leaves this to the application */ break; default: /* unexpected response code */ - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + dcr.hr.ec = TALER_JSON_get_error_code (json); + dcr.hr.hint = TALER_JSON_get_error_hint (json); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for auditor deposit confirmation\n", (unsigned int) response_code, - hr.ec); + dcr.hr.ec); break; } dh->cb (dh->cb_cls, - &hr); + &dcr); TALER_AUDITOR_deposit_confirmation_cancel (dh); } @@ -153,11 +149,14 @@ handle_deposit_confirmation_finished (void *cls, * Verify signature information about the deposit-confirmation. * * @param h_wire hash of merchant wire details + * @param h_policy hash over the policy extension, if any * @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the auditor) * @param exchange_timestamp timestamp when the deposit was received by the wallet + * @param wire_deadline by what time must the amount be wired to the merchant * @param refund_deadline date until which the merchant can issue a refund to the customer via the auditor (can be zero if refunds are not allowed); must not be after the @a wire_deadline * @param amount_without_fee the amount confirmed to be wired by the exchange to the merchant - * @param coin_pub coin’s public key + * @param num_coins number of coins involved + * @param coin_sigs array of @a num_coins coin signatures * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests) * @param exchange_sig the signature made with purpose #TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT * @param exchange_pub the public key of the exchange that matches @a exchange_sig @@ -168,52 +167,52 @@ handle_deposit_confirmation_finished (void *cls, * @param master_sig master signature affirming validity of @a exchange_pub * @return #GNUNET_OK if signatures are OK, #GNUNET_SYSERR if not */ -static int -verify_signatures (const struct GNUNET_HashCode *h_wire, - const struct GNUNET_HashCode *h_contract_terms, - struct GNUNET_TIME_Absolute exchange_timestamp, - struct GNUNET_TIME_Absolute refund_deadline, - const struct TALER_Amount *amount_without_fee, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_MerchantPublicKeyP *merchant_pub, - const struct TALER_ExchangePublicKeyP *exchange_pub, - const struct TALER_ExchangeSignatureP *exchange_sig, - const struct TALER_MasterPublicKeyP *master_pub, - struct GNUNET_TIME_Absolute ep_start, - struct GNUNET_TIME_Absolute ep_expire, - struct GNUNET_TIME_Absolute ep_end, - const struct TALER_MasterSignatureP *master_sig) +static enum GNUNET_GenericReturnValue +verify_signatures ( + const struct TALER_MerchantWireHashP *h_wire, + const struct TALER_ExtensionPolicyHashP *h_policy, + const struct TALER_PrivateContractHashP *h_contract_terms, + struct GNUNET_TIME_Timestamp exchange_timestamp, + struct GNUNET_TIME_Timestamp wire_deadline, + struct GNUNET_TIME_Timestamp refund_deadline, + const struct TALER_Amount *amount_without_fee, + unsigned int num_coins, + const struct TALER_CoinSpendSignatureP *coin_sigs[ + static num_coins], + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct TALER_ExchangePublicKeyP *exchange_pub, + const struct TALER_ExchangeSignatureP *exchange_sig, + const struct TALER_MasterPublicKeyP *master_pub, + struct GNUNET_TIME_Timestamp ep_start, + struct GNUNET_TIME_Timestamp ep_expire, + struct GNUNET_TIME_Timestamp ep_end, + const struct TALER_MasterSignatureP *master_sig) { + if (GNUNET_OK != + TALER_exchange_online_deposit_confirmation_verify ( + h_contract_terms, + h_wire, + h_policy, + exchange_timestamp, + wire_deadline, + refund_deadline, + amount_without_fee, + num_coins, + coin_sigs, + merchant_pub, + exchange_pub, + exchange_sig)) { - struct TALER_DepositConfirmationPS dc = { - .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT), - .purpose.size = htonl (sizeof (dc)), - .h_contract_terms = *h_contract_terms, - .h_wire = *h_wire, - .exchange_timestamp = GNUNET_TIME_absolute_hton (exchange_timestamp), - .refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline), - .coin_pub = *coin_pub, - .merchant = *merchant_pub - }; - - TALER_amount_hton (&dc.amount_without_fee, - amount_without_fee); - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT, - &dc, - &exchange_sig->eddsa_signature, - &exchange_pub->eddsa_pub)) + GNUNET_break_op (0); + TALER_LOG_WARNING ( + "Invalid signature on /deposit-confirmation request!\n"); { - GNUNET_break_op (0); - TALER_LOG_WARNING ( - "Invalid signature on /deposit-confirmation request!\n"); - { - TALER_LOG_DEBUG ("... amount_without_fee was %s\n", - TALER_amount2s (amount_without_fee)); - } - return GNUNET_SYSERR; + TALER_LOG_DEBUG ("... amount_without_fee was %s\n", + TALER_amount2s (amount_without_fee)); } + return GNUNET_SYSERR; } + if (GNUNET_OK != TALER_exchange_offline_signkey_validity_verify ( exchange_pub, @@ -227,7 +226,7 @@ verify_signatures (const struct GNUNET_HashCode *h_wire, TALER_LOG_WARNING ("Invalid signature on exchange signing key!\n"); return GNUNET_SYSERR; } - if (GNUNET_TIME_absolute_is_past (ep_end)) + if (GNUNET_TIME_absolute_is_past (ep_end.abs_time)) { GNUNET_break (0); TALER_LOG_WARNING ("Exchange signing key is no longer valid!\n"); @@ -237,78 +236,54 @@ verify_signatures (const struct GNUNET_HashCode *h_wire, } -/** - * Submit a deposit-confirmation permission to the auditor and get the - * auditor's response. Note that while we return the response - * verbatim to the caller for further processing, we do already verify - * that the response is well-formed. If the auditor's reply is not - * well-formed, we return an HTTP status code of zero to @a cb. - * - * We also verify that the @a exchange_sig is valid for this deposit-confirmation - * request, and that the @a master_sig is a valid signature for @a - * exchange_pub. Also, the @a auditor must be ready to operate (i.e. have - * finished processing the /version reply). If either check fails, we do - * NOT initiate the transaction with the auditor and instead return NULL. - * - * @param auditor the auditor handle; the auditor must be ready to operate - * @param h_wire hash of merchant wire details - * @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the auditor) - * @param exchange_timestamp timestamp when deposit was received by the exchange - * @param refund_deadline date until which the merchant can issue a refund to the customer via the auditor (can be zero if refunds are not allowed); must not be after the @a wire_deadline - * @param amount_without_fee the amount confirmed to be wired by the exchange to the merchant - * @param coin_pub coin’s public key - * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests) - * @param exchange_sig the signature made with purpose #TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT - * @param exchange_pub the public key of the exchange that matches @a exchange_sig - * @param master_pub master public key of the exchange - * @param ep_start when does @a exchange_pub validity start - * @param ep_expire when does @a exchange_pub usage end - * @param ep_end when does @a exchange_pub legal validity end - * @param master_sig master signature affirming validity of @a exchange_pub - * @param cb the callback to call when a reply for this request is available - * @param cb_cls closure for the above callback - * @return a handle for this request; NULL if the inputs are invalid (i.e. - * signatures fail to verify). In this case, the callback is not called. - */ struct TALER_AUDITOR_DepositConfirmationHandle * TALER_AUDITOR_deposit_confirmation ( - struct TALER_AUDITOR_Handle *auditor, - const struct GNUNET_HashCode *h_wire, - const struct GNUNET_HashCode *h_contract_terms, - struct GNUNET_TIME_Absolute exchange_timestamp, - struct GNUNET_TIME_Absolute refund_deadline, - const struct TALER_Amount *amount_without_fee, - const struct TALER_CoinSpendPublicKeyP *coin_pub, + struct GNUNET_CURL_Context *ctx, + const char *url, + const struct TALER_MerchantWireHashP *h_wire, + const struct TALER_ExtensionPolicyHashP *h_policy, + const struct TALER_PrivateContractHashP *h_contract_terms, + struct GNUNET_TIME_Timestamp exchange_timestamp, + struct GNUNET_TIME_Timestamp wire_deadline, + struct GNUNET_TIME_Timestamp refund_deadline, + const struct TALER_Amount *total_without_fee, + unsigned int num_coins, + const struct TALER_CoinSpendPublicKeyP *coin_pubs[ + static num_coins], + const struct TALER_CoinSpendSignatureP *coin_sigs[ + static num_coins], const struct TALER_MerchantPublicKeyP *merchant_pub, const struct TALER_ExchangePublicKeyP *exchange_pub, const struct TALER_ExchangeSignatureP *exchange_sig, const struct TALER_MasterPublicKeyP *master_pub, - struct GNUNET_TIME_Absolute ep_start, - struct GNUNET_TIME_Absolute ep_expire, - struct GNUNET_TIME_Absolute ep_end, + struct GNUNET_TIME_Timestamp ep_start, + struct GNUNET_TIME_Timestamp ep_expire, + struct GNUNET_TIME_Timestamp ep_end, const struct TALER_MasterSignatureP *master_sig, TALER_AUDITOR_DepositConfirmationResultCallback cb, void *cb_cls) { struct TALER_AUDITOR_DepositConfirmationHandle *dh; - struct GNUNET_CURL_Context *ctx; json_t *deposit_confirmation_obj; CURL *eh; + json_t *jcoin_sigs; + json_t *jcoin_pubs; - (void) GNUNET_TIME_round_abs (&exchange_timestamp); - (void) GNUNET_TIME_round_abs (&refund_deadline); - (void) GNUNET_TIME_round_abs (&ep_start); - (void) GNUNET_TIME_round_abs (&ep_expire); - (void) GNUNET_TIME_round_abs (&ep_end); - GNUNET_assert (GNUNET_YES == - TALER_AUDITOR_handle_is_ready_ (auditor)); + if (0 == num_coins) + { + GNUNET_break (0); + return NULL; + } if (GNUNET_OK != verify_signatures (h_wire, + h_policy, h_contract_terms, exchange_timestamp, + wire_deadline, refund_deadline, - amount_without_fee, - coin_pub, + total_without_fee, + num_coins, + coin_sigs, merchant_pub, exchange_pub, exchange_sig, @@ -321,50 +296,70 @@ TALER_AUDITOR_deposit_confirmation ( GNUNET_break_op (0); return NULL; } - + jcoin_sigs = json_array (); + GNUNET_assert (NULL != jcoin_sigs); + jcoin_pubs = json_array (); + GNUNET_assert (NULL != jcoin_pubs); + for (unsigned int i = 0; i<num_coins; i++) + { + GNUNET_assert (0 == + json_array_append_new (jcoin_sigs, + GNUNET_JSON_from_data_auto ( + coin_sigs[i]))); + GNUNET_assert (0 == + json_array_append_new (jcoin_pubs, + GNUNET_JSON_from_data_auto ( + coin_pubs[i]))); + } deposit_confirmation_obj = GNUNET_JSON_PACK ( GNUNET_JSON_pack_data_auto ("h_wire", h_wire), + GNUNET_JSON_pack_data_auto ("h_policy", + h_policy), GNUNET_JSON_pack_data_auto ("h_contract_terms", h_contract_terms), - GNUNET_JSON_pack_time_abs ("exchange_timestamp", - exchange_timestamp), - GNUNET_JSON_pack_time_abs ("refund_deadline", - refund_deadline), - TALER_JSON_pack_amount ("amount_without_fee", - amount_without_fee), - GNUNET_JSON_pack_data_auto ("coin_pub", - coin_pub), + GNUNET_JSON_pack_timestamp ("exchange_timestamp", + exchange_timestamp), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_timestamp ("refund_deadline", + refund_deadline)), + GNUNET_JSON_pack_timestamp ("wire_deadline", + wire_deadline), + TALER_JSON_pack_amount ("total_without_fee", + total_without_fee), + GNUNET_JSON_pack_array_steal ("coin_pubs", + jcoin_pubs), + GNUNET_JSON_pack_array_steal ("coin_sigs", + jcoin_sigs), GNUNET_JSON_pack_data_auto ("merchant_pub", merchant_pub), GNUNET_JSON_pack_data_auto ("exchange_sig", exchange_sig), GNUNET_JSON_pack_data_auto ("master_pub", master_pub), - GNUNET_JSON_pack_time_abs ("ep_start", - ep_start), - GNUNET_JSON_pack_time_abs ("ep_expire", - ep_expire), - GNUNET_JSON_pack_time_abs ("ep_end", - ep_end), + GNUNET_JSON_pack_timestamp ("ep_start", + ep_start), + GNUNET_JSON_pack_timestamp ("ep_expire", + ep_expire), + GNUNET_JSON_pack_timestamp ("ep_end", + ep_end), GNUNET_JSON_pack_data_auto ("master_sig", master_sig), GNUNET_JSON_pack_data_auto ("exchange_pub", exchange_pub)); dh = GNUNET_new (struct TALER_AUDITOR_DepositConfirmationHandle); - dh->auditor = auditor; dh->cb = cb; dh->cb_cls = cb_cls; - dh->url = TALER_AUDITOR_path_to_url_ (auditor, - "/deposit-confirmation"); + dh->url = TALER_url_join (url, + "deposit-confirmation", + NULL); if (NULL == dh->url) { GNUNET_free (dh); return NULL; } eh = TALER_AUDITOR_curl_easy_get_ (dh->url); - if ( (NULL == eh) || (CURLE_OK != curl_easy_setopt (eh, @@ -387,22 +382,25 @@ TALER_AUDITOR_deposit_confirmation ( GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "URL for deposit-confirmation: `%s'\n", dh->url); - ctx = TALER_AUDITOR_handle_to_context_ (auditor); dh->job = GNUNET_CURL_job_add2 (ctx, eh, dh->ctx.headers, &handle_deposit_confirmation_finished, dh); + { + /* Disable 100 continue processing */ + struct curl_slist *x_headers; + + x_headers = curl_slist_append (NULL, + "Expect:"); + GNUNET_CURL_extend_headers (dh->job, + x_headers); + curl_slist_free_all (x_headers); + } return dh; } -/** - * Cancel a deposit-confirmation permission request. This function cannot be used - * on a request handle if a response is already served for it. - * - * @param deposit_confirmation the deposit-confirmation permission request handle - */ void TALER_AUDITOR_deposit_confirmation_cancel ( struct TALER_AUDITOR_DepositConfirmationHandle *deposit_confirmation) |