diff options
Diffstat (limited to 'src/mint-lib/mint_api_deposit.c')
-rw-r--r-- | src/mint-lib/mint_api_deposit.c | 569 |
1 files changed, 0 insertions, 569 deletions
diff --git a/src/mint-lib/mint_api_deposit.c b/src/mint-lib/mint_api_deposit.c deleted file mode 100644 index 400372925..000000000 --- a/src/mint-lib/mint_api_deposit.c +++ /dev/null @@ -1,569 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. - - 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, If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file mint-lib/mint_api_deposit.c - * @brief Implementation of the /deposit request of the mint's HTTP API - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - * @author Christian Grothoff - */ -#include "platform.h" -#include <curl/curl.h> -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include "taler_mint_service.h" -#include "mint_api_common.h" -#include "mint_api_json.h" -#include "mint_api_context.h" -#include "mint_api_handle.h" -#include "taler_signatures.h" - - -/** - * @brief A Deposit Handle - */ -struct TALER_MINT_DepositHandle -{ - - /** - * The connection to mint this request handle will use - */ - struct TALER_MINT_Handle *mint; - - /** - * The url for this request. - */ - char *url; - - /** - * JSON encoding of the request to POST. - */ - char *json_enc; - - /** - * Handle for the request. - */ - struct MAC_Job *job; - - /** - * Function to call with the result. - */ - TALER_MINT_DepositResultCallback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * Download buffer - */ - struct MAC_DownloadBuffer db; - - /** - * Information the mint should sign in response. - */ - struct TALER_DepositConfirmationPS depconf; - - /** - * Value of the /deposit transaction, including fee. - */ - struct TALER_Amount amount_with_fee; - - /** - * Total value of the coin being transacted with. - */ - struct TALER_Amount coin_value; - -}; - - -/** - * Verify that the signature on the "200 OK" response - * from the mint is valid. - * - * @param dh deposit handle - * @param json json reply with the signature - * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not - */ -static int -verify_deposit_signature_ok (const struct TALER_MINT_DepositHandle *dh, - json_t *json) -{ - struct TALER_MintSignatureP mint_sig; - struct TALER_MintPublicKeyP mint_pub; - const struct TALER_MINT_Keys *key_state; - struct MAJ_Specification spec[] = { - MAJ_spec_fixed_auto ("sig", &mint_sig), - MAJ_spec_fixed_auto ("pub", &mint_pub), - MAJ_spec_end - }; - - if (GNUNET_OK != - MAJ_parse_json (json, - spec)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - key_state = TALER_MINT_get_keys (dh->mint); - if (GNUNET_OK != - TALER_MINT_test_signing_key (key_state, - &mint_pub)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MINT_CONFIRM_DEPOSIT, - &dh->depconf.purpose, - &mint_sig.eddsa_signature, - &mint_pub.eddsa_pub)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Verify that the signatures on the "403 FORBIDDEN" response from the - * mint demonstrating customer double-spending are valid. - * - * @param dh deposit handle - * @param json json reply with the signature(s) and transaction history - * @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not - */ -static int -verify_deposit_signature_forbidden (const struct TALER_MINT_DepositHandle *dh, - json_t *json) -{ - json_t *history; - struct TALER_Amount total; - - history = json_object_get (json, - "history"); - if (GNUNET_OK != - TALER_MINT_verify_coin_history_ (dh->coin_value.currency, - &dh->depconf.coin_pub, - history, - &total)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - TALER_amount_add (&total, - &total, - &dh->amount_with_fee)) - { - /* clearly not OK if our transaction would have caused - the overflow... */ - return GNUNET_OK; - } - - if (0 >= TALER_amount_cmp (&total, - &dh->coin_value)) - { - /* transaction should have still fit */ - GNUNET_break (0); - return GNUNET_SYSERR; - } - /* everything OK, proof of double-spending was provided */ - return GNUNET_OK; -} - - -/** - * Function called when we're done processing the - * HTTP /deposit request. - * - * @param cls the `struct TALER_MINT_DepositHandle` - * @param eh the curl request handle - */ -static void -handle_deposit_finished (void *cls, - CURL *eh) -{ - struct TALER_MINT_DepositHandle *dh = cls; - long response_code; - json_t *json; - - dh->job = NULL; - json = MAC_download_get_result (&dh->db, - eh, - &response_code); - switch (response_code) - { - case 0: - break; - case MHD_HTTP_OK: - if (GNUNET_OK != - verify_deposit_signature_ok (dh, - json)) - { - GNUNET_break_op (0); - response_code = 0; - } - break; - case MHD_HTTP_BAD_REQUEST: - /* This should never happen, either us or the mint is buggy - (or API version conflict); just pass JSON reply to the application */ - break; - case MHD_HTTP_FORBIDDEN: - /* Double spending; check signatures on transaction history */ - if (GNUNET_OK != - verify_deposit_signature_forbidden (dh, - json)) - { - GNUNET_break_op (0); - response_code = 0; - } - break; - case MHD_HTTP_UNAUTHORIZED: - /* Nothing really to verify, mint 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: - /* Nothing really to verify, this should never - happen, we should pass the JSON reply to the application */ - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - break; - default: - /* unexpected response code */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u\n", - response_code); - GNUNET_break (0); - response_code = 0; - break; - } - dh->cb (dh->cb_cls, - response_code, - json); - json_decref (json); - TALER_MINT_deposit_cancel (dh); -} - - -/** - * Verify signature information about the deposit. - * - * @param dki public key information - * @param amount the amount to be deposited - * @param h_wire hash of the merchant’s account details - * @param h_contract hash of the contact of the merchant with the customer (further details are never disclosed to the mint) - * @param coin_pub coin’s public key - * @param denom_pub denomination key with which the coin is signed - * @param denom_sig mint’s unblinded signature of the coin - * @param timestamp timestamp when the contract was finalized, must match approximately the current time of the mint - * @param transaction_id transaction id for the transaction between merchant and customer - * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests) - * @param refund_deadline date until which the merchant can issue a refund to the customer via the mint (can be zero if refunds are not allowed) - * @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s private key. - * @return #GNUNET_OK if signatures are OK, #GNUNET_SYSERR if not - */ -static int -verify_signatures (const struct TALER_MINT_DenomPublicKey *dki, - const struct TALER_Amount *amount, - const struct GNUNET_HashCode *h_wire, - const struct GNUNET_HashCode *h_contract, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_DenominationSignature *denom_sig, - const struct TALER_DenominationPublicKey *denom_pub, - struct GNUNET_TIME_Absolute timestamp, - uint64_t transaction_id, - const struct TALER_MerchantPublicKeyP *merchant_pub, - struct GNUNET_TIME_Absolute refund_deadline, - const struct TALER_CoinSpendSignatureP *coin_sig) -{ - struct TALER_DepositRequestPS dr; - struct TALER_CoinPublicInfo coin_info; - - dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT); - dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS)); - dr.h_contract = *h_contract; - dr.h_wire = *h_wire; - dr.timestamp = GNUNET_TIME_absolute_hton (timestamp); - dr.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline); - dr.transaction_id = GNUNET_htonll (transaction_id); - TALER_amount_hton (&dr.amount_with_fee, - amount); - TALER_amount_hton (&dr.deposit_fee, - &dki->fee_deposit); - dr.merchant = *merchant_pub; - dr.coin_pub = *coin_pub; - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT, - &dr.purpose, - &coin_sig->eddsa_signature, - &coin_pub->eddsa_pub)) - { - TALER_LOG_WARNING ("Invalid coin signature on /deposit request\n"); - { - char *s; - s = TALER_amount_to_string (amount); - TALER_LOG_DEBUG ("... amount_with_fee was %s\n", s); - GNUNET_free (s); - s = TALER_amount_to_string (&dki->fee_deposit); - TALER_LOG_DEBUG ("... deposit_fee was %s\n", s); - GNUNET_free (s); - } - - return GNUNET_SYSERR; - } - - /* check coin signature */ - coin_info.coin_pub = *coin_pub; - coin_info.denom_pub = *denom_pub; - coin_info.denom_sig = *denom_sig; - if (GNUNET_YES != - TALER_test_coin_valid (&coin_info)) - { - TALER_LOG_WARNING ("Invalid coin passed for /deposit\n"); - return GNUNET_SYSERR; - } - if (0 < TALER_amount_cmp (&dki->fee_deposit, - amount)) - { - TALER_LOG_WARNING ("Deposit amount smaller than fee\n"); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Submit a deposit permission to the mint and get the mint'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 (i.e. that signatures included in the response are all - * valid). If the mint's reply is not well-formed, we return an - * HTTP status code of zero to @a cb. - * - * We also verify that the @a coin_sig is valid for this deposit - * request, and that the @a ub_sig is a valid signature for @a - * coin_pub. Also, the @a mint must be ready to operate (i.e. have - * finished processing the /keys reply). If either check fails, we do - * NOT initiate the transaction with the mint and instead return NULL. - * - * @param mint the mint handle; the mint must be ready to operate - * @param amount the amount to be deposited - * @param wire_deadline date until which the merchant would like the mint to settle the balance (advisory, the mint cannot be - * forced to settle in the past or upon very short notice, but of course a well-behaved mint will limit aggregation based on the advice received) - * @param wire_details the merchant’s account details, in a format supported by the mint - * @param h_contract hash of the contact of the merchant with the customer (further details are never disclosed to the mint) - * @param coin_pub coin’s public key - * @param denom_pub denomination key with which the coin is signed - * @param denom_sig mint’s unblinded signature of the coin - * @param timestamp timestamp when the contract was finalized, must match approximately the current time of the mint - * @param transaction_id transaction id for the transaction between merchant and customer - * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests) - * @param refund_deadline date until which the merchant can issue a refund to the customer via the mint (can be zero if refunds are not allowed) - * @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s private key. - * @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_MINT_DepositHandle * -TALER_MINT_deposit (struct TALER_MINT_Handle *mint, - const struct TALER_Amount *amount, - struct GNUNET_TIME_Absolute wire_deadline, - json_t *wire_details, - const struct GNUNET_HashCode *h_contract, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct TALER_DenominationSignature *denom_sig, - const struct TALER_DenominationPublicKey *denom_pub, - struct GNUNET_TIME_Absolute timestamp, - uint64_t transaction_id, - const struct TALER_MerchantPublicKeyP *merchant_pub, - struct GNUNET_TIME_Absolute refund_deadline, - const struct TALER_CoinSpendSignatureP *coin_sig, - TALER_MINT_DepositResultCallback cb, - void *cb_cls) -{ - const struct TALER_MINT_Keys *key_state; - const struct TALER_MINT_DenomPublicKey *dki; - struct TALER_MINT_DepositHandle *dh; - struct TALER_MINT_Context *ctx; - json_t *deposit_obj; - CURL *eh; - struct GNUNET_HashCode h_wire; - struct TALER_Amount amount_without_fee; - - (void) TALER_round_abs_time (&wire_deadline); - if (GNUNET_YES != - MAH_handle_is_ready (mint)) - { - GNUNET_break (0); - return NULL; - } - /* initialize h_wire */ - if (GNUNET_OK != - TALER_hash_json (wire_details, - &h_wire)) - { - GNUNET_break (0); - return NULL; - } - key_state = TALER_MINT_get_keys (mint); - dki = TALER_MINT_get_denomination_key (key_state, - denom_pub); - if (NULL == dki) - { - TALER_LOG_WARNING ("Denomination key unknown to mint\n"); - return NULL; - } - if (GNUNET_SYSERR == - TALER_amount_subtract (&amount_without_fee, - amount, - &dki->fee_deposit)) - { - GNUNET_break (0); - return NULL; - } - - if (GNUNET_OK != - verify_signatures (dki, - amount, - &h_wire, - h_contract, - coin_pub, - denom_sig, - denom_pub, - timestamp, - transaction_id, - merchant_pub, - refund_deadline, - coin_sig)) - { - GNUNET_break_op (0); - return NULL; - } - - deposit_obj = json_pack ("{s:o, s:O," /* f/wire */ - " s:o, s:o," /* H_wire, H_contract */ - " s:o, s:o," /* coin_pub, denom_pub */ - " s:o, s:o," /* ub_sig, timestamp */ - " s:I, s:o," /* transaction id, merchant_pub */ - " s:o, s:o," /* refund_deadline, wire_deadline */ - " s:o}", /* coin_sig */ - "f", TALER_json_from_amount (amount), - "wire", wire_details, - "H_wire", TALER_json_from_data (&h_wire, - sizeof (h_wire)), - "H_contract", TALER_json_from_data (h_contract, - sizeof (struct GNUNET_HashCode)), - "coin_pub", TALER_json_from_data (coin_pub, - sizeof (*coin_pub)), - "denom_pub", TALER_json_from_rsa_public_key (denom_pub->rsa_public_key), - "ub_sig", TALER_json_from_rsa_signature (denom_sig->rsa_signature), - "timestamp", TALER_json_from_abs (timestamp), - "transaction_id", (json_int_t) transaction_id, - "merchant_pub", TALER_json_from_data (merchant_pub, - sizeof (*merchant_pub)), - "refund_deadline", TALER_json_from_abs (refund_deadline), - "edate", TALER_json_from_abs (wire_deadline), - "coin_sig", TALER_json_from_data (coin_sig, - sizeof (*coin_sig)) - ); - - dh = GNUNET_new (struct TALER_MINT_DepositHandle); - dh->mint = mint; - dh->cb = cb; - dh->cb_cls = cb_cls; - dh->url = MAH_path_to_url (mint, "/deposit"); - dh->depconf.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS)); - dh->depconf.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_DEPOSIT); - dh->depconf.h_contract = *h_contract; - dh->depconf.h_wire = h_wire; - dh->depconf.transaction_id = GNUNET_htonll (transaction_id); - dh->depconf.timestamp = GNUNET_TIME_absolute_hton (timestamp); - dh->depconf.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline); - TALER_amount_hton (&dh->depconf.amount_without_fee, - &amount_without_fee); - dh->depconf.coin_pub = *coin_pub; - dh->depconf.merchant = *merchant_pub; - dh->amount_with_fee = *amount; - dh->coin_value = dki->value; - - eh = curl_easy_init (); - GNUNET_assert (NULL != (dh->json_enc = - json_dumps (deposit_obj, - JSON_COMPACT))); - json_decref (deposit_obj); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "URL for deposit: `%s'\n", - dh->url); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_URL, - dh->url)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_POSTFIELDS, - dh->json_enc)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_POSTFIELDSIZE, - strlen (dh->json_enc))); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEFUNCTION, - &MAC_download_cb)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEDATA, - &dh->db)); - ctx = MAH_handle_to_context (mint); - dh->job = MAC_job_add (ctx, - eh, - GNUNET_YES, - &handle_deposit_finished, - dh); - return dh; -} - - -/** - * Cancel a deposit permission request. This function cannot be used - * on a request handle if a response is already served for it. - * - * @param deposit the deposit permission request handle - */ -void -TALER_MINT_deposit_cancel (struct TALER_MINT_DepositHandle *deposit) -{ - if (NULL != deposit->job) - { - MAC_job_cancel (deposit->job); - deposit->job = NULL; - } - GNUNET_free_non_null (deposit->db.buf); - GNUNET_free (deposit->url); - GNUNET_free (deposit->json_enc); - GNUNET_free (deposit); -} - - -/* end of mint_api_deposit.c */ |