diff options
author | Marcello Stanisci <marcello.stanisci@inria.fr> | 2015-08-11 15:41:26 +0200 |
---|---|---|
committer | Marcello Stanisci <marcello.stanisci@inria.fr> | 2015-08-11 15:41:26 +0200 |
commit | a4845fb67d4c58a2fe17d6f82f005dbaa0c93b87 (patch) | |
tree | 6b0575abf4c030da05175249282afef429b30cdd | |
parent | abe5971f7398bda68c0e2757ccb8cdbe23d081e5 (diff) | |
download | merchant-a4845fb67d4c58a2fe17d6f82f005dbaa0c93b87.tar.gz merchant-a4845fb67d4c58a2fe17d6f82f005dbaa0c93b87.tar.bz2 merchant-a4845fb67d4c58a2fe17d6f82f005dbaa0c93b87.zip |
first massive refinement
-rw-r--r-- | src/backend/Makefile.am | 13 | ||||
-rw-r--r-- | src/backend/taler-merchant-dbinit.c | 79 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd.c | 43 | ||||
-rw-r--r-- | src/backend/taler-mint-httpd_admin.c | 163 | ||||
-rw-r--r-- | src/backend/taler-mint-httpd_admin.h | 46 | ||||
-rw-r--r-- | src/backend/taler-mint-httpd_db.c | 1444 | ||||
-rw-r--r-- | src/backend/taler-mint-httpd_db.h | 190 | ||||
-rw-r--r-- | src/backend/taler-mint-httpd_deposit.c | 270 | ||||
-rw-r--r-- | src/backend/taler-mint-httpd_deposit.h | 54 | ||||
-rw-r--r-- | src/backend/taler-mint-httpd_keystate.c | 867 | ||||
-rw-r--r-- | src/backend/taler-mint-httpd_keystate.h | 142 | ||||
-rw-r--r-- | src/backend/taler-mint-httpd_mhd.c | 152 | ||||
-rw-r--r-- | src/backend/taler-mint-httpd_mhd.h | 111 | ||||
-rw-r--r-- | src/backend/taler-mint-httpd_parsing.c | 880 | ||||
-rw-r--r-- | src/backend/taler-mint-httpd_refresh.c | 907 | ||||
-rw-r--r-- | src/backend/taler-mint-httpd_refresh.h | 94 | ||||
-rw-r--r-- | src/backend/taler-mint-httpd_responses.c | 829 | ||||
-rw-r--r-- | src/backend/taler-mint-httpd_withdraw.c | 180 | ||||
-rw-r--r-- | src/backend/taler-mint-httpd_withdraw.h | 73 |
19 files changed, 4 insertions, 6533 deletions
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index 9744a2dd..7c100040 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -8,20 +8,13 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd.c \ merchant.c merchant.h \ merchant_db.c merchant_db.h \ - taler-mint-httpd_keystate.c taler-mint-httpd_keystate.h \ - taler-mint-httpd_db.c taler-mint-httpd_db.h \ taler-mint-httpd_parsing.c taler-mint-httpd_parsing.h \ - taler-mint-httpd_responses.c taler-mint-httpd_responses.h \ - taler-mint-httpd_mhd.c taler-mint-httpd_mhd.h \ - taler-mint-httpd_admin.c taler-mint-httpd_admin.h \ - taler-mint-httpd_deposit.c taler-mint-httpd_deposit.h \ - taler-mint-httpd_withdraw.c taler-mint-httpd_withdraw.h \ - taler-mint-httpd_refresh.c taler-mint-httpd_refresh.h + taler-mint-httpd_responses.c taler-mint-httpd_responses.h taler_merchant_httpd_LDADD = \ $(LIBGCRYPT_LIBS) \ - /home/marcello/trans_mint/src/util/libtalerutil.la \ - /home/marcello/trans_mint/src/mintdb/libtalermintdb.la \ + /home/marcello/Taler/trans_mint/src/util/libtalerutil.la \ + /home/marcello/Taler/trans_mint/src/mintdb/libtalermintdb.la \ -lmicrohttpd \ -ljansson \ -lgnunetutil \ diff --git a/src/backend/taler-merchant-dbinit.c b/src/backend/taler-merchant-dbinit.c deleted file mode 100644 index 07731b47..00000000 --- a/src/backend/taler-merchant-dbinit.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - This file is part of TALER - (C) 2014 Christian Grothoff (and other contributing authors) - - 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 merchant/taler_merchant_dbinit.c - * @brief Program to initialise merchant database - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - */ - -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include "merchant_db.h" - - -/** - * Global execution result - */ -static int result; - - -/** - * Main function that will be run by the scheduler. - * - * @param cls closure - * @param args remaining command-line arguments - * @param cfgfile name of the configuration file used (for saving, can be NULL!) - * @param config configuration - */ -static void -run (void *cls, char *const *args, const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *config) -{ - PGconn *conn; - - conn = MERCHANT_DB_connect (config); - if (NULL == conn) - return; - if (GNUNET_OK == MERCHANT_DB_initialize (conn, GNUNET_NO)) - result = GNUNET_OK; - MERCHANT_DB_disconnect (conn); -} - - -/** - * The main function - * - * @param argc number of arguments from the command line - * @param argv command line arguments - * @return 0 ok, 1 on error - */ -int -main (int argc, char *const *argv) -{ - static const struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_OPTION_END - }; - - result = GNUNET_SYSERR; - if (GNUNET_OK != - GNUNET_PROGRAM_run (argc, argv, "taler-merchant-dbinit", - gettext_noop - ("Initialise Taler Merchant's database"), - options, &run, NULL)) - return 3; - return (GNUNET_OK == result) ? 0 : 1; -} diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c index 9ac225b5..9c431c2b 100644 --- a/src/backend/taler-merchant-httpd.c +++ b/src/backend/taler-merchant-httpd.c @@ -27,12 +27,6 @@ #include <taler/taler_json_lib.h> #include <taler/taler_mint_service.h> #include "taler-mint-httpd_parsing.h" -#include "taler-mint-httpd_mhd.h" -#include "taler-mint-httpd_admin.h" -#include "taler-mint-httpd_deposit.h" -#include "taler-mint-httpd_withdraw.h" -#include "taler-mint-httpd_refresh.h" -#include "taler-mint-httpd_keystate.h" #include "taler-mint-httpd_responses.h" #include "merchant.h" #include "merchant_db.h" @@ -79,45 +73,10 @@ static struct MHD_Daemon *mhd; PGconn *db_conn; /** - * Which currency is used by this mint? - * (verbatim copy from mint's code, just to make this - * merchant's source compile) - */ -char *TMH_mint_currency_string; - -/* As above */ -struct TALER_MINTDB_Plugin *TMH_plugin; - - -/** - * As above, though the merchant does need some form of - * configuration + * merchant's conf handle */ struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * As above - */ -int TMH_test_mode; - - -/** - * As above - */ -char *TMH_mint_directory; - - -/** - * As above - */ -struct GNUNET_CRYPTO_EddsaPublicKey TMH_master_public_key; - -/** - * As above - */ -char *TMH_expected_wire_format; - /** * Shutdown task identifier */ diff --git a/src/backend/taler-mint-httpd_admin.c b/src/backend/taler-mint-httpd_admin.c deleted file mode 100644 index 5fdfa58e..00000000 --- a/src/backend/taler-mint-httpd_admin.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero 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 Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_admin.c - * @brief Handle /admin/ requests - * @author Christian Grothoff - */ -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include "taler-mint-httpd_admin.h" -#include "taler-mint-httpd_parsing.h" -#include "taler-mint-httpd_responses.h" - - -/** - * Check permissions (we only allow access to /admin/ from loopback). - * - * @param connection connection to perform access check for - * @return #GNUNET_OK if permitted, - * #GNUNET_NO if denied and error was queued, - * #GNUNET_SYSERR if denied and we failed to report - */ -static int -check_permissions (struct MHD_Connection *connection) -{ - const union MHD_ConnectionInfo *ci; - const struct sockaddr *addr; - int res; - - ci = MHD_get_connection_info (connection, - MHD_CONNECTION_INFO_CLIENT_ADDRESS); - if (NULL == ci) - { - GNUNET_break (0); - res = TMH_RESPONSE_reply_internal_error (connection, - "Failed to verify client address"); - return (MHD_YES == res) ? GNUNET_NO : GNUNET_SYSERR; - } - addr = ci->client_addr; - switch (addr->sa_family) - { - case AF_INET: - { - const struct sockaddr_in *sin = (const struct sockaddr_in *) addr; - - if (INADDR_LOOPBACK != ntohl (sin->sin_addr.s_addr)) - { - res = TMH_RESPONSE_reply_permission_denied (connection, - "/admin/ only allowed via loopback"); - return (MHD_YES == res) ? GNUNET_NO : GNUNET_SYSERR; - } - break; - } - case AF_INET6: - { - const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *) addr; - - if (! IN6_IS_ADDR_LOOPBACK (&sin6->sin6_addr)) - { - res = TMH_RESPONSE_reply_permission_denied (connection, - "/admin/ only allowed via loopback"); - return (MHD_YES == res) ? GNUNET_NO : GNUNET_SYSERR; - } - break; - } - default: - GNUNET_break (0); - res = TMH_RESPONSE_reply_internal_error (connection, - "Unsupported AF"); - return (MHD_YES == res) ? GNUNET_NO : GNUNET_SYSERR; - } - return GNUNET_OK; -} - - - -/** - * Handle a "/admin/add/incoming" request. Parses the - * given "reserve_pub", "amount", "transaction" and "h_wire" - * details and adds the respective transaction to the database. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_ADMIN_handler_admin_add_incoming (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - struct TALER_ReservePublicKeyP reserve_pub; - struct TALER_Amount amount; - struct GNUNET_TIME_Absolute at; - json_t *wire; - json_t *root; - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_fixed ("reserve_pub", &reserve_pub), - TMH_PARSE_member_amount ("amount", &amount), - TMH_PARSE_member_time_abs ("execution_date", &at), - TMH_PARSE_member_object ("wire", &wire), - TMH_PARSE_MEMBER_END - }; - int res; - - res = check_permissions (connection); - if (GNUNET_OK != res) - return (GNUNET_NO == res) ? MHD_YES : MHD_NO; - res = TMH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &root); - if (GNUNET_SYSERR == res) - return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == root) ) - return MHD_YES; - res = TMH_PARSE_json_data (connection, - root, - spec); - if (GNUNET_OK != res) - { - json_decref (root); - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - } - if (GNUNET_YES != - TALER_json_validate_wireformat (TMH_expected_wire_format, - wire)) - { - TMH_PARSE_release_data (spec); - json_decref (root); - return TMH_RESPONSE_reply_arg_unknown (connection, - "wire"); - } - res = TMH_DB_execute_admin_add_incoming (connection, - &reserve_pub, - &amount, - at, - wire); - TMH_PARSE_release_data (spec); - json_decref (root); - return res; -} - -/* end of taler-mint-httpd_admin.c */ diff --git a/src/backend/taler-mint-httpd_admin.h b/src/backend/taler-mint-httpd_admin.h deleted file mode 100644 index b8ca3ce5..00000000 --- a/src/backend/taler-mint-httpd_admin.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero 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 Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_admin.h - * @brief Handle /admin/ requests - * @author Christian Grothoff - */ -#ifndef TALER_MINT_HTTPD_ADMIN_H -#define TALER_MINT_HTTPD_ADMIN_H - -#include <microhttpd.h> -#include "taler-mint-httpd.h" - -/** - * Handle a "/admin/add/incoming" request. Parses the - * given "reserve_pub", "amount", "transaction" and "h_wire" - * details and adds the respective transaction to the database. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_ADMIN_handler_admin_add_incoming (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - -#endif diff --git a/src/backend/taler-mint-httpd_db.c b/src/backend/taler-mint-httpd_db.c deleted file mode 100644 index 4e91e7e7..00000000 --- a/src/backend/taler-mint-httpd_db.c +++ /dev/null @@ -1,1444 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors) - - 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 taler-mint-httpd_db.c - * @brief High-level (transactional-layer) database operations for the mint. - * @author Christian Grothoff - */ -#include "platform.h" -#include <pthread.h> -#include <jansson.h> -#include "taler-mint-httpd_responses.h" -#include "taler-mint-httpd_keystate.h" - - -/** - * Calculate the total value of all transactions performed. - * Stores @a off plus the cost of all transactions in @a tl - * in @a ret. - * - * @param tl transaction list to process - * @param off offset to use as the starting value - * @param ret where the resulting total is to be stored - * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors - */ -static int -calculate_transaction_list_totals (struct TALER_MINTDB_TransactionList *tl, - const struct TALER_Amount *off, - struct TALER_Amount *ret) -{ - struct TALER_Amount spent = *off; - struct TALER_MINTDB_TransactionList *pos; - - for (pos = tl; NULL != pos; pos = pos->next) - { - switch (pos->type) - { - case TALER_MINTDB_TT_DEPOSIT: - if (GNUNET_OK != - TALER_amount_add (&spent, - &spent, - &pos->details.deposit->amount_with_fee)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - break; - case TALER_MINTDB_TT_REFRESH_MELT: - if (GNUNET_OK != - TALER_amount_add (&spent, - &spent, - &pos->details.melt->amount_with_fee)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - break; - case TALER_MINTDB_TT_LOCK: - /* should check if lock is still active, - and if it is for THIS operation; if - lock is inactive, delete it; if lock - is for THIS operation, ignore it; - if lock is for another operation, - count it! */ - GNUNET_assert (0); // FIXME: not implemented! (#3625) - return GNUNET_SYSERR; - } - } - *ret = spent; - return GNUNET_OK; -} - - -/** - * Execute a deposit. The validity of the coin and signature - * have already been checked. The database must now check that - * the coin is not (double or over) spent, and execute the - * transaction (record details, generate success or failure response). - * - * @param connection the MHD connection to handle - * @param deposit information about the deposit - * @return MHD result code - */ -int -TMH_DB_execute_deposit (struct MHD_Connection *connection, - const struct TALER_MINTDB_Deposit *deposit) -{ - struct TALER_MINTDB_Session *session; - struct TALER_MINTDB_TransactionList *tl; - struct TALER_Amount spent; - struct TALER_Amount value; - struct TALER_Amount amount_without_fee; - struct TMH_KS_StateHandle *mks; - struct TALER_MINTDB_DenominationKeyIssueInformation *dki; - int ret; - - if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, - TMH_test_mode))) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - if (GNUNET_YES == - TMH_plugin->have_deposit (TMH_plugin->cls, - session, - deposit)) - { - GNUNET_assert (GNUNET_OK == - TALER_amount_subtract (&amount_without_fee, - &deposit->amount_with_fee, - &deposit->deposit_fee)); - return TMH_RESPONSE_reply_deposit_success (connection, - &deposit->coin.coin_pub, - &deposit->h_wire, - &deposit->h_contract, - deposit->transaction_id, - deposit->timestamp, - deposit->refund_deadline, - &deposit->merchant_pub, - &amount_without_fee); - } - mks = TMH_KS_acquire (); - dki = TMH_KS_denomination_key_lookup (mks, - &deposit->coin.denom_pub, - TMH_KS_DKU_DEPOSIT); - TALER_amount_ntoh (&value, - &dki->issue.properties.value); - TMH_KS_release (mks); - - if (GNUNET_OK != - TMH_plugin->start (TMH_plugin->cls, - session)) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - /* fee for THIS transaction */ - spent = deposit->amount_with_fee; - /* add cost of all previous transactions */ - tl = TMH_plugin->get_coin_transactions (TMH_plugin->cls, - session, - &deposit->coin.coin_pub); - if (GNUNET_OK != - calculate_transaction_list_totals (tl, - &spent, - &spent)) - { - TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, - tl); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - /* Check that cost of all transactions is smaller than - the value of the coin. */ - if (0 < TALER_amount_cmp (&spent, - &value)) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - ret = TMH_RESPONSE_reply_deposit_insufficient_funds (connection, - tl); - TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, - tl); - return ret; - } - TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, - tl); - - if (GNUNET_OK != - TMH_plugin->insert_deposit (TMH_plugin->cls, - session, - deposit)) - { - TALER_LOG_WARNING ("Failed to store /deposit information in database\n"); - TMH_plugin->rollback (TMH_plugin->cls, - session); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - - if (GNUNET_OK != - TMH_plugin->commit (TMH_plugin->cls, - session)) - { - TALER_LOG_WARNING ("/deposit transaction commit failed\n"); - return TMH_RESPONSE_reply_commit_error (connection); - } - GNUNET_assert (GNUNET_OK == - TALER_amount_subtract (&amount_without_fee, - &deposit->amount_with_fee, - &deposit->deposit_fee)); - return TMH_RESPONSE_reply_deposit_success (connection, - &deposit->coin.coin_pub, - &deposit->h_wire, - &deposit->h_contract, - deposit->transaction_id, - deposit->timestamp, - deposit->refund_deadline, - &deposit->merchant_pub, - &amount_without_fee); -} - - -/** - * Execute a /withdraw/status. Given the public key of a reserve, - * return the associated transaction history. - * - * @param connection the MHD connection to handle - * @param reserve_pub public key of the reserve to check - * @return MHD result code - */ -int -TMH_DB_execute_withdraw_status (struct MHD_Connection *connection, - const struct TALER_ReservePublicKeyP *reserve_pub) -{ - struct TALER_MINTDB_Session *session; - struct TALER_MINTDB_ReserveHistory *rh; - int res; - - if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, - TMH_test_mode))) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - rh = TMH_plugin->get_reserve_history (TMH_plugin->cls, - session, - reserve_pub); - if (NULL == rh) - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_NOT_FOUND, - "{s:s, s:s}", - "error", "Reserve not found", - "parameter", "withdraw_pub"); - res = TMH_RESPONSE_reply_withdraw_status_success (connection, - rh); - TMH_plugin->free_reserve_history (TMH_plugin->cls, - rh); - return res; -} - - -/** - * Execute a "/withdraw/sign". Given a reserve and a properly signed - * request to withdraw a coin, check the balance of the reserve and - * if it is sufficient, store the request and return the signed - * blinded envelope. - * - * @param connection the MHD connection to handle - * @param reserve public key of the reserve - * @param denomination_pub public key of the denomination requested - * @param blinded_msg blinded message to be signed - * @param blinded_msg_len number of bytes in @a blinded_msg - * @param signature signature over the withdraw request, to be stored in DB - * @return MHD result code - */ -int -TMH_DB_execute_withdraw_sign (struct MHD_Connection *connection, - const struct TALER_ReservePublicKeyP *reserve, - const struct TALER_DenominationPublicKey *denomination_pub, - const char *blinded_msg, - size_t blinded_msg_len, - const struct TALER_ReserveSignatureP *signature) -{ - struct TALER_MINTDB_Session *session; - struct TALER_MINTDB_ReserveHistory *rh; - const struct TALER_MINTDB_ReserveHistory *pos; - struct TMH_KS_StateHandle *key_state; - struct TALER_MINTDB_CollectableBlindcoin collectable; - struct TALER_MINTDB_DenominationKeyIssueInformation *dki; - struct TALER_MINTDB_DenominationKeyIssueInformation *tdki; - struct GNUNET_CRYPTO_rsa_Signature *sig; - struct TALER_Amount amount_required; - struct TALER_Amount deposit_total; - struct TALER_Amount withdraw_total; - struct TALER_Amount balance; - struct TALER_Amount value; - struct TALER_Amount fee_withdraw; - struct GNUNET_HashCode h_blind; - int res; - - GNUNET_CRYPTO_hash (blinded_msg, - blinded_msg_len, - &h_blind); - - if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, - TMH_test_mode))) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - res = TMH_plugin->get_withdraw_info (TMH_plugin->cls, - session, - &h_blind, - &collectable); - if (GNUNET_SYSERR == res) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - - /* Don't sign again if we have already signed the coin */ - if (GNUNET_YES == res) - { - res = TMH_RESPONSE_reply_withdraw_sign_success (connection, - &collectable); - GNUNET_CRYPTO_rsa_signature_free (collectable.sig.rsa_signature); - GNUNET_CRYPTO_rsa_public_key_free (collectable.denom_pub.rsa_public_key); - return res; - } - GNUNET_assert (GNUNET_NO == res); - - /* Check if balance is sufficient */ - key_state = TMH_KS_acquire (); - dki = TMH_KS_denomination_key_lookup (key_state, - denomination_pub, - TMH_KS_DKU_WITHDRAW); - if (NULL == dki) - { - TMH_KS_release (key_state); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_NOT_FOUND, - "{s:s}", - "error", - "Denomination not found"); - } - if (GNUNET_OK != - TMH_plugin->start (TMH_plugin->cls, - session)) - { - GNUNET_break (0); - TMH_KS_release (key_state); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - - rh = TMH_plugin->get_reserve_history (TMH_plugin->cls, - session, - reserve); - if (NULL == rh) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - TMH_KS_release (key_state); - return TMH_RESPONSE_reply_arg_unknown (connection, - "reserve_pub"); - } - - /* calculate amount required including fees */ - TALER_amount_ntoh (&value, - &dki->issue.properties.value); - TALER_amount_ntoh (&fee_withdraw, - &dki->issue.properties.fee_withdraw); - - if (GNUNET_OK != - TALER_amount_add (&amount_required, - &value, - &fee_withdraw)) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - TMH_KS_release (key_state); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - - /* calculate balance of the reserve */ - res = 0; - for (pos = rh; NULL != pos; pos = pos->next) - { - switch (pos->type) - { - case TALER_MINTDB_RO_BANK_TO_MINT: - if (0 == (res & 1)) - deposit_total = pos->details.bank->amount; - else - if (GNUNET_OK != - TALER_amount_add (&deposit_total, - &deposit_total, - &pos->details.bank->amount)) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - TMH_KS_release (key_state); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - res |= 1; - break; - case TALER_MINTDB_RO_WITHDRAW_COIN: - tdki = TMH_KS_denomination_key_lookup (key_state, - &pos->details.withdraw->denom_pub, - TMH_KS_DKU_WITHDRAW); - TALER_amount_ntoh (&value, - &tdki->issue.properties.value); - if (0 == (res & 2)) - withdraw_total = value; - else - if (GNUNET_OK != - TALER_amount_add (&withdraw_total, - &withdraw_total, - &value)) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - TMH_KS_release (key_state); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - res |= 2; - break; - } - } - if (0 == (res & 1)) - { - /* did not encounter any deposit operations, how can we have a reserve? */ - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - if (0 == (res & 2)) - { - /* did not encounter any withdraw operations, set to zero */ - TALER_amount_get_zero (deposit_total.currency, - &withdraw_total); - } - /* All reserve balances should be non-negative */ - GNUNET_assert (GNUNET_SYSERR != - TALER_amount_subtract (&balance, - &deposit_total, - &withdraw_total)); - if (0 < TALER_amount_cmp (&amount_required, - &balance)) - { - TMH_KS_release (key_state); - TMH_plugin->rollback (TMH_plugin->cls, - session); - res = TMH_RESPONSE_reply_withdraw_sign_insufficient_funds (connection, - rh); - TMH_plugin->free_reserve_history (TMH_plugin->cls, - rh); - return res; - } - TMH_plugin->free_reserve_history (TMH_plugin->cls, - rh); - - /* Balance is good, sign the coin! */ - sig = GNUNET_CRYPTO_rsa_sign (dki->denom_priv.rsa_private_key, - blinded_msg, - blinded_msg_len); - TMH_KS_release (key_state); - if (NULL == sig) - { - GNUNET_break (0); - TMH_plugin->rollback (TMH_plugin->cls, - session); - return TMH_RESPONSE_reply_internal_error (connection, - "Internal error"); - } - collectable.sig.rsa_signature = sig; - collectable.denom_pub = *denomination_pub; - collectable.amount_with_fee = amount_required; - collectable.withdraw_fee = fee_withdraw; - collectable.reserve_pub = *reserve; - collectable.h_coin_envelope = h_blind; - collectable.reserve_sig = *signature; - if (GNUNET_OK != - TMH_plugin->insert_withdraw_info (TMH_plugin->cls, - session, - &collectable)) - { - GNUNET_break (0); - GNUNET_CRYPTO_rsa_signature_free (sig); - TMH_plugin->rollback (TMH_plugin->cls, - session); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - if (GNUNET_OK != - TMH_plugin->commit (TMH_plugin->cls, - session)) - { - TALER_LOG_WARNING ("/withdraw/sign transaction commit failed\n"); - return TMH_RESPONSE_reply_commit_error (connection); - } - res = TMH_RESPONSE_reply_withdraw_sign_success (connection, - &collectable); - GNUNET_CRYPTO_rsa_signature_free (sig); - return res; -} - - -/** - * Parse coin melt requests from a JSON object and write them to - * the database. - * - * @param connection the connection to send errors to - * @param session the database connection - * @param key_state the mint's key state - * @param session_hash hash identifying the refresh session - * @param coin_details details about the coin being melted - * @param oldcoin_index what is the number assigned to this coin - * @return #GNUNET_OK on success, - * #GNUNET_NO if an error message was generated, - * #GNUNET_SYSERR on internal errors (no response generated) - */ -static int -refresh_accept_melts (struct MHD_Connection *connection, - struct TALER_MINTDB_Session *session, - const struct TMH_KS_StateHandle *key_state, - const struct GNUNET_HashCode *session_hash, - const struct TMH_DB_MeltDetails *coin_details, - uint16_t oldcoin_index) -{ - struct TALER_MINTDB_DenominationKeyInformationP *dki; - struct TALER_MINTDB_TransactionList *tl; - struct TALER_Amount coin_value; - struct TALER_Amount coin_residual; - struct TALER_Amount spent; - struct TALER_MINTDB_RefreshMelt melt; - int res; - - dki = &TMH_KS_denomination_key_lookup (key_state, - &coin_details->coin_info.denom_pub, - TMH_KS_DKU_DEPOSIT)->issue; - - if (NULL == dki) - return (MHD_YES == - TMH_RESPONSE_reply_arg_unknown (connection, - "denom_pub")) - ? GNUNET_NO : GNUNET_SYSERR; - - TALER_amount_ntoh (&coin_value, - &dki->properties.value); - /* fee for THIS transaction; the melt amount includes the fee! */ - spent = coin_details->melt_amount_with_fee; - /* add historic transaction costs of this coin */ - tl = TMH_plugin->get_coin_transactions (TMH_plugin->cls, - session, - &coin_details->coin_info.coin_pub); - if (GNUNET_OK != - calculate_transaction_list_totals (tl, - &spent, - &spent)) - { - GNUNET_break (0); - TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, - tl); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - /* Refuse to refresh when the coin's value is insufficient - for the cost of all transactions. */ - if (TALER_amount_cmp (&coin_value, - &spent) < 0) - { - GNUNET_assert (GNUNET_OK == - TALER_amount_subtract (&coin_residual, - &spent, - &coin_details->melt_amount_with_fee)); - res = (MHD_YES == - TMH_RESPONSE_reply_refresh_melt_insufficient_funds (connection, - &coin_details->coin_info.coin_pub, - coin_value, - tl, - coin_details->melt_amount_with_fee, - coin_residual)) - ? GNUNET_NO : GNUNET_SYSERR; - TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, - tl); - return res; - } - TMH_plugin->free_coin_transaction_list (TMH_plugin->cls, - tl); - - melt.coin = coin_details->coin_info; - melt.coin_sig = coin_details->melt_sig; - melt.session_hash = *session_hash; - melt.amount_with_fee = coin_details->melt_amount_with_fee; - if (GNUNET_OK != - TMH_plugin->insert_refresh_melt (TMH_plugin->cls, - session, - oldcoin_index, - &melt)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Execute a "/refresh/melt". We have been given a list of valid - * coins and a request to melt them into the given - * @a refresh_session_pub. Check that the coins all have the - * required value left and if so, store that they have been - * melted and confirm the melting operation to the client. - * - * @param connection the MHD connection to handle - * @param session_hash hash code of the session the coins are melted into - * @param num_new_denoms number of entries in @a denom_pubs, size of y-dimension of @a commit_coin array - * @param denom_pubs public keys of the coins we want to withdraw in the end - * @param coin_count number of entries in @a coin_melt_details, size of y-dimension of @a commit_link array - * @param coin_melt_details signatures and (residual) value of the respective coin should be melted - * @param commit_coin 2d array of coin commitments (what the mint is to sign - * once the "/refres/reveal" of cut and choose is done), - * x-dimension must be #TALER_CNC_KAPPA - * @param commit_link 2d array of coin link commitments (what the mint is - * to return via "/refresh/link" to enable linkage in the - * future) - * x-dimension must be #TALER_CNC_KAPPA - * @return MHD result code - */ -int -TMH_DB_execute_refresh_melt (struct MHD_Connection *connection, - const struct GNUNET_HashCode *session_hash, - unsigned int num_new_denoms, - const struct TALER_DenominationPublicKey *denom_pubs, - unsigned int coin_count, - const struct TMH_DB_MeltDetails *coin_melt_details, - struct TALER_MINTDB_RefreshCommitCoin *const* commit_coin, - struct TALER_MINTDB_RefreshCommitLinkP *const* commit_link) -{ - struct TMH_KS_StateHandle *key_state; - struct TALER_MINTDB_RefreshSession refresh_session; - struct TALER_MINTDB_Session *session; - int res; - unsigned int i; - - if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, - TMH_test_mode))) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - if (GNUNET_OK != - TMH_plugin->start (TMH_plugin->cls, - session)) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - res = TMH_plugin->get_refresh_session (TMH_plugin->cls, - session, - session_hash, - &refresh_session); - if (GNUNET_YES == res) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - res = TMH_RESPONSE_reply_refresh_melt_success (connection, - session_hash, - refresh_session.noreveal_index); - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - } - if (GNUNET_SYSERR == res) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - - /* store 'global' session data */ - refresh_session.num_oldcoins = coin_count; - refresh_session.num_newcoins = num_new_denoms; - refresh_session.noreveal_index - = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, - TALER_CNC_KAPPA); - if (GNUNET_OK != - (res = TMH_plugin->create_refresh_session (TMH_plugin->cls, - session, - session_hash, - &refresh_session))) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - - /* Melt old coins and check that they had enough residual value */ - key_state = TMH_KS_acquire (); - for (i=0;i<coin_count;i++) - { - if (GNUNET_OK != - (res = refresh_accept_melts (connection, - session, - key_state, - session_hash, - &coin_melt_details[i], - i))) - { - TMH_KS_release (key_state); - TMH_plugin->rollback (TMH_plugin->cls, - session); - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - } - } - TMH_KS_release (key_state); - - /* store requested new denominations */ - if (GNUNET_OK != - TMH_plugin->insert_refresh_order (TMH_plugin->cls, - session, - session_hash, - num_new_denoms, - denom_pubs)) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - - for (i = 0; i < TALER_CNC_KAPPA; i++) - { - if (GNUNET_OK != - TMH_plugin->insert_refresh_commit_coins (TMH_plugin->cls, - session, - session_hash, - i, - num_new_denoms, - commit_coin[i])) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - } - for (i = 0; i < TALER_CNC_KAPPA; i++) - { - if (GNUNET_OK != - TMH_plugin->insert_refresh_commit_links (TMH_plugin->cls, - session, - session_hash, - i, - coin_count, - commit_link[i])) - { - TMH_plugin->rollback (TMH_plugin->cls, - session); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - } - - if (GNUNET_OK != - TMH_plugin->commit (TMH_plugin->cls, - session)) - { - TALER_LOG_WARNING ("/refresh/melt transaction commit failed\n"); - return TMH_RESPONSE_reply_commit_error (connection); - } - return TMH_RESPONSE_reply_refresh_melt_success (connection, - session_hash, - refresh_session.noreveal_index); -} - - -/** - * Send an error response with the details of the original melt - * commitment and the location of the mismatch. - * - * @param connection the MHD connection to handle - * @param session database connection to use - * @param session_hash hash of session to query - * @param off commitment offset to check - * @param index index of the mismatch - * @param object_name name of the object with the problem - * @return #GNUNET_NO if we generated the error message - * #GNUNET_SYSERR if we could not even generate an error message - */ -static int -send_melt_commitment_error (struct MHD_Connection *connection, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - unsigned int off, - unsigned int index, - const char *object_name) -{ - struct TALER_MINTDB_MeltCommitment *mc; - int ret; - - mc = TMH_plugin->get_melt_commitment (TMH_plugin->cls, - session, - session_hash); - if (NULL == mc) - { - GNUNET_break (0); - return (MHD_YES == - TMH_RESPONSE_reply_internal_error (connection, - "Melt commitment assembly")) - ? GNUNET_NO : GNUNET_SYSERR; - } - ret = (MHD_YES == - TMH_RESPONSE_reply_refresh_reveal_missmatch (connection, - mc, - off, - index, - object_name)) - ? GNUNET_NO : GNUNET_SYSERR; - TMH_plugin->free_melt_commitment (TMH_plugin->cls, - mc); - return ret; -} - - -/** - * Check if the given @a transfer_privs correspond to an honest - * commitment for the given session. - * Checks that the transfer private keys match their commitments. - * Then derives the shared secret for each #TALER_CNC_KAPPA, and check that they match. - * - * @param connection the MHD connection to handle - * @param session database connection to use - * @param session_hash hash of session to query - * @param off commitment offset to check - * @param num_oldcoins size of the @a transfer_privs and @a melts arrays - * @param transfer_privs private transfer keys - * @param melts array of melted coins - * @param num_newcoins number of newcoins being generated - * @param denom_pubs array of @a num_newcoins keys for the new coins - * @return #GNUNET_OK if the committment was honest, - * #GNUNET_NO if there was a problem and we generated an error message - * #GNUNET_SYSERR if we could not even generate an error message - */ -static int -check_commitment (struct MHD_Connection *connection, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - unsigned int off, - unsigned int num_oldcoins, - const struct TALER_TransferPrivateKeyP *transfer_privs, - const struct TALER_MINTDB_RefreshMelt *melts, - unsigned int num_newcoins, - const struct TALER_DenominationPublicKey *denom_pubs) -{ - unsigned int j; - struct TALER_LinkSecretP last_shared_secret; - int secret_initialized = GNUNET_NO; - struct TALER_MINTDB_RefreshCommitLinkP *commit_links; - struct TALER_MINTDB_RefreshCommitCoin *commit_coins; - - commit_links = GNUNET_malloc (num_oldcoins * - sizeof (struct TALER_MINTDB_RefreshCommitLinkP)); - if (GNUNET_OK != - TMH_plugin->get_refresh_commit_links (TMH_plugin->cls, - session, - session_hash, - off, - num_oldcoins, - commit_links)) - { - GNUNET_break (0); - GNUNET_free (commit_links); - return (MHD_YES == TMH_RESPONSE_reply_internal_db_error (connection)) - ? GNUNET_NO : GNUNET_SYSERR; - } - - for (j = 0; j < num_oldcoins; j++) - { - struct TALER_LinkSecretP shared_secret; - struct TALER_TransferPublicKeyP transfer_pub_check; - - GNUNET_CRYPTO_ecdhe_key_get_public (&transfer_privs[j].ecdhe_priv, - &transfer_pub_check.ecdhe_pub); - if (0 != - memcmp (&transfer_pub_check, - &commit_links[j].transfer_pub, - sizeof (struct TALER_TransferPublicKeyP))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "transfer keys do not match\n"); - GNUNET_free (commit_links); - return send_melt_commitment_error (connection, - session, - session_hash, - off, - j, - "transfer key"); - } - - if (GNUNET_OK != - TALER_link_decrypt_secret (&commit_links[j].shared_secret_enc, - &transfer_privs[j], - &melts[j].coin.coin_pub, - &shared_secret)) - { - GNUNET_free (commit_links); - return (MHD_YES == - TMH_RESPONSE_reply_internal_error (connection, - "Transfer secret decryption error")) - ? GNUNET_NO : GNUNET_SYSERR; - } - if (GNUNET_NO == secret_initialized) - { - secret_initialized = GNUNET_YES; - last_shared_secret = shared_secret; - } - else if (0 != memcmp (&shared_secret, - &last_shared_secret, - sizeof (struct GNUNET_HashCode))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "shared secrets do not match\n"); - GNUNET_free (commit_links); - return send_melt_commitment_error (connection, - session, - session_hash, - off, - j, - "transfer secret"); - } - } - GNUNET_break (GNUNET_YES == secret_initialized); - GNUNET_free (commit_links); - - /* Check that the commitments for all new coins were correct */ - commit_coins = GNUNET_malloc (num_newcoins * - sizeof (struct TALER_MINTDB_RefreshCommitCoin)); - - if (GNUNET_OK != - TMH_plugin->get_refresh_commit_coins (TMH_plugin->cls, - session, - session_hash, - off, - num_newcoins, - commit_coins)) - { - GNUNET_break (0); - GNUNET_free (commit_coins); - return (MHD_YES == TMH_RESPONSE_reply_internal_db_error (connection)) - ? GNUNET_NO : GNUNET_SYSERR; - } - - for (j = 0; j < num_newcoins; j++) - { - struct TALER_RefreshLinkDecrypted *link_data; - struct TALER_CoinSpendPublicKeyP coin_pub; - struct GNUNET_HashCode h_msg; - char *buf; - size_t buf_len; - - link_data = TALER_refresh_decrypt (commit_coins[j].refresh_link, - &last_shared_secret); - if (NULL == link_data) - { - GNUNET_break (0); - GNUNET_free (commit_coins); - return (MHD_YES == TMH_RESPONSE_reply_internal_error (connection, - "Decryption error")) - ? GNUNET_NO : GNUNET_SYSERR; - } - - GNUNET_CRYPTO_eddsa_key_get_public (&link_data->coin_priv.eddsa_priv, - &coin_pub.eddsa_pub); - GNUNET_CRYPTO_hash (&coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP), - &h_msg); - if (0 == (buf_len = - GNUNET_CRYPTO_rsa_blind (&h_msg, - link_data->blinding_key.rsa_blinding_key, - denom_pubs[j].rsa_public_key, - &buf))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "blind failed\n"); - GNUNET_free (commit_coins); - return (MHD_YES == TMH_RESPONSE_reply_internal_error (connection, - "Blinding error")) - ? GNUNET_NO : GNUNET_SYSERR; - } - - if ( (buf_len != commit_coins[j].coin_ev_size) || - (0 != memcmp (buf, - commit_coins[j].coin_ev, - buf_len)) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "blind envelope does not match for k=%u, old=%d\n", - off, - (int) j); - GNUNET_free (commit_coins); - return send_melt_commitment_error (connection, - session, - session_hash, - off, - j, - "envelope"); - } - GNUNET_free (buf); - } - GNUNET_free (commit_coins); - - return GNUNET_OK; -} - - -/** - * Mint a coin as part of a refresh operation. Obtains the - * envelope from the database and performs the signing operation. - * - * @param connection the MHD connection to handle - * @param session database connection to use - * @param session_hash hash of session to query - * @param key_state key state to lookup denomination pubs - * @param denom_pub denomination key for the coin to create - * @param commit_coin the coin that was committed - * @param coin_off number of the coin - * @return NULL on error, otherwise signature over the coin - */ -static struct TALER_DenominationSignature -refresh_mint_coin (struct MHD_Connection *connection, - struct TALER_MINTDB_Session *session, - const struct GNUNET_HashCode *session_hash, - struct TMH_KS_StateHandle *key_state, - const struct TALER_DenominationPublicKey *denom_pub, - const struct TALER_MINTDB_RefreshCommitCoin *commit_coin, - unsigned int coin_off) -{ - struct TALER_MINTDB_DenominationKeyIssueInformation *dki; - struct TALER_DenominationSignature ev_sig; - - dki = TMH_KS_denomination_key_lookup (key_state, - denom_pub, - TMH_KS_DKU_WITHDRAW); - if (NULL == dki) - { - GNUNET_break (0); - ev_sig.rsa_signature = NULL; - return ev_sig; - } - ev_sig.rsa_signature - = GNUNET_CRYPTO_rsa_sign (dki->denom_priv.rsa_private_key, - commit_coin->coin_ev, - commit_coin->coin_ev_size); - if (NULL == ev_sig.rsa_signature) - { - GNUNET_break (0); - return ev_sig; - } - if (GNUNET_OK != - TMH_plugin->insert_refresh_out (TMH_plugin->cls, - session, - session_hash, - coin_off, - &ev_sig)) - { - GNUNET_break (0); - GNUNET_CRYPTO_rsa_signature_free (ev_sig.rsa_signature); - ev_sig.rsa_signature = NULL; - } - return ev_sig; -} - - -/** - * Execute a "/refresh/reveal". The client is revealing to us the - * transfer keys for @a #TALER_CNC_KAPPA-1 sets of coins. Verify that the - * revealed transfer keys would allow linkage to the blinded coins, - * and if so, return the signed coins for corresponding to the set of - * coins that was not chosen. - * - * @param connection the MHD connection to handle - * @param session_hash hash identifying the refresh session - * @param num_oldcoins size of y-dimension of @a transfer_privs array - * @param transfer_privs array with the revealed transfer keys, - * x-dimension must be #TALER_CNC_KAPPA - 1 - * @return MHD result code - */ -int -TMH_DB_execute_refresh_reveal (struct MHD_Connection *connection, - const struct GNUNET_HashCode *session_hash, - unsigned int num_oldcoins, - struct TALER_TransferPrivateKeyP **transfer_privs) -{ - int res; - struct TALER_MINTDB_Session *session; - struct TALER_MINTDB_RefreshSession refresh_session; - struct TMH_KS_StateHandle *key_state; - struct TALER_MINTDB_RefreshMelt *melts; - struct TALER_DenominationPublicKey *denom_pubs; - struct TALER_DenominationSignature *ev_sigs; - struct TALER_MINTDB_RefreshCommitCoin *commit_coins; - unsigned int i; - unsigned int j; - unsigned int off; - - if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, - TMH_test_mode))) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - - res = TMH_plugin->get_refresh_session (TMH_plugin->cls, - session, - session_hash, - &refresh_session); - if (GNUNET_NO == res) - return TMH_RESPONSE_reply_arg_invalid (connection, - "session_hash"); - if (GNUNET_SYSERR == res) - return TMH_RESPONSE_reply_internal_db_error (connection); - if (0 == refresh_session.num_oldcoins) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - - melts = GNUNET_malloc (refresh_session.num_oldcoins * - sizeof (struct TALER_MINTDB_RefreshMelt)); - for (j=0;j<refresh_session.num_oldcoins;j++) - { - if (GNUNET_OK != - TMH_plugin->get_refresh_melt (TMH_plugin->cls, - session, - session_hash, - j, - &melts[j])) - { - GNUNET_break (0); - GNUNET_free (melts); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - } - denom_pubs = GNUNET_malloc (refresh_session.num_newcoins * - sizeof (struct TALER_DenominationPublicKey)); - if (GNUNET_OK != - TMH_plugin->get_refresh_order (TMH_plugin->cls, - session, - session_hash, - refresh_session.num_newcoins, - denom_pubs)) - { - GNUNET_break (0); - GNUNET_free (denom_pubs); - GNUNET_free (melts); - return (MHD_YES == TMH_RESPONSE_reply_internal_db_error (connection)) - ? GNUNET_NO : GNUNET_SYSERR; - } - - - off = 0; - for (i=0;i<TALER_CNC_KAPPA - 1;i++) - { - if (i == refresh_session.noreveal_index) - off = 1; - if (GNUNET_OK != - (res = check_commitment (connection, - session, - session_hash, - i + off, - refresh_session.num_oldcoins, - transfer_privs[i + off], - melts, - refresh_session.num_newcoins, - denom_pubs))) - { - for (j=0;j<refresh_session.num_newcoins;j++) - GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); - GNUNET_free (denom_pubs); - GNUNET_free (melts); - return (GNUNET_NO == res) ? MHD_YES : MHD_NO; - } - } - GNUNET_free (melts); - - /* Client request OK, start transaction */ - if (GNUNET_OK != - TMH_plugin->start (TMH_plugin->cls, - session)) - { - GNUNET_break (0); - for (j=0;j<refresh_session.num_newcoins;j++) - GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); - GNUNET_free (denom_pubs); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - - commit_coins = GNUNET_malloc (refresh_session.num_newcoins * - sizeof (struct TALER_MINTDB_RefreshCommitCoin)); - if (GNUNET_OK != - TMH_plugin->get_refresh_commit_coins (TMH_plugin->cls, - session, - session_hash, - refresh_session.noreveal_index, - refresh_session.num_newcoins, - commit_coins)) - { - GNUNET_break (0); - GNUNET_free (commit_coins); - for (j=0;j<refresh_session.num_newcoins;j++) - GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); - GNUNET_free (denom_pubs); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - ev_sigs = GNUNET_malloc (refresh_session.num_newcoins * - sizeof (struct TALER_DenominationSignature)); - key_state = TMH_KS_acquire (); - for (j=0;j<refresh_session.num_newcoins;j++) - { - ev_sigs[j] = refresh_mint_coin (connection, - session, - session_hash, - key_state, - &denom_pubs[j], - &commit_coins[j], - j); - if (NULL == ev_sigs[j].rsa_signature) - { - TMH_KS_release (key_state); - for (i=0;i<j;i++) - GNUNET_CRYPTO_rsa_signature_free (ev_sigs[i].rsa_signature); - GNUNET_free (ev_sigs); - for (j=0;j<refresh_session.num_newcoins;j++) - GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); - GNUNET_free (denom_pubs); - GNUNET_free (commit_coins); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - } - TMH_KS_release (key_state); - for (j=0;j<refresh_session.num_newcoins;j++) - GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); - GNUNET_free (denom_pubs); - GNUNET_free (commit_coins); - - if (GNUNET_OK != - TMH_plugin->commit (TMH_plugin->cls, - session)) - { - TALER_LOG_WARNING ("/refresh/reveal transaction commit failed\n"); - for (i=0;i<refresh_session.num_newcoins;i++) - GNUNET_CRYPTO_rsa_signature_free (ev_sigs[i].rsa_signature); - GNUNET_free (ev_sigs); - return TMH_RESPONSE_reply_commit_error (connection); - } - - res = TMH_RESPONSE_reply_refresh_reveal_success (connection, - refresh_session.num_newcoins, - ev_sigs); - for (i=0;i<refresh_session.num_newcoins;i++) - GNUNET_CRYPTO_rsa_signature_free (ev_sigs[i].rsa_signature); - GNUNET_free (ev_sigs); - return res; -} - - -/** - * Closure for #handle_transfer_data(). - */ -struct HTD_Context -{ - - /** - * Session link data we collect. - */ - struct TMH_RESPONSE_LinkSessionInfo *sessions; - - /** - * Database session. Nothing to do with @a sessions. - */ - struct TALER_MINTDB_Session *session; - - /** - * MHD connection, for queueing replies. - */ - struct MHD_Connection *connection; - - /** - * Number of sessions the coin was melted into. - */ - unsigned int num_sessions; - - /** - * How are we expected to proceed. #GNUNET_SYSERR if we - * failed to return an error (should return #MHD_NO). - * #GNUNET_NO if we succeeded in queueing an MHD error - * (should return #MHD_YES from #TMH_execute_refresh_link), - * #GNUNET_OK if we should call #TMH_RESPONSE_reply_refresh_link_success(). - */ - int status; -}; - - -/** - * Function called with the session hashes and transfer secret - * information for a given coin. Gets the linkage data and - * builds the reply for the client. - * - * - * @param cls closure, a `struct HTD_Context` - * @param session_hash a session the coin was melted in - * @param transfer_pub public transfer key for the session - * @param shared_secret_enc set to shared secret for the session - */ -static void -handle_transfer_data (void *cls, - const struct GNUNET_HashCode *session_hash, - const struct TALER_TransferPublicKeyP *transfer_pub, - const struct TALER_EncryptedLinkSecretP *shared_secret_enc) -{ - struct HTD_Context *ctx = cls; - struct TALER_MINTDB_LinkDataList *ldl; - struct TMH_RESPONSE_LinkSessionInfo *lsi; - - if (GNUNET_OK != ctx->status) - return; - ldl = TMH_plugin->get_link_data_list (TMH_plugin->cls, - ctx->session, - session_hash); - if (NULL == ldl) - { - GNUNET_break (0); - ctx->status = GNUNET_NO; - if (MHD_NO == - TMH_RESPONSE_reply_json_pack (ctx->connection, - MHD_HTTP_NOT_FOUND, - "{s:s}", - "error", - "link data not found (link)")) - ctx->status = GNUNET_SYSERR; - return; - } - GNUNET_array_grow (ctx->sessions, - ctx->num_sessions, - ctx->num_sessions + 1); - lsi = &ctx->sessions[ctx->num_sessions - 1]; - lsi->transfer_pub = *transfer_pub; - lsi->shared_secret_enc = *shared_secret_enc; - lsi->ldl = ldl; -} - - -/** - * Execute a "/refresh/link". Returns the linkage information that - * will allow the owner of a coin to follow the refresh trail to - * the refreshed coin. - * - * @param connection the MHD connection to handle - * @param coin_pub public key of the coin to link - * @return MHD result code - */ -int -TMH_DB_execute_refresh_link (struct MHD_Connection *connection, - const struct TALER_CoinSpendPublicKeyP *coin_pub) -{ - struct HTD_Context ctx; - int res; - unsigned int i; - - if (NULL == (ctx.session = TMH_plugin->get_session (TMH_plugin->cls, - TMH_test_mode))) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - ctx.connection = connection; - ctx.num_sessions = 0; - ctx.sessions = NULL; - ctx.status = GNUNET_OK; - res = TMH_plugin->get_transfer (TMH_plugin->cls, - ctx.session, - coin_pub, - &handle_transfer_data, - &ctx); - if (GNUNET_SYSERR == ctx.status) - { - res = MHD_NO; - goto cleanup; - } - if (GNUNET_NO == ctx.status) - { - res = MHD_YES; - goto cleanup; - } - GNUNET_assert (GNUNET_OK == ctx.status); - if (0 == ctx.num_sessions) - return TMH_RESPONSE_reply_arg_unknown (connection, - "coin_pub"); - res = TMH_RESPONSE_reply_refresh_link_success (connection, - ctx.num_sessions, - ctx.sessions); - cleanup: - for (i=0;i<ctx.num_sessions;i++) - TMH_plugin->free_link_data_list (TMH_plugin->cls, - ctx.sessions[i].ldl); - GNUNET_free (ctx.sessions); - return res; -} - - -/** - * Add an incoming transaction to the database. Checks if the - * transaction is fresh (not a duplicate) and if so adds it to - * the database. - * - * @param connection the MHD connection to handle - * @param reserve_pub public key of the reserve - * @param amount amount to add to the reserve - * @param execution_time when did we receive the wire transfer - * @param wire details about the wire transfer - * @return MHD result code - */ -int -TMH_DB_execute_admin_add_incoming (struct MHD_Connection *connection, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *amount, - struct GNUNET_TIME_Absolute execution_time, - json_t *wire) -{ - struct TALER_MINTDB_Session *session; - int ret; - - if (NULL == (session = TMH_plugin->get_session (TMH_plugin->cls, - TMH_test_mode))) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - ret = TMH_plugin->reserves_in_insert (TMH_plugin->cls, - session, - reserve_pub, - amount, - execution_time, - wire); - if (GNUNET_SYSERR == ret) - { - GNUNET_break (0); - return TMH_RESPONSE_reply_internal_db_error (connection); - } - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:s}", - "status", - (GNUNET_OK == ret) - ? "NEW" - : "DUP"); -} - - -/* end of taler-mint-httpd_db.c */ diff --git a/src/backend/taler-mint-httpd_db.h b/src/backend/taler-mint-httpd_db.h deleted file mode 100644 index 8a171153..00000000 --- a/src/backend/taler-mint-httpd_db.h +++ /dev/null @@ -1,190 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015 Christian Grothoff (and other contributing authors) - - 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/taler-mint-httpd_db.h - * @brief High-level (transactional-layer) database operations for the mint - * @author Chrisitan Grothoff - */ -#ifndef TALER_MINT_HTTPD_DB_H -#define TALER_MINT_HTTPD_DB_H - -#include <microhttpd.h> -#include "taler_mintdb_plugin.h" - - -/** - * Execute a "/deposit". The validity of the coin and signature - * have already been checked. The database must now check that - * the coin is not (double or over) spent, and execute the - * transaction (record details, generate success or failure response). - * - * @param connection the MHD connection to handle - * @param deposit information about the deposit - * @return MHD result code - */ -int -TMH_DB_execute_deposit (struct MHD_Connection *connection, - const struct TALER_MINTDB_Deposit *deposit); - - -/** - * Execute a "/withdraw/status". Given the public key of a reserve, - * return the associated transaction history. - * - * @param connection the MHD connection to handle - * @param reserve_pub public key of the reserve to check - * @return MHD result code - */ -int -TMH_DB_execute_withdraw_status (struct MHD_Connection *connection, - const struct TALER_ReservePublicKeyP *reserve_pub); - - -/** - * Execute a "/withdraw/sign". Given a reserve and a properly signed - * request to withdraw a coin, check the balance of the reserve and - * if it is sufficient, store the request and return the signed - * blinded envelope. - * - * @param connection the MHD connection to handle - * @param reserve public key of the reserve - * @param denomination_pub public key of the denomination requested - * @param blinded_msg blinded message to be signed - * @param blinded_msg_len number of bytes in @a blinded_msg - * @param signature signature over the withdraw request, to be stored in DB - * @return MHD result code - */ -int -TMH_DB_execute_withdraw_sign (struct MHD_Connection *connection, - const struct TALER_ReservePublicKeyP *reserve, - const struct TALER_DenominationPublicKey *denomination_pub, - const char *blinded_msg, - size_t blinded_msg_len, - const struct TALER_ReserveSignatureP *signature); - - -/** - * @brief Details about a melt operation of an individual coin. - */ -struct TMH_DB_MeltDetails -{ - - /** - * Information about the coin being melted. - */ - struct TALER_CoinPublicInfo coin_info; - - /** - * Signature allowing the melt (using - * a `struct TALER_MINTDB_RefreshMeltConfirmSignRequestBody`) to sign over. - */ - struct TALER_CoinSpendSignatureP melt_sig; - - /** - * How much of the coin's value did the client allow to be melted? - * This amount includes the fees, so the final amount contributed - * to the melt is this value minus the fee for melting the coin. - */ - struct TALER_Amount melt_amount_with_fee; -}; - - -/** - * Execute a "/refresh/melt". We have been given a list of valid - * coins and a request to melt them into the given - * @a refresh_session_pub. Check that the coins all have the - * required value left and if so, store that they have been - * melted and confirm the melting operation to the client. - * - * @param connection the MHD connection to handle - * @param session_hash hash code of the session the coins are melted into - * @param num_new_denoms number of entries in @a denom_pubs, size of y-dimension of @a commit_coin array - * @param denom_pubs array of public denomination keys for the refresh (?) - * @param coin_count number of entries in @ a coin_melt_details, size of y-dimension of @a commit_link array - * @param coin_melt_details signatures and (residual) value of and information about the respective coin to be melted - * @param commit_coin 2d array of coin commitments (what the mint is to sign - * once the "/refres/reveal" of cut and choose is done) - * @param commit_link 2d array of coin link commitments (what the mint is - * to return via "/refresh/link" to enable linkage in the - * future) - * @return MHD result code - */ -int -TMH_DB_execute_refresh_melt (struct MHD_Connection *connection, - const struct GNUNET_HashCode *session_hash, - unsigned int num_new_denoms, - const struct TALER_DenominationPublicKey *denom_pubs, - unsigned int coin_count, - const struct TMH_DB_MeltDetails *coin_melt_details, - struct TALER_MINTDB_RefreshCommitCoin *const* commit_coin, - struct TALER_MINTDB_RefreshCommitLinkP *const* commit_link); - - -/** - * Execute a "/refresh/reveal". The client is revealing to us the - * transfer keys for #TALER_CNC_KAPPA-1 sets of coins. Verify that the - * revealed transfer keys would allow linkage to the blinded coins, - * and if so, return the signed coins for corresponding to the set of - * coins that was not chosen. - * - * @param connection the MHD connection to handle - * @param session_hash hash over the refresh session - * @param num_oldcoins size of y-dimension of @a transfer_privs array - * @param transfer_privs array with the revealed transfer keys, #TALER_CNC_KAPPA is 1st-dimension - * @return MHD result code - */ -int -TMH_DB_execute_refresh_reveal (struct MHD_Connection *connection, - const struct GNUNET_HashCode *session_hash, - unsigned int num_oldcoins, - struct TALER_TransferPrivateKeyP **transfer_privs); - - -/** - * Execute a "/refresh/link". Returns the linkage information that - * will allow the owner of a coin to follow the refresh trail to the - * refreshed coin. - * - * @param connection the MHD connection to handle - * @param coin_pub public key of the coin to link - * @return MHD result code - */ -int -TMH_DB_execute_refresh_link (struct MHD_Connection *connection, - const struct TALER_CoinSpendPublicKeyP *coin_pub); - - - -/** - * Add an incoming transaction to the database. - * - * @param connection the MHD connection to handle - * @param reserve_pub public key of the reserve - * @param amount amount to add to the reserve - * @param execution_time when did we receive the wire transfer - * @param wire details about the wire transfer - * @return MHD result code - */ -int -TMH_DB_execute_admin_add_incoming (struct MHD_Connection *connection, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_Amount *amount, - struct GNUNET_TIME_Absolute execution_time, - json_t *wire); - - -#endif -/* TALER_MINT_HTTPD_DB_H */ diff --git a/src/backend/taler-mint-httpd_deposit.c b/src/backend/taler-mint-httpd_deposit.c deleted file mode 100644 index 5725cd1c..00000000 --- a/src/backend/taler-mint-httpd_deposit.c +++ /dev/null @@ -1,270 +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 Affero 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 Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_deposit.c - * @brief Handle /deposit requests; parses the POST and JSON and - * verifies the coin signature before handing things off - * to the database. - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - * - * TODO: - * - ugly if-construction for deposit type - */ -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include <microhttpd.h> -#include <pthread.h> -#include "taler-mint-httpd_parsing.h" -#include "taler-mint-httpd_deposit.h" -#include "taler-mint-httpd_responses.h" -#include "taler-mint-httpd_keystate.h" - - -/** - * We have parsed the JSON information about the deposit, do some - * basic sanity checks (especially that the signature on the coin is - * valid, and that this type of coin exists) and then execute the - * deposit. - * - * @param connection the MHD connection to handle - * @param deposit information about the deposit - * @return MHD result code - */ -static int -verify_and_execute_deposit (struct MHD_Connection *connection, - const struct TALER_MINTDB_Deposit *deposit) -{ - struct TMH_KS_StateHandle *key_state; - struct TALER_DepositRequestPS dr; - struct TALER_MINTDB_DenominationKeyIssueInformation *dki; - struct TALER_Amount fee_deposit; - - dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT); - dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS)); - dr.h_contract = deposit->h_contract; - dr.h_wire = deposit->h_wire; - dr.timestamp = GNUNET_TIME_absolute_hton (deposit->timestamp); - dr.refund_deadline = GNUNET_TIME_absolute_hton (deposit->refund_deadline); - dr.transaction_id = GNUNET_htonll (deposit->transaction_id); - TALER_amount_hton (&dr.amount_with_fee, - &deposit->amount_with_fee); - TALER_amount_hton (&dr.deposit_fee, - &deposit->deposit_fee); - dr.merchant = deposit->merchant_pub; - dr.coin_pub = deposit->coin.coin_pub; - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT, - &dr.purpose, - &deposit->csig.eddsa_signature, - &deposit->coin.coin_pub.eddsa_pub)) - { - TALER_LOG_WARNING ("Invalid signature on /deposit request\n"); - return TMH_RESPONSE_reply_signature_invalid (connection, - "coin_sig"); - } - /* check denomination exists and is valid */ - key_state = TMH_KS_acquire (); - dki = TMH_KS_denomination_key_lookup (key_state, - &deposit->coin.denom_pub, - TMH_KS_DKU_DEPOSIT); - if (NULL == dki) - { - TMH_KS_release (key_state); - TALER_LOG_WARNING ("Unknown denomination key in /deposit request\n"); - return TMH_RESPONSE_reply_arg_unknown (connection, - "denom_pub"); - } - /* check coin signature */ - if (GNUNET_YES != - TALER_test_coin_valid (&deposit->coin)) - { - TALER_LOG_WARNING ("Invalid coin passed for /deposit\n"); - TMH_KS_release (key_state); - return TMH_RESPONSE_reply_signature_invalid (connection, - "ub_sig"); - } - TALER_amount_ntoh (&fee_deposit, - &dki->issue.properties.fee_deposit); - if (0 < TALER_amount_cmp (&fee_deposit, - &deposit->amount_with_fee)) - { - TMH_KS_release (key_state); - return TMH_RESPONSE_reply_external_error (connection, - "deposited amount smaller than depositing fee"); - } - TMH_KS_release (key_state); - - return TMH_DB_execute_deposit (connection, - deposit); -} - - -/** - * Handle a "/deposit" request. This function parses the - * JSON information and then calls #verify_and_execute_deposit() - * to verify the signatures and execute the deposit. - * - * @param connection the MHD connection to handle - * @param root root of the posted JSON - * @param amount how much should be deposited - * @param wire json describing the wire details (?) - * @return MHD result code - */ -static int -parse_and_handle_deposit_request (struct MHD_Connection *connection, - const json_t *root, - const struct TALER_Amount *amount, - json_t *wire) -{ - int res; - struct TALER_MINTDB_Deposit deposit; - struct TALER_MINTDB_DenominationKeyIssueInformation *dki; - struct TMH_KS_StateHandle *ks; - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_denomination_public_key ("denom_pub", &deposit.coin.denom_pub), - TMH_PARSE_member_denomination_signature ("ub_sig", &deposit.coin.denom_sig), - TMH_PARSE_member_fixed ("coin_pub", &deposit.coin.coin_pub), - TMH_PARSE_member_fixed ("merchant_pub", &deposit.merchant_pub), - TMH_PARSE_member_fixed ("H_contract", &deposit.h_contract), - TMH_PARSE_member_fixed ("H_wire", &deposit.h_wire), - TMH_PARSE_member_fixed ("coin_sig", &deposit.csig), - TMH_PARSE_member_uint64 ("transaction_id", &deposit.transaction_id), - TMH_PARSE_member_time_abs ("timestamp", &deposit.timestamp), - TMH_PARSE_member_time_abs ("refund_deadline", &deposit.refund_deadline), - TMH_PARSE_MEMBER_END - }; - - memset (&deposit, 0, sizeof (deposit)); - res = TMH_PARSE_json_data (connection, - root, - spec); - if (GNUNET_SYSERR == res) - return MHD_NO; /* hard failure */ - if (GNUNET_NO == res) - return MHD_YES; /* failure */ - - if (GNUNET_YES != - TALER_json_validate_wireformat (TMH_expected_wire_format, - wire)) - { - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_arg_unknown (connection, - "wire"); - } - if (GNUNET_OK != - TALER_hash_json (wire, - &deposit.h_wire)) - { - TALER_LOG_WARNING ("Failed to parse JSON wire format specification for /deposit request\n"); - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_arg_invalid (connection, - "wire"); - } - ks = TMH_KS_acquire (); - dki = TMH_KS_denomination_key_lookup (ks, - &deposit.coin.denom_pub, - TMH_KS_DKU_DEPOSIT); - if (NULL == dki) - { - TMH_KS_release (ks); - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_arg_unknown (connection, - "denom_pub"); - } - TALER_amount_ntoh (&deposit.deposit_fee, - &dki->issue.properties.fee_deposit); - TMH_KS_release (ks); - deposit.wire = wire; - deposit.amount_with_fee = *amount; - if (-1 == TALER_amount_cmp (&deposit.amount_with_fee, - &deposit.deposit_fee)) - { - /* Total amount smaller than fee, invalid */ - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_arg_invalid (connection, - "f"); - } - res = verify_and_execute_deposit (connection, - &deposit); - TMH_PARSE_release_data (spec); - return res; -} - - -/** - * Handle a "/deposit" request. Parses the JSON in the post to find - * the "type" (either DIRECT_DEPOSIT or INCREMENTAL_DEPOSIT), and, if - * successful, passes the JSON data to - * #parse_and_handle_deposit_request() to further check the details - * of the operation specified in the "wire" field of the JSON data. - * If everything checks out, this will ultimately lead to the - * "/deposit" being executed, or rejected. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_DEPOSIT_handler_deposit (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - json_t *json; - json_t *wire; - int res; - struct TALER_Amount amount; - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_object ("wire", &wire), - TMH_PARSE_member_amount ("f", &amount), - TMH_PARSE_MEMBER_END - }; - - res = TMH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); - if (GNUNET_SYSERR == res) - return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == json) ) - return MHD_YES; - res = TMH_PARSE_json_data (connection, - json, - spec); - if (GNUNET_OK != res) - { - json_decref (json); - return (GNUNET_NO == res) ? MHD_YES : MHD_NO; - } - res = parse_and_handle_deposit_request (connection, - json, - &amount, - wire); - TMH_PARSE_release_data (spec); - json_decref (json); - return res; -} - - -/* end of taler-mint-httpd_deposit.c */ diff --git a/src/backend/taler-mint-httpd_deposit.h b/src/backend/taler-mint-httpd_deposit.h deleted file mode 100644 index c2d3fe13..00000000 --- a/src/backend/taler-mint-httpd_deposit.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero 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 Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_deposit.h - * @brief Handle /deposit requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#ifndef TALER_MINT_HTTPD_DEPOSIT_H -#define TALER_MINT_HTTPD_DEPOSIT_H - -#include <gnunet/gnunet_util_lib.h> -#include <microhttpd.h> -#include "taler-mint-httpd.h" - - -/** - * Handle a "/deposit" request. Parses the JSON in the post to find - * the "type" (either DIRECT_DEPOSIT or INCREMENTAL_DEPOSIT), and, if - * successful, passes the JSON data to - * #parse_and_handle_deposit_request() to further check the details - * of the operation specified in the "wire" field of the JSON data. - * If everything checks out, this will ultimately lead to the - * "/deposit" being executed, or rejected. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_DEPOSIT_handler_deposit (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - -#endif diff --git a/src/backend/taler-mint-httpd_keystate.c b/src/backend/taler-mint-httpd_keystate.c deleted file mode 100644 index ec09ab44..00000000 --- a/src/backend/taler-mint-httpd_keystate.c +++ /dev/null @@ -1,867 +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 Affero 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 Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_keystate.c - * @brief management of our coin signing keys - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#include "platform.h" -#include <pthread.h> -#include "taler-mint-httpd_keystate.h" -#include "taler_mintdb_plugin.h" - - -/** - * Snapshot of the (coin and signing) keys (including private keys) of - * the mint. There can be multiple instances of this struct, as it is - * reference counted and only destroyed once the last user is done - * with it. The current instance is acquired using - * #TMH_KS_acquire(). Using this function increases the - * reference count. The contents of this structure (except for the - * reference counter) should be considered READ-ONLY until it is - * ultimately destroyed (as there can be many concurrent users). - */ -struct TMH_KS_StateHandle -{ - /** - * JSON array with denomination keys. (Currently not really used - * after initialization.) - */ - json_t *denom_keys_array; - - /** - * JSON array with signing keys. (Currently not really used - * after initialization.) - */ - json_t *sign_keys_array; - - /** - * Cached JSON text that the mint will send for a "/keys" request. - * Includes our @e TMH_master_public_key public key, the signing and - * denomination keys as well as the @e reload_time. - */ - char *keys_json; - - /** - * Mapping from denomination keys to denomination key issue struct. - * Used to lookup the key by hash. - */ - struct GNUNET_CONTAINER_MultiHashMap *denomkey_map; - - /** - * Hash context we used to combine the hashes of all denomination - * keys into one big hash. - */ - struct GNUNET_HashContext *hash_context; - - /** - * When did we initiate the key reloading? - */ - struct GNUNET_TIME_Absolute reload_time; - - /** - * When is the next key invalid and we have to reload? (We also - * reload on SIGUSR1.) - */ - struct GNUNET_TIME_Absolute next_reload; - - /** - * Mint signing key that should be used currently. - */ - struct TALER_MINTDB_PrivateSigningKeyInformationP current_sign_key_issue; - - /** - * Reference count. The struct is released when the RC hits zero. - */ - unsigned int refcnt; -}; - - -/** - * Mint key state. Never use directly, instead access via - * #TMH_KS_acquire() and #TMH_KS_release(). - */ -static struct TMH_KS_StateHandle *internal_key_state; - -/** - * Mutex protecting access to #internal_key_state. - */ -static pthread_mutex_t internal_key_state_mutex = PTHREAD_MUTEX_INITIALIZER; - -/** - * Pipe used for signaling reloading of our key state. - */ -static int reload_pipe[2]; - - -/** - * Convert the public part of a denomination key issue to a JSON - * object. - * - * @param pk public key of the denomination key - * @param dki the denomination key issue - * @return a JSON object describing the denomination key isue (public part) - */ -static json_t * -denom_key_issue_to_json (const struct TALER_DenominationPublicKey *pk, - const struct TALER_MINTDB_DenominationKeyInformationP *dki) -{ - struct TALER_Amount value; - struct TALER_Amount fee_withdraw; - struct TALER_Amount fee_deposit; - struct TALER_Amount fee_refresh; - - TALER_amount_ntoh (&value, - &dki->properties.value); - TALER_amount_ntoh (&fee_withdraw, - &dki->properties.fee_withdraw); - TALER_amount_ntoh (&fee_deposit, - &dki->properties.fee_deposit); - TALER_amount_ntoh (&fee_refresh, - &dki->properties.fee_refresh); - return - json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}", - "master_sig", - TALER_json_from_data (&dki->signature, - sizeof (struct GNUNET_CRYPTO_EddsaSignature)), - "stamp_start", - TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (dki->properties.start)), - "stamp_expire_withdraw", - TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (dki->properties.expire_withdraw)), - "stamp_expire_deposit", - TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (dki->properties.expire_spend)), - "stamp_expire_legal", - TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (dki->properties.expire_legal)), - "denom_pub", - TALER_json_from_rsa_public_key (pk->rsa_public_key), - "value", - TALER_json_from_amount (&value), - "fee_withdraw", - TALER_json_from_amount (&fee_withdraw), - "fee_deposit", - TALER_json_from_amount (&fee_deposit), - "fee_refresh", - TALER_json_from_amount (&fee_refresh)); -} - - -/** - * Get the relative time value that describes how - * far in the future do we want to provide coin keys. - * - * @return the provide duration - */ -static struct GNUNET_TIME_Relative -TALER_MINT_conf_duration_provide () -{ - struct GNUNET_TIME_Relative rel; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (cfg, - "mint_keys", - "lookahead_provide", - &rel)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "mint_keys", - "lookahead_provide", - "time value required"); - GNUNET_assert (0); - } - return rel; -} - - -/** - * Iterator for (re)loading/initializing denomination keys. - * - * @param cls closure - * @param dki the denomination key issue - * @param alias coin alias - * @return #GNUNET_OK to continue to iterate, - * #GNUNET_NO to stop iteration with no error, - * #GNUNET_SYSERR to abort iteration with error! - */ -static int -reload_keys_denom_iter (void *cls, - const char *alias, - const struct TALER_MINTDB_DenominationKeyIssueInformation *dki) -{ - struct TMH_KS_StateHandle *ctx = cls; - struct GNUNET_TIME_Absolute now; - struct GNUNET_TIME_Absolute horizon; - struct GNUNET_HashCode denom_key_hash; - struct TALER_MINTDB_DenominationKeyIssueInformation *d2; - struct TALER_MINTDB_Session *session; - int res; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Loading denomination key `%s'\n", - alias); - horizon = GNUNET_TIME_relative_to_absolute (TALER_MINT_conf_duration_provide ()); - if (GNUNET_TIME_absolute_ntoh (dki->issue.properties.start).abs_value_us > - horizon.abs_value_us) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Skipping future denomination key `%s'\n", - alias); - return GNUNET_OK; - } - now = GNUNET_TIME_absolute_get (); - if (GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_spend).abs_value_us < - now.abs_value_us) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Skipping expired denomination key `%s'\n", - alias); - return GNUNET_OK; - } - - GNUNET_CRYPTO_rsa_public_key_hash (dki->denom_pub.rsa_public_key, - &denom_key_hash); - GNUNET_CRYPTO_hash_context_read (ctx->hash_context, - &denom_key_hash, - sizeof (struct GNUNET_HashCode)); - session = TMH_plugin->get_session (TMH_plugin->cls, - TMH_test_mode); - if (NULL == session) - return GNUNET_SYSERR; - /* Try to insert DKI into DB until we succeed; note that if the DB - failure is persistent, this code may loop forever (as there is no - sane alternative, we cannot continue without the DKI being in the - DB). */ - res = GNUNET_SYSERR; - while (GNUNET_OK != res) - { - res = TMH_plugin->start (TMH_plugin->cls, - session); - if (GNUNET_OK != res) - { - /* Transaction start failed!? Very bad error, log and retry */ - GNUNET_break (0); - continue; - } - res = TMH_plugin->get_denomination_info (TMH_plugin->cls, - session, - &dki->denom_pub, - NULL); - if (GNUNET_SYSERR == res) - { - /* Fetch failed!? Very bad error, log and retry */ - GNUNET_break (0); - TMH_plugin->rollback (TMH_plugin->cls, - session); - continue; - } - if (GNUNET_OK == res) - { - /* Record exists, we're good, just exit */ - TMH_plugin->rollback (TMH_plugin->cls, - session); - break; - } - res = TMH_plugin->insert_denomination_info (TMH_plugin->cls, - session, - &dki->denom_pub, - &dki->issue); - if (GNUNET_OK != res) - { - /* Insert failed!? Very bad error, log and retry */ - GNUNET_break (0); - TMH_plugin->rollback (TMH_plugin->cls, - session); - continue; - } - res = TMH_plugin->commit (TMH_plugin->cls, - session); - /* If commit succeeded, we're done, otherwise we retry; this - time without logging, as theroetically commits can fail - in a transactional DB due to concurrent activities that - cannot be reconciled. This should be rare for DKIs, but - as it is possible we just retry until we succeed. */ - } - - d2 = GNUNET_new (struct TALER_MINTDB_DenominationKeyIssueInformation); - d2->issue = dki->issue; - d2->denom_priv.rsa_private_key - = GNUNET_CRYPTO_rsa_private_key_dup (dki->denom_priv.rsa_private_key); - d2->denom_pub.rsa_public_key - = GNUNET_CRYPTO_rsa_public_key_dup (dki->denom_pub.rsa_public_key); - res = GNUNET_CONTAINER_multihashmap_put (ctx->denomkey_map, - &denom_key_hash, - d2, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); - if (GNUNET_OK != res) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Duplicate denomination key `%s'\n", - alias); - GNUNET_CRYPTO_rsa_private_key_free (d2->denom_priv.rsa_private_key); - GNUNET_CRYPTO_rsa_public_key_free (d2->denom_pub.rsa_public_key); - GNUNET_free (d2); - return GNUNET_OK; - } - json_array_append_new (ctx->denom_keys_array, - denom_key_issue_to_json (&dki->denom_pub, - &dki->issue)); - return GNUNET_OK; -} - - -/** - * Convert the public part of a sign key issue to a JSON object. - * - * @param ski the sign key issue - * @return a JSON object describing the sign key isue (public part) - */ -static json_t * -sign_key_issue_to_json (const struct TALER_MintSigningKeyValidityPS *ski) -{ - return - json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o}", - "stamp_start", - TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (ski->start)), - "stamp_expire", - TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (ski->expire)), - "stamp_end", - TALER_json_from_abs (GNUNET_TIME_absolute_ntoh (ski->end)), - "master_pub", - TALER_json_from_data (&ski->master_public_key, - sizeof (struct TALER_MasterPublicKeyP)), - "master_sig", - TALER_json_from_data (&ski->signature, - sizeof (struct TALER_MasterSignatureP)), - "key", - TALER_json_from_data (&ski->signkey_pub, - sizeof (struct TALER_MintPublicKeyP))); -} - - -/** - * Iterator for sign keys. - * - * @param cls closure - * @param filename name of the file the key came from - * @param ski the sign key issue - * @return #GNUNET_OK to continue to iterate, - * #GNUNET_NO to stop iteration with no error, - * #GNUNET_SYSERR to abort iteration with error! - */ -static int -reload_keys_sign_iter (void *cls, - const char *filename, - const struct TALER_MINTDB_PrivateSigningKeyInformationP *ski) -{ - struct TMH_KS_StateHandle *ctx = cls; - struct GNUNET_TIME_Absolute now; - struct GNUNET_TIME_Absolute horizon; - - horizon = GNUNET_TIME_relative_to_absolute (TALER_MINT_conf_duration_provide ()); - if (GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us > - horizon.abs_value_us) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Skipping future signing key `%s'\n", - filename); - return GNUNET_OK; - } - now = GNUNET_TIME_absolute_get (); - if (GNUNET_TIME_absolute_ntoh (ski->issue.expire).abs_value_us < - now.abs_value_us) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Skipping expired signing key `%s'\n", - filename); - return GNUNET_OK; - } - - /* The signkey is valid at this time, check if it's more recent than - what we have so far! */ - if ( (GNUNET_TIME_absolute_ntoh (ctx->current_sign_key_issue.issue.start).abs_value_us < - GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us) && - (GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us < - now.abs_value_us) ) - { - /* We use the most recent one, if it is valid now (not just in the near future) */ - ctx->current_sign_key_issue = *ski; - } - json_array_append_new (ctx->sign_keys_array, - sign_key_issue_to_json (&ski->issue)); - - return GNUNET_OK; -} - - -/** - * Iterator for freeing denomination keys. - * - * @param cls closure with the `struct TMH_KS_StateHandle` - * @param key key for the denomination key - * @param value coin details - * @return #GNUNET_OK to continue to iterate, - * #GNUNET_NO to stop iteration with no error, - * #GNUNET_SYSERR to abort iteration with error! - */ -static int -free_denom_key (void *cls, - const struct GNUNET_HashCode *key, - void *value) -{ - struct TALER_MINTDB_DenominationKeyIssueInformation *dki = value; - - GNUNET_CRYPTO_rsa_private_key_free (dki->denom_priv.rsa_private_key); - GNUNET_CRYPTO_rsa_public_key_free (dki->denom_pub.rsa_public_key); - GNUNET_free (dki); - return GNUNET_OK; -} - - -/** - * Release key state, free if necessary (if reference count gets to zero). - * Internal method used when the mutex is already held. - * - * @param key_state the key state to release - */ -static void -TMH_KS_release_ (struct TMH_KS_StateHandle *key_state) -{ - GNUNET_assert (0 < key_state->refcnt); - key_state->refcnt--; - if (0 == key_state->refcnt) - { - if (NULL != key_state->denom_keys_array) - { - json_decref (key_state->denom_keys_array); - key_state->denom_keys_array = NULL; - } - if (NULL != key_state->sign_keys_array) - { - json_decref (key_state->sign_keys_array); - key_state->sign_keys_array = NULL; - } - if (NULL != key_state->denomkey_map) - { - GNUNET_CONTAINER_multihashmap_iterate (key_state->denomkey_map, - &free_denom_key, - key_state); - GNUNET_CONTAINER_multihashmap_destroy (key_state->denomkey_map); - key_state->denomkey_map = NULL; - } - GNUNET_free_non_null (key_state->keys_json); - GNUNET_free (key_state); - } -} - - -/** - * Release key state, free if necessary (if reference count gets to zero). - * - * @param key_state the key state to release - */ -void -TMH_KS_release (struct TMH_KS_StateHandle *key_state) -{ - GNUNET_assert (0 == pthread_mutex_lock (&internal_key_state_mutex)); - TMH_KS_release_ (key_state); - GNUNET_assert (0 == pthread_mutex_unlock (&internal_key_state_mutex)); -} - - -/** - * Acquire the key state of the mint. Updates keys if necessary. - * For every call to #TMH_KS_acquire(), a matching call - * to #TMH_KS_release() must be made. - * - * @return the key state - */ -struct TMH_KS_StateHandle * -TMH_KS_acquire (void) -{ - struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); - struct TMH_KS_StateHandle *key_state; - json_t *keys; - struct TALER_MintKeySetPS ks; - struct TALER_MintSignatureP sig; - - GNUNET_assert (0 == pthread_mutex_lock (&internal_key_state_mutex)); - if ( (NULL != internal_key_state) && - (internal_key_state->next_reload.abs_value_us <= now.abs_value_us) ) - { - TMH_KS_release_ (internal_key_state); - internal_key_state = NULL; - } - if (NULL == internal_key_state) - { - key_state = GNUNET_new (struct TMH_KS_StateHandle); - key_state->hash_context = GNUNET_CRYPTO_hash_context_start (); - key_state->denom_keys_array = json_array (); - GNUNET_assert (NULL != key_state->denom_keys_array); - key_state->sign_keys_array = json_array (); - GNUNET_assert (NULL != key_state->sign_keys_array); - key_state->denomkey_map = GNUNET_CONTAINER_multihashmap_create (32, - GNUNET_NO); - key_state->reload_time = GNUNET_TIME_absolute_get (); - TALER_round_abs_time (&key_state->reload_time); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Loading keys from `%s'\n", - TMH_mint_directory); - TALER_MINTDB_denomination_keys_iterate (TMH_mint_directory, - &reload_keys_denom_iter, - key_state); - TALER_MINTDB_signing_keys_iterate (TMH_mint_directory, - &reload_keys_sign_iter, - key_state); - ks.purpose.size = htonl (sizeof (ks)); - ks.purpose.purpose = htonl (TALER_SIGNATURE_MINT_KEY_SET); - ks.list_issue_date = GNUNET_TIME_absolute_hton (key_state->reload_time); - GNUNET_CRYPTO_hash_context_finish (key_state->hash_context, - &ks.hc); - key_state->hash_context = NULL; - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv.eddsa_priv, - &ks.purpose, - &sig.eddsa_signature)); - key_state->next_reload = GNUNET_TIME_absolute_ntoh (key_state->current_sign_key_issue.issue.expire); - if (0 == key_state->next_reload.abs_value_us) - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "No valid signing key found!\n"); - - keys = json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o}", - "master_public_key", - TALER_json_from_data (&TMH_master_public_key, - sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)), - "signkeys", key_state->sign_keys_array, - "denoms", key_state->denom_keys_array, - "list_issue_date", TALER_json_from_abs (key_state->reload_time), - "eddsa_pub", TALER_json_from_data (&key_state->current_sign_key_issue.issue.signkey_pub, - sizeof (struct TALER_MintPublicKeyP)), - "eddsa_sig", TALER_json_from_data (&sig, - sizeof (struct TALER_MintSignatureP))); - key_state->sign_keys_array = NULL; - key_state->denom_keys_array = NULL; - key_state->keys_json = json_dumps (keys, - JSON_INDENT (2)); - json_decref (keys); - internal_key_state = key_state; - } - key_state = internal_key_state; - key_state->refcnt++; - GNUNET_assert (0 == pthread_mutex_unlock (&internal_key_state_mutex)); - - return key_state; -} - - -/** - * Look up the issue for a denom public key. - * - * @param key_state state to look in - * @param denom_pub denomination public key - * @param use purpose for which the key is being located - * @return the denomination key issue, - * or NULL if denom_pub could not be found - */ -struct TALER_MINTDB_DenominationKeyIssueInformation * -TMH_KS_denomination_key_lookup (const struct TMH_KS_StateHandle *key_state, - const struct TALER_DenominationPublicKey *denom_pub, - enum TMH_KS_DenominationKeyUse use) -{ - struct GNUNET_HashCode hc; - struct TALER_MINTDB_DenominationKeyIssueInformation *dki; - struct GNUNET_TIME_Absolute now; - - GNUNET_CRYPTO_rsa_public_key_hash (denom_pub->rsa_public_key, - &hc); - dki = GNUNET_CONTAINER_multihashmap_get (key_state->denomkey_map, - &hc); - if (NULL == dki) - return NULL; - now = GNUNET_TIME_absolute_get (); - if (now.abs_value_us < - GNUNET_TIME_absolute_ntoh (dki->issue.properties.start).abs_value_us) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Not returning DKI for %s, as start time is in the future\n", - GNUNET_h2s (&hc)); - return NULL; - } - now = GNUNET_TIME_absolute_get (); - switch (use) - { - case TMH_KS_DKU_WITHDRAW: - if (now.abs_value_us > - GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_withdraw).abs_value_us) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Not returning DKI for %s, as time to create coins has passed\n", - GNUNET_h2s (&hc)); - return NULL; - } - break; - case TMH_KS_DKU_DEPOSIT: - if (now.abs_value_us > - GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_spend).abs_value_us) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Not returning DKI for %s, as time to spend coin has passed\n", - GNUNET_h2s (&hc)); - return NULL; - } - break; - } - return dki; -} - - -/** - * Handle a signal, writing relevant signal numbers to the pipe. - * - * @param signal_number the signal number - */ -static void -handle_signal (int signal_number) -{ - ssize_t res; - char c = signal_number; - - res = write (reload_pipe[1], - &c, - 1); - if ( (res < 0) && - (EINTR != errno) ) - { - GNUNET_break (0); - return; - } - if (0 == res) - { - GNUNET_break (0); - return; - } -} - - -/** - * Call #handle_signal() to pass the received signal via - * the control pipe. - */ -static void -handle_sigusr1 () -{ - handle_signal (SIGUSR1); -} - - -/** - * Call #handle_signal() to pass the received signal via - * the control pipe. - */ -static void -handle_sigint () -{ - handle_signal (SIGINT); -} - - -/** - * Call #handle_signal() to pass the received signal via - * the control pipe. - */ -static void -handle_sigterm () -{ - handle_signal (SIGTERM); -} - - -/** - * Call #handle_signal() to pass the received signal via - * the control pipe. - */ -static void -handle_sighup () -{ - handle_signal (SIGHUP); -} - - -/** - * Read signals from a pipe in a loop, and reload keys from disk if - * SIGUSR1 is received, terminate if SIGTERM/SIGINT is received, and - * restart if SIGHUP is received. - * - * @return #GNUNET_SYSERR on errors, - * #GNUNET_OK to terminate normally - * #GNUNET_NO to restart an update version of the binary - */ -int -TMH_KS_loop (void) -{ - struct GNUNET_SIGNAL_Context *sigusr1; - struct GNUNET_SIGNAL_Context *sigterm; - struct GNUNET_SIGNAL_Context *sigint; - struct GNUNET_SIGNAL_Context *sighup; - int ret; - - if (0 != pipe (reload_pipe)) - { - fprintf (stderr, - "Failed to create pipe.\n"); - return GNUNET_SYSERR; - } - sigusr1 = GNUNET_SIGNAL_handler_install (SIGUSR1, - &handle_sigusr1); - sigterm = GNUNET_SIGNAL_handler_install (SIGTERM, - &handle_sigterm); - sigint = GNUNET_SIGNAL_handler_install (SIGINT, - &handle_sigint); - sighup = GNUNET_SIGNAL_handler_install (SIGHUP, - &handle_sighup); - - ret = 0; - while (0 == ret) - { - char c; - ssize_t res; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "(re-)loading keys\n"); - if (NULL != internal_key_state) - { - TMH_KS_release (internal_key_state); - internal_key_state = NULL; - } - /* This will re-initialize 'internal_key_state' with - an initial refcnt of 1 */ - (void) TMH_KS_acquire (); - -read_again: - errno = 0; - res = read (reload_pipe[0], - &c, - 1); - if ((res < 0) && (EINTR != errno)) - { - GNUNET_break (0); - ret = GNUNET_SYSERR; - break; - } - if (EINTR == errno) - goto read_again; - switch (c) - { - case SIGUSR1: - /* reload internal key state, we do this in the loop */ - break; - case SIGTERM: - case SIGINT: - /* terminate */ - ret = GNUNET_OK; - break; - case SIGHUP: - /* restart updated binary */ - ret = GNUNET_NO; - break; - default: - /* unexpected character */ - GNUNET_break (0); - break; - } - } - if (NULL != internal_key_state) - { - TMH_KS_release (internal_key_state); - internal_key_state = NULL; - } - GNUNET_SIGNAL_handler_uninstall (sigusr1); - GNUNET_SIGNAL_handler_uninstall (sigterm); - GNUNET_SIGNAL_handler_uninstall (sigint); - GNUNET_SIGNAL_handler_uninstall (sighup); - return ret; -} - - -/** - * Sign the message in @a purpose with the mint's signing key. - * - * @param purpose the message to sign - * @param[out] pub set to the current public signing key of the mint - * @param[out] sig signature over purpose using current signing key - */ -void -TMH_KS_sign (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, - struct TALER_MintPublicKeyP *pub, - struct TALER_MintSignatureP *sig) - -{ - struct TMH_KS_StateHandle *key_state; - - key_state = TMH_KS_acquire (); - *pub = key_state->current_sign_key_issue.issue.signkey_pub; - GNUNET_assert (GNUNET_OK == - GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv.eddsa_priv, - purpose, - &sig->eddsa_signature)); - TMH_KS_release (key_state); -} - - -/** - * Function to call to handle the request by sending - * back static data from the @a rh. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_KS_handler_keys (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - struct TMH_KS_StateHandle *key_state; - struct MHD_Response *response; - int ret; - - key_state = TMH_KS_acquire (); - response = MHD_create_response_from_buffer (strlen (key_state->keys_json), - key_state->keys_json, - MHD_RESPMEM_MUST_COPY); - TMH_KS_release (key_state); - if (NULL == response) - { - GNUNET_break (0); - return MHD_NO; - } - (void) MHD_add_response_header (response, - "Content-Type", - rh->mime_type); - ret = MHD_queue_response (connection, - rh->response_code, - response); - MHD_destroy_response (response); - return ret; -} - - -/* end of taler-mint-httpd_keystate.c */ diff --git a/src/backend/taler-mint-httpd_keystate.h b/src/backend/taler-mint-httpd_keystate.h deleted file mode 100644 index 62b041e9..00000000 --- a/src/backend/taler-mint-httpd_keystate.h +++ /dev/null @@ -1,142 +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 Affero 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 Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file mint/taler-mint-httpd_keystate.h - * @brief management of our private signing keys (denomination keys) - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#ifndef TALER_MINT_HTTPD_KEYSTATE_H -#define TALER_MINT_HTTPD_KEYSTATE_H - -#include <gnunet/gnunet_util_lib.h> -#include <microhttpd.h> -#include "taler-mint-httpd.h" -#include "taler_mintdb_lib.h" - - -/** - * Snapshot of the (coin and signing) - * keys (including private keys) of the mint. - */ -struct TMH_KS_StateHandle; - - -/** - * Acquire the key state of the mint. Updates keys if necessary. - * For every call to #TMH_KS_acquire(), a matching call - * to #TMH_KS_release() must be made. - * - * @return the key state - */ -struct TMH_KS_StateHandle * -TMH_KS_acquire (void); - - -/** - * Release key state, free if necessary (if reference count gets to zero). - * - * @param key_state the key state to release - */ -void -TMH_KS_release (struct TMH_KS_StateHandle *key_state); - - -/** - * Denomination key lookups can be for signing of fresh coins - * or to validate signatures on existing coins. As the validity - * periods for a key differ, the caller must specify which - * use is relevant for the current operation. - */ -enum TMH_KS_DenominationKeyUse { - - /** - * The key is to be used for a /withdraw/sign or /refresh (mint) - * operation. - */ - TMH_KS_DKU_WITHDRAW, - - /** - * The key is to be usd for a /deposit or /refresh (melt) operation. - */ - TMH_KS_DKU_DEPOSIT - -}; - - -/** - * Look up the issue for a denom public key. Note that the result - * is only valid while the @a key_state is not released! - * - * @param key_state state to look in - * @param denom_pub denomination public key - * @param use purpose for which the key is being located - * @return the denomination key issue, - * or NULL if denom_pub could not be found (or is not valid at this time for the given @a use) - */ -struct TALER_MINTDB_DenominationKeyIssueInformation * -TMH_KS_denomination_key_lookup (const struct TMH_KS_StateHandle *key_state, - const struct TALER_DenominationPublicKey *denom_pub, - enum TMH_KS_DenominationKeyUse use); - - -/** - * Read signals from a pipe in a loop, and reload keys from disk if - * SIGUSR1 is received, terminate if SIGTERM/SIGINT is received, and - * restart if SIGHUP is received. - * - * @return #GNUNET_SYSERR on errors, - * #GNUNET_OK to terminate normally - * #GNUNET_NO to restart an update version of the binary - */ -int -TMH_KS_loop (void); - - -/** - * Sign the message in @a purpose with the mint's signing - * key. - * - * @param purpose the message to sign - * @param[out] pub set to the current public signing key of the mint - * @param[out] sig signature over purpose using current signing key - */ -void -TMH_KS_sign (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, - struct TALER_MintPublicKeyP *pub, - struct TALER_MintSignatureP *sig); - - -/** - * Handle a "/keys" request - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_KS_handler_keys (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -#endif diff --git a/src/backend/taler-mint-httpd_mhd.c b/src/backend/taler-mint-httpd_mhd.c deleted file mode 100644 index b4e3c1f6..00000000 --- a/src/backend/taler-mint-httpd_mhd.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero 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 Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ - -/** - * @file taler-mint-httpd_mhd.c - * @brief helpers for MHD interaction; these are TALER_MINT_handler_ functions - * that generate simple MHD replies that do not require any real operations - * to be performed (error handling, static pages, etc.) - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include <microhttpd.h> -#include <pthread.h> -#include "taler-mint-httpd_responses.h" -#include "taler-mint-httpd.h" -#include "taler-mint-httpd_mhd.h" -#include "taler-mint-httpd_responses.h" - - -/** - * Function to call to handle the request by sending - * back static data from the @a rh. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_MHD_handler_static_response (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - struct MHD_Response *response; - int ret; - - if (0 == rh->data_size) - rh->data_size = strlen ((const char *) rh->data); - response = MHD_create_response_from_buffer (rh->data_size, - (void *) rh->data, - MHD_RESPMEM_PERSISTENT); - if (NULL == response) - { - GNUNET_break (0); - return MHD_NO; - } - if (NULL != rh->mime_type) - (void) MHD_add_response_header (response, - MHD_HTTP_HEADER_CONTENT_TYPE, - rh->mime_type); - ret = MHD_queue_response (connection, - rh->response_code, - response); - MHD_destroy_response (response); - return ret; -} - - -/** - * Function to call to handle the request by sending - * back a redirect to the AGPL source code. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_MHD_handler_agpl_redirect (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - const char *agpl = - "This server is licensed under the Affero GPL. You will now be redirected to the source code."; - struct MHD_Response *response; - int ret; - - response = MHD_create_response_from_buffer (strlen (agpl), - (void *) agpl, - MHD_RESPMEM_PERSISTENT); - if (NULL == response) - { - GNUNET_break (0); - return MHD_NO; - } - if (NULL != rh->mime_type) - (void) MHD_add_response_header (response, - MHD_HTTP_HEADER_CONTENT_TYPE, - rh->mime_type); - MHD_add_response_header (response, - MHD_HTTP_HEADER_LOCATION, - "http://www.git.taler.net/?p=mint.git"); - ret = MHD_queue_response (connection, - rh->response_code, - response); - MHD_destroy_response (response); - return ret; -} - - -/** - * Function to call to handle the request by building a JSON - * reply with an error message from @a rh. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_MHD_handler_send_json_pack_error (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - return TMH_RESPONSE_reply_json_pack (connection, - rh->response_code, - "{s:s}", - "error", - rh->data); -} - - -/* end of taler-mint-httpd_mhd.c */ diff --git a/src/backend/taler-mint-httpd_mhd.h b/src/backend/taler-mint-httpd_mhd.h deleted file mode 100644 index a9f575df..00000000 --- a/src/backend/taler-mint-httpd_mhd.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero 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 Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ - -/** - * @file taler-mint-httpd_mhd.h - * @brief helpers for MHD interaction, used to generate simple responses - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#ifndef TALER_MINT_HTTPD_MHD_H -#define TALER_MINT_HTTPD_MHD_H -#include <gnunet/gnunet_util_lib.h> -#include <microhttpd.h> -#include "taler-mint-httpd.h" - - -/** - * Function to call to handle the request by sending - * back static data from the @a rh. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_MHD_handler_static_response (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -/** - * Function to call to handle the request by sending - * back a redirect to the AGPL source code. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_MHD_handler_agpl_redirect (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -/** - * Function to call to handle the request by building a JSON - * reply from varargs. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param response_code HTTP response code to use - * @param do_cache can the response be cached? (0: no, 1: yes) - * @param fmt format string for pack - * @param ... varargs - * @return MHD result code - */ -int -TMH_MHD_helper_send_json_pack (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void *connection_cls, - int response_code, - int do_cache, - const char *fmt, - ...); - - -/** - * Function to call to handle the request by building a JSON - * reply with an error message from @a rh. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_MHD_handler_send_json_pack_error (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -#endif diff --git a/src/backend/taler-mint-httpd_parsing.c b/src/backend/taler-mint-httpd_parsing.c index 1844fa88..f84e7314 100644 --- a/src/backend/taler-mint-httpd_parsing.c +++ b/src/backend/taler-mint-httpd_parsing.c @@ -139,90 +139,6 @@ buffer_append (struct Buffer *buf, return GNUNET_OK; } - -/** - * Release all memory allocated for the variable-size fields in - * the parser specification. - * - * @param spec specification to free - * @param spec_len number of items in @a spec to look at - */ -static void -release_data (struct TMH_PARSE_FieldSpecification *spec, - unsigned int spec_len) -{ - unsigned int i; - - for (i=0; i < spec_len; i++) - { - switch (spec[i].command) - { - case TMH_PARSE_JNC_FIELD: - GNUNET_break (0); - return; - case TMH_PARSE_JNC_INDEX: - GNUNET_break (0); - return; - case TMH_PARSE_JNC_RET_DATA: - break; - case TMH_PARSE_JNC_RET_DATA_VAR: - if (NULL != spec[i].destination) - { - GNUNET_free (* (void**) spec[i].destination); - *(void**) spec[i].destination = NULL; - *spec[i].destination_size_out = 0; - } - break; - case TMH_PARSE_JNC_RET_TYPED_JSON: - { - json_t *json; - - json = *(json_t **) spec[i].destination; - if (NULL != json) - { - json_decref (json); - *(json_t**) spec[i].destination = NULL; - } - } - break; - case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY: - { - struct TALER_DenominationPublicKey *pk; - - pk = spec[i].destination; - if (NULL != pk->rsa_public_key) - { - GNUNET_CRYPTO_rsa_public_key_free (pk->rsa_public_key); - pk->rsa_public_key = NULL; - } - } - break; - case TMH_PARSE_JNC_RET_RSA_SIGNATURE: - { - struct TALER_DenominationSignature *sig; - - sig = spec[i].destination; - if (NULL != sig->rsa_signature) - { - GNUNET_CRYPTO_rsa_signature_free (sig->rsa_signature); - sig->rsa_signature = NULL; - } - } - break; - case TMH_PARSE_JNC_RET_AMOUNT: - memset (spec[i].destination, - 0, - sizeof (struct TALER_Amount)); - break; - case TMH_PARSE_JNC_RET_TIME_ABSOLUTE: - break; - case TMH_PARSE_JNC_RET_UINT64: - break; - } - } -} - - /** * Process a POST request containing a JSON object. This function * realizes an MHD POST processor that will (incrementally) process @@ -324,800 +240,4 @@ TMH_PARSE_post_json (struct MHD_Connection *connection, return GNUNET_YES; } - -/** - * Function called whenever we are done with a request - * to clean up our state. - * - * @param con_cls value as it was left by - * #TMH_PARSE_post_json(), to be cleaned up - */ -void -TMH_PARSE_post_cleanup_callback (void *con_cls) -{ - struct Buffer *r = con_cls; - - if (NULL != r) - { - buffer_deinit (r); - GNUNET_free (r); - } -} - - -/** - * Extract base32crockford encoded data from request. - * - * Queues an error response to the connection if the parameter is missing or - * invalid. - * - * @param connection the MHD connection - * @param param_name the name of the parameter with the key - * @param[out] out_data pointer to store the result - * @param out_size expected size of data - * @return - * #GNUNET_YES if the the argument is present - * #GNUNET_NO if the argument is absent or malformed - * #GNUNET_SYSERR on internal error (error response could not be sent) - */ -int -TMH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection, - const char *param_name, - void *out_data, - size_t out_size) -{ - const char *str; - - str = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - param_name); - if (NULL == str) - { - return (MHD_NO == - TMH_RESPONSE_reply_arg_missing (connection, param_name)) - ? GNUNET_SYSERR : GNUNET_NO; - } - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (str, - strlen (str), - out_data, - out_size)) - return (MHD_NO == - TMH_RESPONSE_reply_arg_invalid (connection, param_name)) - ? GNUNET_SYSERR : GNUNET_NO; - return GNUNET_OK; -} - - -/** - * Extraxt variable-size base32crockford encoded data from request. - * - * Queues an error response to the connection if the parameter is missing - * or the encoding is invalid. - * - * @param connection the MHD connection - * @param param_name the name of the parameter with the key - * @param[out] out_data pointer to allocate buffer and store the result - * @param[out] out_size set to the size of the buffer allocated in @a out_data - * @return - * #GNUNET_YES if the the argument is present - * #GNUNET_NO if the argument is absent or malformed - * #GNUNET_SYSERR on internal error (error response could not be sent) - */ -int -TMH_PARSE_mhd_request_var_arg_data (struct MHD_Connection *connection, - const char *param_name, - void **out_data, - size_t *out_size) -{ - const char *str; - size_t slen; - size_t olen; - void *out; - - str = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - param_name); - if (NULL == str) - { - return (MHD_NO == - TMH_RESPONSE_reply_arg_missing (connection, param_name)) - ? GNUNET_SYSERR : GNUNET_NO; - } - slen = strlen (str); - olen = (slen * 5) / 8; - out = GNUNET_malloc (olen); - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (str, - strlen (str), - out, - olen)) - { - GNUNET_free (out); - *out_size = 0; - return (MHD_NO == - TMH_RESPONSE_reply_arg_invalid (connection, param_name)) - ? GNUNET_SYSERR : GNUNET_NO; - } - *out_data = out; - *out_size = olen; - return GNUNET_OK; -} - - -/** - * Navigate through a JSON tree. - * - * Sends an error response if navigation is impossible (i.e. - * the JSON object is invalid) - * - * @param connection the connection to send an error response to - * @param root the JSON node to start the navigation at. - * @param ... navigation specification (see `enum TMH_PARSE_JsonNavigationCommand`) - * @return - * #GNUNET_YES if navigation was successful - * #GNUNET_NO if json is malformed, error response was generated - * #GNUNET_SYSERR on internal error (no response was generated, - * connection must be closed) - */ -int -TMH_PARSE_navigate_json (struct MHD_Connection *connection, - const json_t *root, - ...) -{ - va_list argp; - int ret; - json_t *path; /* what's our current path from 'root'? */ - - path = json_array (); - va_start (argp, root); - ret = 2; /* just not any of the valid return values */ - while (2 == ret) - { - enum TMH_PARSE_JsonNavigationCommand command - = va_arg (argp, - enum TMH_PARSE_JsonNavigationCommand); - - switch (command) - { - case TMH_PARSE_JNC_FIELD: - { - const char *fname = va_arg(argp, const char *); - - json_array_append_new (path, - json_string (fname)); - root = json_object_get (root, - fname); - if (NULL == root) - { - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:s, s:O}", - "error", "missing field in JSON", - "field", fname, - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - } - break; - - case TMH_PARSE_JNC_INDEX: - { - int fnum = va_arg(argp, int); - - json_array_append_new (path, - json_integer (fnum)); - root = json_array_get (root, - fnum); - if (NULL == root) - { - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "missing index in JSON", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - } - break; - - case TMH_PARSE_JNC_RET_DATA: - { - void *where = va_arg (argp, void *); - size_t len = va_arg (argp, size_t); - const char *str; - int res; - - str = json_string_value (root); - if (NULL == str) - { - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "string expected", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - res = GNUNET_STRINGS_string_to_data (str, strlen (str), - where, len); - if (GNUNET_OK != res) - { - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "malformed binary data in JSON", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - ret = GNUNET_OK; - } - break; - - case TMH_PARSE_JNC_RET_DATA_VAR: - { - void **where = va_arg (argp, void **); - size_t *len = va_arg (argp, size_t *); - const char *str; - int res; - - str = json_string_value (root); - if (NULL == str) - { - ret = (MHD_YES == - TMH_RESPONSE_reply_internal_error (connection, - "json_string_value() failed")) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - *len = (strlen (str) * 5) / 8; - if (NULL != where) - { - *where = GNUNET_malloc (*len); - res = GNUNET_STRINGS_string_to_data (str, - strlen (str), - *where, - *len); - if (GNUNET_OK != res) - { - GNUNET_free (*where); - *where = NULL; - *len = 0; - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "malformed binary data in JSON", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - } - ret = GNUNET_OK; - } - break; - - case TMH_PARSE_JNC_RET_TYPED_JSON: - { - int typ = va_arg (argp, int); - const json_t **r_json = va_arg (argp, const json_t **); - - if ( (NULL == root) || - ( (-1 != typ) && - (json_typeof (root) != typ)) ) - { - *r_json = NULL; - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:i, s:i, s:O}", - "error", "wrong JSON field type", - "type_expected", typ, - "type_actual", json_typeof (root), - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - *r_json = root; - json_incref ((json_t *) root); - ret = GNUNET_OK; - } - break; - - case TMH_PARSE_JNC_RET_UINT64: - { - uint64_t *r_u64 = va_arg (argp, uint64_t *); - - if (json_typeof (root) != JSON_INTEGER) - { - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:s, s:i, s:O}", - "error", "wrong JSON field type", - "type_expected", "integer", - "type_actual", json_typeof (root), - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - *r_u64 = (uint64_t) json_integer_value (root); - ret = GNUNET_OK; - } - break; - - case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY: - { - struct TALER_DenominationPublicKey *where; - size_t len; - const char *str; - int res; - void *buf; - - where = va_arg (argp, - struct TALER_DenominationPublicKey *); - str = json_string_value (root); - if (NULL == str) - { - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "string expected", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - len = (strlen (str) * 5) / 8; - buf = GNUNET_malloc (len); - res = GNUNET_STRINGS_string_to_data (str, - strlen (str), - buf, - len); - if (GNUNET_OK != res) - { - GNUNET_free (buf); - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "malformed binary data in JSON", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - where->rsa_public_key = GNUNET_CRYPTO_rsa_public_key_decode (buf, - len); - GNUNET_free (buf); - if (NULL == where->rsa_public_key) - { - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "malformed RSA public key in JSON", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - ret = GNUNET_OK; - break; - } - - case TMH_PARSE_JNC_RET_RSA_SIGNATURE: - { - struct TALER_DenominationSignature *where; - size_t len; - const char *str; - int res; - void *buf; - - where = va_arg (argp, - struct TALER_DenominationSignature *); - str = json_string_value (root); - if (NULL == str) - { - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "string expected", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - len = (strlen (str) * 5) / 8; - buf = GNUNET_malloc (len); - res = GNUNET_STRINGS_string_to_data (str, - strlen (str), - buf, - len); - if (GNUNET_OK != res) - { - GNUNET_free (buf); - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "malformed binary data in JSON", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - where->rsa_signature = GNUNET_CRYPTO_rsa_signature_decode (buf, - len); - GNUNET_free (buf); - if (NULL == where->rsa_signature) - { - ret = (MHD_YES == - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "malformed RSA signature in JSON", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - ret = GNUNET_OK; - break; - } - - case TMH_PARSE_JNC_RET_AMOUNT: - { - struct TALER_Amount *where = va_arg (argp, void *); - - if (GNUNET_OK != - TALER_json_to_amount ((json_t *) root, - where)) - { - if (MHD_YES != - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O}", - "error", "Bad format", - "path", path)) - return GNUNET_SYSERR; - return GNUNET_NO; - } - if (0 != strcmp (where->currency, - TMH_mint_currency_string)) - { - if (MHD_YES != - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:O, s:s}", - "error", "Currency not supported", - "path", path, - "currency", where->currency)) - { - memset (where, 0, sizeof (struct TALER_Amount)); - return GNUNET_SYSERR; - } - memset (where, 0, sizeof (struct TALER_Amount)); - return GNUNET_NO; - } - ret = GNUNET_OK; - break; - } - - case TMH_PARSE_JNC_RET_TIME_ABSOLUTE: - { - struct GNUNET_TIME_Absolute *where = va_arg (argp, void *); - - if (GNUNET_OK != - TALER_json_to_abs ((json_t *) root, - where)) - { - if (MHD_YES != - TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:s, s:O}", - "error", "Bad format", - "hint", "expected absolute time", - "path", path)) - return GNUNET_SYSERR; - return GNUNET_NO; - } - ret = GNUNET_OK; - break; - } - - default: - GNUNET_break (0); - ret = (MHD_YES == - TMH_RESPONSE_reply_internal_error (connection, - "unhandled value in switch")) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - } - va_end (argp); - json_decref (path); - return ret; -} - - -/** - * Parse JSON object into components based on the given field - * specification. - * - * @param connection the connection to send an error response to - * @param root the JSON node to start the navigation at. - * @param spec field specification for the parser - * @return - * #GNUNET_YES if navigation was successful (caller is responsible - * for freeing allocated variable-size data using - * #TMH_PARSE_release_data() when done) - * #GNUNET_NO if json is malformed, error response was generated - * #GNUNET_SYSERR on internal error - */ -int -TMH_PARSE_json_data (struct MHD_Connection *connection, - const json_t *root, - struct TMH_PARSE_FieldSpecification *spec) -{ - unsigned int i; - int ret; - - ret = GNUNET_YES; - for (i=0; NULL != spec[i].field_name; i++) - { - if (GNUNET_YES != ret) - break; - switch (spec[i].command) - { - case TMH_PARSE_JNC_FIELD: - GNUNET_break (0); - return GNUNET_SYSERR; - case TMH_PARSE_JNC_INDEX: - GNUNET_break (0); - return GNUNET_SYSERR; - case TMH_PARSE_JNC_RET_DATA: - ret = TMH_PARSE_navigate_json (connection, - root, - TMH_PARSE_JNC_FIELD, - spec[i].field_name, - TMH_PARSE_JNC_RET_DATA, - spec[i].destination, - spec[i].destination_size_in); - break; - case TMH_PARSE_JNC_RET_DATA_VAR: - ret = TMH_PARSE_navigate_json (connection, - root, - TMH_PARSE_JNC_FIELD, - spec[i].field_name, - TMH_PARSE_JNC_RET_DATA_VAR, - (void **) spec[i].destination, - spec[i].destination_size_out); - break; - case TMH_PARSE_JNC_RET_TYPED_JSON: - ret = TMH_PARSE_navigate_json (connection, - root, - TMH_PARSE_JNC_FIELD, - spec[i].field_name, - TMH_PARSE_JNC_RET_TYPED_JSON, - spec[i].type, - spec[i].destination); - break; - case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY: - ret = TMH_PARSE_navigate_json (connection, - root, - TMH_PARSE_JNC_FIELD, - spec[i].field_name, - TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY, - spec[i].destination); - break; - case TMH_PARSE_JNC_RET_RSA_SIGNATURE: - ret = TMH_PARSE_navigate_json (connection, - root, - TMH_PARSE_JNC_FIELD, - spec[i].field_name, - TMH_PARSE_JNC_RET_RSA_SIGNATURE, - spec[i].destination); - break; - case TMH_PARSE_JNC_RET_AMOUNT: - GNUNET_assert (sizeof (struct TALER_Amount) == - spec[i].destination_size_in); - ret = TMH_PARSE_navigate_json (connection, - root, - TMH_PARSE_JNC_FIELD, - spec[i].field_name, - TMH_PARSE_JNC_RET_AMOUNT, - spec[i].destination); - break; - case TMH_PARSE_JNC_RET_TIME_ABSOLUTE: - GNUNET_assert (sizeof (struct GNUNET_TIME_Absolute) == - spec[i].destination_size_in); - ret = TMH_PARSE_navigate_json (connection, - root, - TMH_PARSE_JNC_FIELD, - spec[i].field_name, - TMH_PARSE_JNC_RET_TIME_ABSOLUTE, - spec[i].destination); - break; - case TMH_PARSE_JNC_RET_UINT64: - GNUNET_assert (sizeof (uint64_t) == - spec[i].destination_size_in); - ret = TMH_PARSE_navigate_json (connection, - root, - TMH_PARSE_JNC_FIELD, - spec[i].field_name, - TMH_PARSE_JNC_RET_UINT64, - spec[i].destination); - break; - } - } - if (GNUNET_YES != ret) - release_data (spec, - i - 1); - return ret; -} - - -/** - * Release all memory allocated for the variable-size fields in - * the parser specification. - * - * @param spec specification to free - */ -void -TMH_PARSE_release_data (struct TMH_PARSE_FieldSpecification *spec) -{ - unsigned int i; - - for (i=0; NULL != spec[i].field_name; i++) ; - release_data (spec, i); -} - - -/** - * Generate line in parser specification for 64-bit integer - * given as an integer in JSON. - * - * @param field name of the field - * @param[out] u64 integer to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_uint64 (const char *field, - uint64_t *u64) -{ - struct TMH_PARSE_FieldSpecification ret = - { field, (void *) u64, sizeof (uint64_t), NULL, TMH_PARSE_JNC_RET_UINT64, 0 }; - return ret; -} - - -/** - * Generate line in parser specification for JSON object value. - * - * @param field name of the field - * @param[out] jsonp address of pointer to JSON to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_object (const char *field, - json_t **jsonp) -{ - struct TMH_PARSE_FieldSpecification ret = - { field, jsonp, 0, NULL, TMH_PARSE_JNC_RET_TYPED_JSON, JSON_OBJECT }; - *jsonp = NULL; - return ret; -} - - -/** - * Generate line in parser specification for JSON array value. - * - * @param field name of the field - * @param[out] jsonp address of JSON pointer to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_array (const char *field, - json_t **jsonp) -{ - struct TMH_PARSE_FieldSpecification ret = - { field, jsonp, 0, NULL, TMH_PARSE_JNC_RET_TYPED_JSON, JSON_ARRAY }; - *jsonp = NULL; - return ret; -} - - -/** - * Generate line in parser specification for an absolute time. - * - * @param field name of the field - * @param[out] atime time to initialize - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_time_abs (const char *field, - struct GNUNET_TIME_Absolute *atime) -{ - struct TMH_PARSE_FieldSpecification ret = - { field, atime, sizeof(struct GNUNET_TIME_Absolute), NULL, TMH_PARSE_JNC_RET_TIME_ABSOLUTE, 0 }; - return ret; -} - - -/** - * Generate line in parser specification for RSA public key. - * - * @param field name of the field - * @param[out] pk key to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_denomination_public_key (const char *field, - struct TALER_DenominationPublicKey *pk) -{ - struct TMH_PARSE_FieldSpecification ret = - { field, pk, 0, NULL, TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY, 0 }; - pk->rsa_public_key = NULL; - return ret; -} - - -/** - * Generate line in parser specification for RSA public key. - * - * @param field name of the field - * @param sig the signature to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_denomination_signature (const char *field, - struct TALER_DenominationSignature *sig) -{ - struct TMH_PARSE_FieldSpecification ret = - { field, sig, 0, NULL, TMH_PARSE_JNC_RET_RSA_SIGNATURE, 0 }; - sig->rsa_signature = NULL; - return ret; -} - - -/** - * Generate line in parser specification for an amount. - * - * @param field name of the field - * @param amount a `struct TALER_Amount *` to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_amount (const char *field, - struct TALER_Amount *amount) -{ - struct TMH_PARSE_FieldSpecification ret = - { field, amount, sizeof(struct TALER_Amount), NULL, TMH_PARSE_JNC_RET_AMOUNT, 0 }; - memset (amount, 0, sizeof (struct TALER_Amount)); - return ret; -} - - -/** - * Generate line in parser specification for variable-size value. - * - * @param field name of the field - * @param[out] ptr pointer to initialize - * @param[out] ptr_size size to initialize - * @return corresponding field spec - */ -struct TMH_PARSE_FieldSpecification -TMH_PARSE_member_variable (const char *field, - void **ptr, - size_t *ptr_size) -{ - struct TMH_PARSE_FieldSpecification ret = - { field, ptr, 0, ptr_size, TMH_PARSE_JNC_RET_DATA_VAR, 0 }; - *ptr = NULL; - return ret; -} - /* end of taler-mint-httpd_parsing.c */ diff --git a/src/backend/taler-mint-httpd_refresh.c b/src/backend/taler-mint-httpd_refresh.c deleted file mode 100644 index 687fb998..00000000 --- a/src/backend/taler-mint-httpd_refresh.c +++ /dev/null @@ -1,907 +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 Affero 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 Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_refresh.c - * @brief Handle /refresh/ requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include <microhttpd.h> -#include "taler-mint-httpd_parsing.h" -#include "taler-mint-httpd_mhd.h" -#include "taler-mint-httpd_refresh.h" -#include "taler-mint-httpd_responses.h" -#include "taler-mint-httpd_keystate.h" - - -/** - * Handle a "/refresh/melt" request after the main JSON parsing has happened. - * We now need to validate the coins being melted and the session signature - * and then hand things of to execute the melt operation. - * - * @param connection the MHD connection to handle - * @param num_new_denoms number of coins to be created, size of y-dimension of @a commit_link array - * @param denom_pubs array of @a num_new_denoms keys - * @param coin_count number of coins to be melted, size of y-dimension of @a commit_coin array - * @param coin_melt_details array with @a coin_count entries with melting details - * @param session_hash hash over the data that the client commits to - * @param commit_coin 2d array of coin commitments (what the mint is to sign - * once the "/refres/reveal" of cut and choose is done) - * @param commit_link 2d array of coin link commitments (what the mint is - * to return via "/refresh/link" to enable linkage in the - * future) - * @return MHD result code - */ -static int -handle_refresh_melt_binary (struct MHD_Connection *connection, - unsigned int num_new_denoms, - const struct TALER_DenominationPublicKey *denom_pubs, - unsigned int coin_count, - const struct TMH_DB_MeltDetails *coin_melt_details, - const struct GNUNET_HashCode *session_hash, - struct TALER_MINTDB_RefreshCommitCoin *const* commit_coin, - struct TALER_MINTDB_RefreshCommitLinkP *const* commit_link) -{ - unsigned int i; - struct TMH_KS_StateHandle *key_state; - struct TALER_MINTDB_DenominationKeyInformationP *dki; - struct TALER_Amount cost; - struct TALER_Amount total_cost; - struct TALER_Amount melt; - struct TALER_Amount value; - struct TALER_Amount fee_withdraw; - struct TALER_Amount fee_melt; - struct TALER_Amount total_melt; - - GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TMH_mint_currency_string, - &total_cost)); - key_state = TMH_KS_acquire (); - for (i=0;i<num_new_denoms;i++) - { - dki = &TMH_KS_denomination_key_lookup (key_state, - &denom_pubs[i], - TMH_KS_DKU_WITHDRAW)->issue; - TALER_amount_ntoh (&value, - &dki->properties.value); - TALER_amount_ntoh (&fee_withdraw, - &dki->properties.fee_withdraw); - if ( (GNUNET_OK != - TALER_amount_add (&cost, - &value, - &fee_withdraw)) || - (GNUNET_OK != - TALER_amount_add (&total_cost, - &cost, - &total_cost)) ) - { - TMH_KS_release (key_state); - return TMH_RESPONSE_reply_internal_error (connection, - "cost calculation failure"); - } - } - - GNUNET_assert (GNUNET_OK == - TALER_amount_get_zero (TMH_mint_currency_string, - &total_melt)); - for (i=0;i<coin_count;i++) - { - /* calculate contribution of the i-th melt by subtracting - the fee; add the rest to the total_melt value */ - dki = &TMH_KS_denomination_key_lookup (key_state, - &coin_melt_details[i].coin_info.denom_pub, - TMH_KS_DKU_DEPOSIT)->issue; - TALER_amount_ntoh (&fee_melt, - &dki->properties.fee_refresh); - if (GNUNET_OK != - TALER_amount_subtract (&melt, - &coin_melt_details->melt_amount_with_fee, - &fee_melt)) - { - TMH_KS_release (key_state); - return TMH_RESPONSE_reply_external_error (connection, - "Melt contribution below melting fee"); - } - if (GNUNET_OK != - TALER_amount_add (&total_melt, - &melt, - &total_melt)) - { - TMH_KS_release (key_state); - return TMH_RESPONSE_reply_internal_error (connection, - "balance calculation failure"); - } - } - TMH_KS_release (key_state); - if (0 != - TALER_amount_cmp (&total_cost, - &total_melt)) - { - /* We require total value of coins being melted and - total value of coins being generated to match! */ - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s}", - "error", "value mismatch"); - } - return TMH_DB_execute_refresh_melt (connection, - session_hash, - num_new_denoms, - denom_pubs, - coin_count, - coin_melt_details, - commit_coin, - commit_link); -} - - -/** - * Extract public coin information from a JSON object. - * - * @param connection the connection to send error responses to - * @param coin_info the JSON object to extract the coin info from - * @param[out] r_melt_detail set to details about the coin's melting permission (if valid) - * @return #GNUNET_YES if coin public info in JSON was valid - * #GNUNET_NO JSON was invalid, response was generated - * #GNUNET_SYSERR on internal error - */ -static int -get_coin_public_info (struct MHD_Connection *connection, - json_t *coin_info, - struct TMH_DB_MeltDetails *r_melt_detail) -{ - int ret; - struct TALER_CoinSpendSignatureP melt_sig; - struct TALER_DenominationSignature sig; - struct TALER_DenominationPublicKey pk; - struct TALER_Amount amount; - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_fixed ("coin_pub", &r_melt_detail->coin_info.coin_pub), - TMH_PARSE_member_denomination_signature ("denom_sig", &sig), - TMH_PARSE_member_denomination_public_key ("denom_pub", &pk), - TMH_PARSE_member_fixed ("confirm_sig", &melt_sig), - TMH_PARSE_member_amount ("value_with_fee", &amount), - TMH_PARSE_MEMBER_END - }; - - ret = TMH_PARSE_json_data (connection, - coin_info, - spec); - if (GNUNET_OK != ret) - return ret; - /* check mint signature on the coin */ - r_melt_detail->coin_info.denom_sig = sig; - r_melt_detail->coin_info.denom_pub = pk; - if (GNUNET_OK != - TALER_test_coin_valid (&r_melt_detail->coin_info)) - { - TMH_PARSE_release_data (spec); - r_melt_detail->coin_info.denom_sig.rsa_signature = NULL; - r_melt_detail->coin_info.denom_pub.rsa_public_key = NULL; - return (MHD_YES == - TMH_RESPONSE_reply_signature_invalid (connection, - "denom_sig")) - ? GNUNET_NO : GNUNET_SYSERR; - } - r_melt_detail->melt_sig = melt_sig; - r_melt_detail->melt_amount_with_fee = amount; - TMH_PARSE_release_data (spec); - return GNUNET_OK; -} - - -/** - * Verify that the signature shows that this coin is to be melted into - * the given @a session_pub melting session, and that this is a valid - * coin (we know the denomination key and the signature on it is - * valid). Essentially, this does all of the per-coin checks that can - * be done before the transaction starts. - * - * @param connection the connection to send error responses to - * @param session_hash hash over refresh session the coin is melted into - * @param melt_detail details about the coin's melting permission (if valid) - * @return #GNUNET_YES if coin public info in JSON was valid - * #GNUNET_NO JSON was invalid, response was generated - * #GNUNET_SYSERR on internal error - */ -static int -verify_coin_public_info (struct MHD_Connection *connection, - const struct GNUNET_HashCode *session_hash, - const struct TMH_DB_MeltDetails *melt_detail) -{ - struct TALER_RefreshMeltCoinAffirmationPS body; - struct TMH_KS_StateHandle *key_state; - struct TALER_MINTDB_DenominationKeyIssueInformation *dki; - struct TALER_Amount fee_refresh; - - key_state = TMH_KS_acquire (); - dki = TMH_KS_denomination_key_lookup (key_state, - &melt_detail->coin_info.denom_pub, - TMH_KS_DKU_DEPOSIT); - if (NULL == dki) - { - TMH_KS_release (key_state); - TALER_LOG_WARNING ("Unknown denomination key in /refresh/melt request\n"); - return TMH_RESPONSE_reply_arg_unknown (connection, - "denom_pub"); - } - /* FIXME: need to check if denomination key is still - valid for issuing! (#3634) */ - TALER_amount_ntoh (&fee_refresh, - &dki->issue.properties.fee_refresh); - body.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS)); - body.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT); - body.session_hash = *session_hash; - TALER_amount_hton (&body.amount_with_fee, - &melt_detail->melt_amount_with_fee); - TALER_amount_hton (&body.melt_fee, - &fee_refresh); - body.coin_pub = melt_detail->coin_info.coin_pub; - if (TALER_amount_cmp (&fee_refresh, - &melt_detail->melt_amount_with_fee) < 0) - { - TMH_KS_release (key_state); - return (MHD_YES == - TMH_RESPONSE_reply_external_error (connection, - "melt amount smaller than melting fee")) - ? GNUNET_NO : GNUNET_SYSERR; - } - - TMH_KS_release (key_state); - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT, - &body.purpose, - &melt_detail->melt_sig.eddsa_signature, - &melt_detail->coin_info.coin_pub.eddsa_pub)) - { - if (MHD_YES != - TMH_RESPONSE_reply_signature_invalid (connection, - "confirm_sig")) - return GNUNET_SYSERR; - return GNUNET_NO; - } - return GNUNET_OK; -} - - -/** - * Release memory from the @a commit_coin array. - * - * @param commit_coin array to release - * @param kappa size of 1st dimension - * @param num_new_coins size of 2nd dimension - */ -static void -free_commit_coins (struct TALER_MINTDB_RefreshCommitCoin **commit_coin, - unsigned int kappa, - unsigned int num_new_coins) -{ - unsigned int i; - unsigned int j; - - for (i=0;i<kappa;i++) - { - if (NULL == commit_coin[i]) - break; - for (j=0;j<num_new_coins;j++) - { - GNUNET_free_non_null (commit_coin[i][j].coin_ev); - GNUNET_free_non_null (commit_coin[i][j].refresh_link); - } - GNUNET_free (commit_coin[i]); - } -} - - -/** - * Release memory from the @a commit_link array. - * - * @param commit_link array to release - * @param kappa size of 1st dimension - * @param num_old_coins size of 2nd dimension - */ -static void -free_commit_links (struct TALER_MINTDB_RefreshCommitLinkP **commit_link, - unsigned int kappa, - unsigned int num_old_coins) -{ - unsigned int i; - - for (i=0;i<kappa;i++) - { - if (NULL == commit_link[i]) - break; - GNUNET_free (commit_link[i]); - } -} - - -/** - * Handle a "/refresh/melt" request after the first parsing has happened. - * We now need to validate the coins being melted and the session signature - * and then hand things of to execute the melt operation. This function - * parses the JSON arrays and then passes processing on to - * #handle_refresh_melt_binary(). - * - * @param connection the MHD connection to handle - * @param new_denoms array of denomination keys - * @param melt_coins array of coins to melt - * @param num_oldcoins number of coins that are being melted - * @param transfer_pubs #TALER_CNC_KAPPA-dimensional array of @a num_oldcoins transfer keys - * @param secret_encs #TALER_CNC_KAPPA-dimensional array of @a num_oldcoins secrets - * @param num_newcoins number of coins that the refresh will generate - * @param coin_evs #TALER_CNC_KAPPA-dimensional array of @a num_newcoins envelopes to sign - * @param link_encs #TALER_CNC_KAPPA-dimensional array of @a num_newcoins encrypted links - * @return MHD result code - */ -static int -handle_refresh_melt_json (struct MHD_Connection *connection, - const json_t *new_denoms, - const json_t *melt_coins, - unsigned int num_oldcoins, - const json_t *transfer_pubs, - const json_t *secret_encs, - unsigned int num_newcoins, - const json_t *coin_evs, - const json_t *link_encs) - -{ - int res; - unsigned int i; - unsigned int j; - struct TALER_DenominationPublicKey *denom_pubs; - unsigned int num_new_denoms; - struct TMH_DB_MeltDetails *coin_melt_details; - unsigned int coin_count; - struct GNUNET_HashCode session_hash; - struct GNUNET_HashContext *hash_context; - struct TALER_MINTDB_RefreshCommitCoin *commit_coin[TALER_CNC_KAPPA]; - struct TALER_MINTDB_RefreshCommitLinkP *commit_link[TALER_CNC_KAPPA]; - - /* For the signature check, we hash most of the inputs together - (except for the signatures on the coins). */ - hash_context = GNUNET_CRYPTO_hash_context_start (); - num_new_denoms = json_array_size (new_denoms); - denom_pubs = GNUNET_malloc (num_new_denoms * - sizeof (struct TALER_DenominationPublicKey)); - for (i=0;i<num_new_denoms;i++) - { - char *buf; - size_t buf_size; - - res = TMH_PARSE_navigate_json (connection, - new_denoms, - TMH_PARSE_JNC_INDEX, (int) i, - TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY, - &denom_pubs[i].rsa_public_key); - if (GNUNET_OK != res) - { - for (j=0;j<i;j++) - GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); - GNUNET_free (denom_pubs); - return res; - } - buf_size = GNUNET_CRYPTO_rsa_public_key_encode (denom_pubs[i].rsa_public_key, - &buf); - GNUNET_CRYPTO_hash_context_read (hash_context, - buf, - buf_size); - GNUNET_free (buf); - } - - coin_count = json_array_size (melt_coins); - coin_melt_details = GNUNET_malloc (coin_count * - sizeof (struct TMH_DB_MeltDetails)); - for (i=0;i<coin_count;i++) - { - /* decode JSON data on coin to melt */ - struct TALER_AmountNBO melt_amount; - - res = get_coin_public_info (connection, - json_array_get (melt_coins, i), - &coin_melt_details[i]); - if (GNUNET_OK != res) - { - for (j=0;j<i;j++) - { - GNUNET_CRYPTO_rsa_public_key_free (coin_melt_details[j].coin_info.denom_pub.rsa_public_key); - GNUNET_CRYPTO_rsa_signature_free (coin_melt_details[j].coin_info.denom_sig.rsa_signature); - } - for (j=0;j<num_new_denoms;j++) - GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); - GNUNET_free (coin_melt_details); - GNUNET_free (denom_pubs); - return (GNUNET_NO == res) ? MHD_YES : MHD_NO; - } - /* Check that the client does not try to melt the same coin twice - into the same session! */ - for (j=0;j<i;j++) - { - if (0 == memcmp (&coin_melt_details[i].coin_info.coin_pub, - &coin_melt_details[j].coin_info.coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP))) - { - for (j=0;j<i;j++) - { - GNUNET_CRYPTO_rsa_public_key_free (coin_melt_details[j].coin_info.denom_pub.rsa_public_key); - GNUNET_CRYPTO_rsa_signature_free (coin_melt_details[j].coin_info.denom_sig.rsa_signature); - } - for (j=0;j<num_new_denoms;j++) - GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); - GNUNET_free (coin_melt_details); - GNUNET_free (denom_pubs); - return TMH_RESPONSE_reply_external_error (connection, - "melting same coin twice in same session is not allowed"); - } - } - TALER_amount_hton (&melt_amount, - &coin_melt_details[i].melt_amount_with_fee); - GNUNET_CRYPTO_hash_context_read (hash_context, - &coin_melt_details[i].coin_info.coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP)); - GNUNET_CRYPTO_hash_context_read (hash_context, - &melt_amount, - sizeof (struct TALER_AmountNBO)); - - } - - /* parse JSON arrays into 2d binary arrays and hash everything - together for the signature check */ - memset (commit_coin, 0, sizeof (commit_coin)); - memset (commit_link, 0, sizeof (commit_link)); - for (i = 0; i < TALER_CNC_KAPPA; i++) - { - commit_coin[i] = GNUNET_malloc (num_newcoins * - sizeof (struct TALER_MINTDB_RefreshCommitCoin)); - for (j = 0; j < num_newcoins; j++) - { - char *link_enc; - size_t link_enc_size; - struct TALER_MINTDB_RefreshCommitCoin *rcc = &commit_coin[i][j]; - - res = TMH_PARSE_navigate_json (connection, - coin_evs, - TMH_PARSE_JNC_INDEX, (int) i, - TMH_PARSE_JNC_INDEX, (int) j, - TMH_PARSE_JNC_RET_DATA_VAR, - &rcc->coin_ev, - &rcc->coin_ev_size); - - if (GNUNET_OK != res) - { - GNUNET_CRYPTO_hash_context_abort (hash_context); - free_commit_coins (commit_coin, - TALER_CNC_KAPPA, - num_newcoins); - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - } - GNUNET_CRYPTO_hash_context_read (hash_context, - rcc->coin_ev, - rcc->coin_ev_size); - res = TMH_PARSE_navigate_json (connection, - link_encs, - TMH_PARSE_JNC_INDEX, (int) i, - TMH_PARSE_JNC_INDEX, (int) j, - TMH_PARSE_JNC_RET_DATA_VAR, - &link_enc, - &link_enc_size); - if (GNUNET_OK != res) - { - GNUNET_CRYPTO_hash_context_abort (hash_context); - free_commit_coins (commit_coin, - TALER_CNC_KAPPA, - num_newcoins); - GNUNET_free (link_enc); - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - } - rcc->refresh_link - = TALER_refresh_link_encrypted_decode (link_enc, - link_enc_size); - GNUNET_CRYPTO_hash_context_read (hash_context, - link_enc, - link_enc_size); - GNUNET_free (link_enc); - } - } - - for (i = 0; i < TALER_CNC_KAPPA; i++) - { - commit_link[i] = GNUNET_malloc (num_oldcoins * - sizeof (struct TALER_MINTDB_RefreshCommitLinkP)); - for (j = 0; j < num_oldcoins; j++) - { - struct TALER_MINTDB_RefreshCommitLinkP *rcl = &commit_link[i][j]; - - res = TMH_PARSE_navigate_json (connection, - transfer_pubs, - TMH_PARSE_JNC_INDEX, (int) i, - TMH_PARSE_JNC_INDEX, (int) j, - TMH_PARSE_JNC_RET_DATA, - &rcl->transfer_pub, - sizeof (struct TALER_TransferPublicKeyP)); - - if (GNUNET_OK != res) - { - GNUNET_break (GNUNET_SYSERR != res); - GNUNET_CRYPTO_hash_context_abort (hash_context); - free_commit_coins (commit_coin, - TALER_CNC_KAPPA, - num_newcoins); - free_commit_links (commit_link, - TALER_CNC_KAPPA, - num_oldcoins); - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - } - res = TMH_PARSE_navigate_json (connection, - secret_encs, - TMH_PARSE_JNC_INDEX, (int) i, - TMH_PARSE_JNC_INDEX, (int) j, - TMH_PARSE_JNC_RET_DATA, - &rcl->shared_secret_enc, - sizeof (struct TALER_EncryptedLinkSecretP)); - - if (GNUNET_OK != res) - { - GNUNET_break (GNUNET_SYSERR != res); - GNUNET_CRYPTO_hash_context_abort (hash_context); - free_commit_coins (commit_coin, - TALER_CNC_KAPPA, - num_newcoins); - free_commit_links (commit_link, - TALER_CNC_KAPPA, - num_oldcoins); - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - } - - GNUNET_CRYPTO_hash_context_read (hash_context, - rcl, - sizeof (struct TALER_MINTDB_RefreshCommitLinkP)); - } - - } - GNUNET_CRYPTO_hash_context_finish (hash_context, - &session_hash); - - for (i=0;i<coin_count;i++) - { - /* verify signatures on coins to melt */ - res = verify_coin_public_info (connection, - &session_hash, - &coin_melt_details[i]); - if (GNUNET_OK != res) - { - res = (GNUNET_NO == res) ? MHD_YES : MHD_NO; - goto cleanup; - } - } - - /* execute commit */ - res = handle_refresh_melt_binary (connection, - num_new_denoms, - denom_pubs, - coin_count, - coin_melt_details, - &session_hash, - commit_coin, - commit_link); - cleanup: - free_commit_coins (commit_coin, - TALER_CNC_KAPPA, - num_newcoins); - free_commit_links (commit_link, - TALER_CNC_KAPPA, - num_oldcoins); - for (j=0;j<coin_count;j++) - { - GNUNET_CRYPTO_rsa_public_key_free (coin_melt_details[j].coin_info.denom_pub.rsa_public_key); - GNUNET_CRYPTO_rsa_signature_free (coin_melt_details[j].coin_info.denom_sig.rsa_signature); - } - for (j=0;j<num_new_denoms;j++) - GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); - GNUNET_free (coin_melt_details); - GNUNET_free (denom_pubs); - return res; -} - - -/** - * Handle a "/refresh/melt" request. Parses the request into the JSON - * components and then hands things of to #handle_refresh_melt_json() - * to validate the melted coins, the signature and execute the melt - * using TMH_DB_execute_refresh_melt(). - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_REFRESH_handler_refresh_melt (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - json_t *root; - json_t *new_denoms; - json_t *melt_coins; - json_t *coin_evs; - json_t *link_encs; - json_t *transfer_pubs; - json_t *secret_encs; - unsigned int num_oldcoins; - unsigned int num_newcoins; - json_t *coin_detail; - int res; - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_array ("new_denoms", &new_denoms), - TMH_PARSE_member_array ("melt_coins", &melt_coins), - TMH_PARSE_member_array ("coin_evs", &coin_evs), - TMH_PARSE_member_array ("link_encs", &link_encs), - TMH_PARSE_member_array ("transfer_pubs", &transfer_pubs), - TMH_PARSE_member_array ("secret_encs", &secret_encs), - TMH_PARSE_MEMBER_END - }; - - res = TMH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &root); - if (GNUNET_SYSERR == res) - return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == root) ) - return MHD_YES; - - res = TMH_PARSE_json_data (connection, - root, - spec); - json_decref (root); - if (GNUNET_OK != res) - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - - /* Determine dimensionality of the request (kappa, #old and #new coins) */ - if (TALER_CNC_KAPPA != json_array_size (coin_evs)) - { - GNUNET_break_op (0); - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_arg_invalid (connection, - "coin_evs"); - } - if (TALER_CNC_KAPPA != json_array_size (transfer_pubs)) - { - GNUNET_break_op (0); - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_arg_invalid (connection, - "transfer_pubs"); - } - res = TMH_PARSE_navigate_json (connection, coin_evs, - TMH_PARSE_JNC_INDEX, (int) 0, - TMH_PARSE_JNC_RET_DATA, - JSON_ARRAY, &coin_detail); - if (GNUNET_OK != res) - { - TMH_PARSE_release_data (spec); - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - } - num_newcoins = json_array_size (coin_detail); - res = TMH_PARSE_navigate_json (connection, - transfer_pubs, - TMH_PARSE_JNC_INDEX, (int) 0, - TMH_PARSE_JNC_RET_DATA, - JSON_ARRAY, &coin_detail); - if (GNUNET_OK != res) - { - TMH_PARSE_release_data (spec); - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - } - num_oldcoins = json_array_size (coin_detail); - - res = handle_refresh_melt_json (connection, - new_denoms, - melt_coins, - num_oldcoins, - transfer_pubs, - secret_encs, - num_newcoins, - coin_evs, - link_encs); - - TMH_PARSE_release_data (spec); - return res; -} - - -/** - * Handle a "/refresh/reveal" request. Parses the given JSON - * transfer private keys and if successful, passes everything to - * #TMH_DB_execute_refresh_reveal() which will verify that the - * revealed information is valid then returns the signed refreshed - * coins. - * - * @param connection the MHD connection to handle - * @param session_hash hash identifying the melting session - * @param num_oldcoins length of the 2nd dimension of @a transfer_privs array - * @param tp_json private transfer keys in JSON format - * @return MHD result code - */ -static int -handle_refresh_reveal_json (struct MHD_Connection *connection, - const struct GNUNET_HashCode *session_hash, - unsigned int num_oldcoins, - const json_t *tp_json) -{ - struct TALER_TransferPrivateKeyP *transfer_privs[TALER_CNC_KAPPA - 1]; - unsigned int i; - unsigned int j; - int res; - - for (i = 0; i < TALER_CNC_KAPPA - 1; i++) - transfer_privs[i] = GNUNET_malloc (num_oldcoins * - sizeof (struct TALER_TransferPrivateKeyP)); - res = GNUNET_OK; - for (i = 0; i < TALER_CNC_KAPPA - 1; i++) - { - if (GNUNET_OK != res) - break; - for (j = 0; j < num_oldcoins; j++) - { - if (GNUNET_OK != res) - break; - res = TMH_PARSE_navigate_json (connection, - tp_json, - TMH_PARSE_JNC_INDEX, (int) i, - TMH_PARSE_JNC_INDEX, (int) j, - TMH_PARSE_JNC_RET_DATA, - &transfer_privs[i][j], - sizeof (struct TALER_TransferPrivateKeyP)); - } - } - if (GNUNET_OK != res) - res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - else - res = TMH_DB_execute_refresh_reveal (connection, - session_hash, - num_oldcoins, - transfer_privs); - for (i = 0; i < TALER_CNC_KAPPA - 1; i++) - GNUNET_free (transfer_privs[i]); - return res; -} - - -/** - * Handle a "/refresh/reveal" request. This time, the client reveals - * the private transfer keys except for the cut-and-choose value - * returned from "/refresh/melt". This function parses the revealed - * keys and secrets and ultimately passes everything to - * #TMH_DB_execute_refresh_reveal() which will verify that the - * revealed information is valid then returns the signed refreshed - * coins. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_REFRESH_handler_refresh_reveal (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - struct GNUNET_HashCode session_hash; - int res; - unsigned int num_oldcoins; - json_t *reveal_detail; - json_t *root; - json_t *transfer_privs; - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_fixed ("session_hash", &session_hash), - TMH_PARSE_member_array ("transfer_privs", &transfer_privs), - TMH_PARSE_MEMBER_END - }; - - res = TMH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &root); - if (GNUNET_SYSERR == res) - return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == root) ) - return MHD_YES; - - res = TMH_PARSE_json_data (connection, - root, - spec); - json_decref (root); - if (GNUNET_OK != res) - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - - /* Determine dimensionality of the request (kappa and #old coins) */ - /* Note we do +1 as 1 row (cut-and-choose!) is missing! */ - if (TALER_CNC_KAPPA != json_array_size (transfer_privs) + 1) - { - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_arg_invalid (connection, - "transfer_privs"); - } - res = TMH_PARSE_navigate_json (connection, - transfer_privs, - TMH_PARSE_JNC_INDEX, 0, - TMH_PARSE_JNC_RET_TYPED_JSON, - JSON_ARRAY, - &reveal_detail); - if (GNUNET_OK != res) - { - TMH_PARSE_release_data (spec); - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - } - num_oldcoins = json_array_size (reveal_detail); - res = handle_refresh_reveal_json (connection, - &session_hash, - num_oldcoins, - transfer_privs); - TMH_PARSE_release_data (spec); - return res; -} - - -/** - * Handle a "/refresh/link" request. Note that for "/refresh/link" - * we do use a simple HTTP GET, and a HTTP POST! - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_REFRESH_handler_refresh_link (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - struct TALER_CoinSpendPublicKeyP coin_pub; - int res; - - res = TMH_PARSE_mhd_request_arg_data (connection, - "coin_pub", - &coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP)); - if (GNUNET_SYSERR == res) - return MHD_NO; - if (GNUNET_OK != res) - return MHD_YES; - return TMH_DB_execute_refresh_link (connection, - &coin_pub); -} - - -/* end of taler-mint-httpd_refresh.c */ diff --git a/src/backend/taler-mint-httpd_refresh.h b/src/backend/taler-mint-httpd_refresh.h deleted file mode 100644 index 8fe12a27..00000000 --- a/src/backend/taler-mint-httpd_refresh.h +++ /dev/null @@ -1,94 +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 Affero 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 Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_refresh.h - * @brief Handle /refresh/ requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#ifndef TALER_MINT_HTTPD_REFRESH_H -#define TALER_MINT_HTTPD_REFRESH_H - -#include <gnunet/gnunet_util_lib.h> -#include <microhttpd.h> -#include "taler-mint-httpd.h" - - -/** - * Handle a "/refresh/melt" request. Parses the request into the JSON - * components and then hands things of to #handle_refresh_melt_json() - * to validate the melted coins, the signature and execute the melt - * using TMH_DB_execute_refresh_melt(). - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_REFRESH_handler_refresh_melt (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -/** - * Handle a "/refresh/reveal" request. This time, the client reveals - * the private transfer keys except for the cut-and-choose value - * returned from "/refresh/commit". This function parses the revealed - * keys and secrets and ultimately passes everything to - * #TMH_DB_execute_refresh_reveal() which will verify that the - * revealed information is valid then returns the signed refreshed - * coins. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_REFRESH_handler_refresh_reveal (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -/** - * Handle a "/refresh/link" request - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_REFRESH_handler_refresh_link (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -#endif diff --git a/src/backend/taler-mint-httpd_responses.c b/src/backend/taler-mint-httpd_responses.c index 57b233e7..a2a49c03 100644 --- a/src/backend/taler-mint-httpd_responses.c +++ b/src/backend/taler-mint-httpd_responses.c @@ -26,7 +26,6 @@ #include "taler-mint-httpd_responses.h" #include "taler_util.h" #include <gnunet/gnunet_util_lib.h> -#include "taler-mint-httpd_keystate.h" /** @@ -107,104 +106,6 @@ TMH_RESPONSE_reply_json_pack (struct MHD_Connection *connection, return ret; } - -/** - * Send a response indicating an invalid argument. - * - * @param connection the MHD connection to use - * @param param_name the parameter that is invalid - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection, - const char *param_name) -{ - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:s}", - "error", "invalid parameter", - "parameter", param_name); -} - - -/** - * Send a response indicating an argument refering to a - * resource unknown to the mint (i.e. unknown reserve or - * denomination key). - * - * @param connection the MHD connection to use - * @param param_name the parameter that is invalid - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection, - const char *param_name) -{ - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_NOT_FOUND, - "{s:s, s:s}", - "error", "unknown entity referenced", - "parameter", param_name); -} - - -/** - * Send a response indicating an invalid signature. - * - * @param connection the MHD connection to use - * @param param_name the parameter that is invalid - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection, - const char *param_name) -{ - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_UNAUTHORIZED, - "{s:s, s:s}", - "error", "invalid signature", - "parameter", param_name); -} - - -/** - * Send a response indicating a missing argument. - * - * @param connection the MHD connection to use - * @param param_name the parameter that is missing - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection, - const char *param_name) -{ - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{ s:s, s:s}", - "error", "missing parameter", - "parameter", param_name); -} - - -/** - * Send a response indicating permission denied. - * - * @param connection the MHD connection to use - * @param hint hint about why access was denied - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection, - const char *hint) -{ - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_FORBIDDEN, - "{s:s, s:s}", - "error", "permission denied", - "hint", hint); -} - - /** * Send a response indicating an internal error. * @@ -223,58 +124,6 @@ TMH_RESPONSE_reply_internal_error (struct MHD_Connection *connection, "hint", hint); } - -/** - * Send a response indicating an external error. - * - * @param connection the MHD connection to use - * @param hint hint about the error's nature - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_external_error (struct MHD_Connection *connection, - const char *hint) -{ - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:s}", - "error", "client error", - "hint", hint); -} - - -/** - * Send a response indicating an error committing a - * transaction (concurrent interference). - * - * @param connection the MHD connection to use - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_commit_error (struct MHD_Connection *connection) -{ - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s}", - "error", "commit failure"); -} - - -/** - * Send a response indicating a failure to talk to the Mint's - * database. - * - * @param connection the MHD connection to use - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection) -{ - return TMH_RESPONSE_reply_internal_error (connection, - "Failed to connect to database"); -} - - /** * Send a response indicating that the request was too big. * @@ -316,682 +165,4 @@ TMH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection) "invalid json"); } - -/** - * Send confirmation of deposit success to client. This function - * will create a signed message affirming the given information - * and return it to the client. By this, the mint affirms that - * the coin had sufficient (residual) value for the specified - * transaction and that it will execute the requested deposit - * operation with the given wiring details. - * - * @param connection connection to the client - * @param coin_pub public key of the coin - * @param h_wire hash of wire details - * @param h_contract hash of contract details - * @param transaction_id transaction ID - * @param timestamp client's timestamp - * @param refund_deadline until when this deposit be refunded - * @param merchant merchant public key - * @param amount_without_fee fraction of coin value to deposit, without the fee - * @return MHD result code - */ -int -TMH_RESPONSE_reply_deposit_success (struct MHD_Connection *connection, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - const struct GNUNET_HashCode *h_wire, - const struct GNUNET_HashCode *h_contract, - uint64_t transaction_id, - struct GNUNET_TIME_Absolute timestamp, - struct GNUNET_TIME_Absolute refund_deadline, - const struct TALER_MerchantPublicKeyP *merchant, - const struct TALER_Amount *amount_without_fee) -{ - struct TALER_DepositConfirmationPS dc; - struct TALER_MintPublicKeyP pub; - struct TALER_MintSignatureP sig; - - dc.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_DEPOSIT); - dc.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS)); - dc.h_contract = *h_contract; - dc.h_wire = *h_wire; - dc.transaction_id = GNUNET_htonll (transaction_id); - dc.timestamp = GNUNET_TIME_absolute_hton (timestamp); - dc.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline); - TALER_amount_hton (&dc.amount_without_fee, - amount_without_fee); - dc.coin_pub = *coin_pub; - dc.merchant = *merchant; - TMH_KS_sign (&dc.purpose, - &pub, - &sig); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:s, s:o, s:o}", - "status", "DEPOSIT_OK", - "sig", TALER_json_from_data (&sig, - sizeof (sig)), - "pub", TALER_json_from_data (&pub, - sizeof (pub))); -} - - -/** - * Compile the transaction history of a coin into a JSON object. - * - * @param tl transaction history to JSON-ify - * @return json representation of the @a rh - */ -static json_t * -compile_transaction_history (const struct TALER_MINTDB_TransactionList *tl) -{ - json_t *transaction; - const char *type; - struct TALER_Amount value; - json_t *history; - const struct TALER_MINTDB_TransactionList *pos; - - history = json_array (); - for (pos = tl; NULL != pos; pos = pos->next) - { - switch (pos->type) - { - case TALER_MINTDB_TT_DEPOSIT: - { - struct TALER_DepositRequestPS dr; - const struct TALER_MINTDB_Deposit *deposit = pos->details.deposit; - - type = "deposit"; - value = deposit->amount_with_fee; - dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT); - dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS)); - dr.h_contract = deposit->h_contract; - dr.h_wire = deposit->h_wire; - dr.timestamp = GNUNET_TIME_absolute_hton (deposit->timestamp); - dr.refund_deadline = GNUNET_TIME_absolute_hton (deposit->refund_deadline); - dr.transaction_id = GNUNET_htonll (deposit->transaction_id); - TALER_amount_hton (&dr.amount_with_fee, - &deposit->amount_with_fee); - TALER_amount_hton (&dr.deposit_fee, - &deposit->deposit_fee); - dr.merchant = deposit->merchant_pub; - dr.coin_pub = deposit->coin.coin_pub; - transaction = TALER_json_from_eddsa_sig (&dr.purpose, - &deposit->csig.eddsa_signature); - break; - } - case TALER_MINTDB_TT_REFRESH_MELT: - { - struct TALER_RefreshMeltCoinAffirmationPS ms; - const struct TALER_MINTDB_RefreshMelt *melt = pos->details.melt; - - type = "melt"; - value = melt->amount_with_fee; - ms.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT); - ms.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS)); - ms.session_hash = melt->session_hash; - TALER_amount_hton (&ms.amount_with_fee, - &melt->amount_with_fee); - TALER_amount_hton (&ms.melt_fee, - &melt->melt_fee); - ms.coin_pub = melt->coin.coin_pub; - transaction = TALER_json_from_eddsa_sig (&ms.purpose, - &melt->coin_sig.eddsa_signature); - } - break; - case TALER_MINTDB_TT_LOCK: - { - type = "lock"; - value = pos->details.lock->amount; - transaction = NULL; - GNUNET_break (0); /* #3625: Lock NOT implemented! */ - break; - } - default: - GNUNET_assert (0); - } - json_array_append_new (history, - json_pack ("{s:s, s:o, s:o}", - "type", type, - "amount", TALER_json_from_amount (&value), - "signature", transaction)); - } - return history; -} - - -/** - * Send proof that a /deposit request is invalid to client. This - * function will create a message with all of the operations affecting - * the coin that demonstrate that the coin has insufficient value. - * - * @param connection connection to the client - * @param tl transaction list to use to build reply - * @return MHD result code - */ -int -TMH_RESPONSE_reply_deposit_insufficient_funds (struct MHD_Connection *connection, - const struct TALER_MINTDB_TransactionList *tl) -{ - json_t *history; - - history = compile_transaction_history (tl); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_FORBIDDEN, - "{s:s, s:o}", - "error", "insufficient funds", - "history", history); -} - - -/** - * Compile the history of a reserve into a JSON object - * and calculate the total balance. - * - * @param rh reserve history to JSON-ify - * @param[out] balance set to current reserve balance - * @return json representation of the @a rh, NULL on error - */ -static json_t * -compile_reserve_history (const struct TALER_MINTDB_ReserveHistory *rh, - struct TALER_Amount *balance) -{ - struct TALER_Amount deposit_total; - struct TALER_Amount withdraw_total; - struct TALER_Amount value; - json_t *json_history; - json_t *transaction; - int ret; - const struct TALER_MINTDB_ReserveHistory *pos; - struct TALER_WithdrawRequestPS wr; - - json_history = json_array (); - ret = 0; - for (pos = rh; NULL != pos; pos = pos->next) - { - switch (pos->type) - { - case TALER_MINTDB_RO_BANK_TO_MINT: - if (0 == ret) - deposit_total = pos->details.bank->amount; - else - if (GNUNET_OK != - TALER_amount_add (&deposit_total, - &deposit_total, - &pos->details.bank->amount)) - { - json_decref (json_history); - return NULL; - } - ret = 1; - json_array_append_new (json_history, - json_pack ("{s:s, s:O, s:o}", - "type", "DEPOSIT", - "wire", pos->details.bank->wire, - "amount", TALER_json_from_amount (&pos->details.bank->amount))); - break; - case TALER_MINTDB_RO_WITHDRAW_COIN: - break; - } - } - - ret = 0; - for (pos = rh; NULL != pos; pos = pos->next) - { - switch (pos->type) - { - case TALER_MINTDB_RO_BANK_TO_MINT: - break; - case TALER_MINTDB_RO_WITHDRAW_COIN: - value = pos->details.withdraw->amount_with_fee; - if (0 == ret) - { - withdraw_total = value; - } - else - { - if (GNUNET_OK != - TALER_amount_add (&withdraw_total, - &withdraw_total, - &value)) - { - json_decref (json_history); - return NULL; - } - } - ret = 1; - wr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW); - wr.purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS)); - wr.reserve_pub = pos->details.withdraw->reserve_pub; - TALER_amount_hton (&wr.amount_with_fee, - &value); - TALER_amount_hton (&wr.withdraw_fee, - &pos->details.withdraw->withdraw_fee); - GNUNET_CRYPTO_rsa_public_key_hash (pos->details.withdraw->denom_pub.rsa_public_key, - &wr.h_denomination_pub); - wr.h_coin_envelope = pos->details.withdraw->h_coin_envelope; - - transaction = TALER_json_from_eddsa_sig (&wr.purpose, - &pos->details.withdraw->reserve_sig.eddsa_signature); - - json_array_append_new (json_history, - json_pack ("{s:s, s:o, s:o}", - "type", "WITHDRAW", - "signature", transaction, - "amount", TALER_json_from_amount (&value))); - break; - } - } - if (0 == ret) - { - /* did not encounter any withdraw operations, set to zero */ - TALER_amount_get_zero (deposit_total.currency, - &withdraw_total); - } - if (GNUNET_SYSERR == - TALER_amount_subtract (balance, - &deposit_total, - &withdraw_total)) - { - GNUNET_break (0); - json_decref (json_history); - return NULL; - } - - return json_history; -} - - -/** - * Send reserve status information to client. - * - * @param connection connection to the client - * @param rh reserve history to return - * @return MHD result code - */ -int -TMH_RESPONSE_reply_withdraw_status_success (struct MHD_Connection *connection, - const struct TALER_MINTDB_ReserveHistory *rh) -{ - json_t *json_balance; - json_t *json_history; - struct TALER_Amount balance; - - json_history = compile_reserve_history (rh, - &balance); - if (NULL == json_history) - return TMH_RESPONSE_reply_internal_error (connection, - "balance calculation failure"); - json_balance = TALER_json_from_amount (&balance); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o, s:o}", - "balance", json_balance, - "history", json_history); -} - - -/** - * Send reserve status information to client with the - * message that we have insufficient funds for the - * requested /withdraw/sign operation. - * - * @param connection connection to the client - * @param rh reserve history to return - * @return MHD result code - */ -int -TMH_RESPONSE_reply_withdraw_sign_insufficient_funds (struct MHD_Connection *connection, - const struct TALER_MINTDB_ReserveHistory *rh) -{ - json_t *json_balance; - json_t *json_history; - struct TALER_Amount balance; - - json_history = compile_reserve_history (rh, - &balance); - if (NULL == json_history) - return TMH_RESPONSE_reply_internal_error (connection, - "balance calculation failure"); - json_balance = TALER_json_from_amount (&balance); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_PAYMENT_REQUIRED, - "{s:s, s:o, s:o}", - "error", "Insufficient funds", - "balance", json_balance, - "history", json_history); -} - - -/** - * Send blinded coin information to client. - * - * @param connection connection to the client - * @param collectable blinded coin to return - * @return MHD result code - */ -int -TMH_RESPONSE_reply_withdraw_sign_success (struct MHD_Connection *connection, - const struct TALER_MINTDB_CollectableBlindcoin *collectable) -{ - json_t *sig_json; - - sig_json = TALER_json_from_rsa_signature (collectable->sig.rsa_signature); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o}", - "ev_sig", sig_json); -} - - -/** - * Send a response for a failed "/refresh/melt" request. The - * transaction history of the given coin demonstrates that the - * @a residual value of the coin is below the @a requested - * contribution of the coin for the melt. Thus, the mint - * refuses the melt operation. - * - * @param connection the connection to send the response to - * @param coin_pub public key of the coin - * @param coin_value original value of the coin - * @param tl transaction history for the coin - * @param requested how much this coin was supposed to contribute - * @param residual remaining value of the coin (after subtracting @a tl) - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_refresh_melt_insufficient_funds (struct MHD_Connection *connection, - const struct TALER_CoinSpendPublicKeyP *coin_pub, - struct TALER_Amount coin_value, - struct TALER_MINTDB_TransactionList *tl, - struct TALER_Amount requested, - struct TALER_Amount residual) -{ - json_t *history; - - history = compile_transaction_history (tl); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_NOT_FOUND, - "{s:s, s:o, s:o, s:o, s:o, s:o}", - "error", "insufficient funds", - "coin-pub", TALER_json_from_data (coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP)), - "original-value", TALER_json_from_amount (&coin_value), - "residual-value", TALER_json_from_amount (&residual), - "requested-value", TALER_json_from_amount (&requested), - "history", history); -} - - -/** - * Send a response to a "/refresh/melt" request. - * - * @param connection the connection to send the response to - * @param session_hash hash of the refresh session - * @param noreveal_index which index will the client not have to reveal - * @return a MHD status code - */ -int -TMH_RESPONSE_reply_refresh_melt_success (struct MHD_Connection *connection, - const struct GNUNET_HashCode *session_hash, - uint16_t noreveal_index) -{ - struct TALER_RefreshMeltConfirmationPS body; - struct TALER_MintPublicKeyP pub; - struct TALER_MintSignatureP sig; - json_t *sig_json; - - body.purpose.size = htonl (sizeof (struct TALER_RefreshMeltConfirmationPS)); - body.purpose.purpose = htonl (TALER_SIGNATURE_MINT_CONFIRM_MELT); - body.session_hash = *session_hash; - body.noreveal_index = htons (noreveal_index); - TMH_KS_sign (&body.purpose, - &pub, - &sig); - sig_json = TALER_json_from_data (&sig, - sizeof (sig)); - GNUNET_assert (NULL != sig_json); - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:i, s:o, s:o}", - "noreveal_index", (int) noreveal_index, - "mint_sig", sig_json, - "mint_pub", TALER_json_from_data (&pub, - sizeof (pub))); -} - - -/** - * Send a response for "/refresh/reveal". - * - * @param connection the connection to send the response to - * @param num_newcoins number of new coins for which we reveal data - * @param sigs array of @a num_newcoins signatures revealed - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_refresh_reveal_success (struct MHD_Connection *connection, - unsigned int num_newcoins, - const struct TALER_DenominationSignature *sigs) -{ - int newcoin_index; - json_t *root; - json_t *list; - int ret; - - root = json_object (); - list = json_array (); - json_object_set_new (root, - "ev_sigs", - list); - for (newcoin_index = 0; newcoin_index < num_newcoins; newcoin_index++) - json_array_append_new (list, - TALER_json_from_rsa_signature (sigs[newcoin_index].rsa_signature)); - ret = TMH_RESPONSE_reply_json (connection, - root, - MHD_HTTP_OK); - json_decref (root); - return ret; -} - - -/** - * Send a response for a failed "/refresh/reveal", where the - * revealed value(s) do not match the original commitment. - * - * @param connection the connection to send the response to - * @param mc all information about the original commitment - * @param off offset in the array of kappa-commitments where - * the missmatch was detected - * @param j index of the coin for which the missmatch was - * detected - * @param missmatch_object name of the object that was - * bogus (i.e. "transfer key"). - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_refresh_reveal_missmatch (struct MHD_Connection *connection, - const struct TALER_MINTDB_MeltCommitment *mc, - unsigned int off, - unsigned int j, - const char *missmatch_object) -{ - json_t *info_old; - json_t *info_new; - json_t *info_commit; - json_t *info_links; - unsigned int i; - unsigned int k; - - info_old = json_array (); - for (i=0;i<mc->num_oldcoins;i++) - { - const struct TALER_MINTDB_RefreshMelt *rm; - json_t *rm_json; - - rm = &mc->melts[i]; - rm_json = json_object (); - json_object_set_new (rm_json, - "coin_sig", - TALER_json_from_data (&rm->coin_sig, - sizeof (struct TALER_CoinSpendSignatureP))); - json_object_set_new (rm_json, - "coin_pub", - TALER_json_from_data (&rm->coin.coin_pub, - sizeof (struct TALER_CoinSpendPublicKeyP))); - json_object_set_new (rm_json, - "melt_amount_with_fee", - TALER_json_from_amount (&rm->amount_with_fee)); - json_object_set_new (rm_json, - "melt_fee", - TALER_json_from_amount (&rm->melt_fee)); - json_array_append_new (info_old, - rm_json); - } - info_new = json_array (); - for (i=0;i<mc->num_newcoins;i++) - { - const struct TALER_DenominationPublicKey *pk; - - pk = &mc->denom_pubs[i]; - json_array_append_new (info_new, - TALER_json_from_rsa_public_key (pk->rsa_public_key)); - - } - info_commit = json_array (); - info_links = json_array (); - for (k=0;k<TALER_CNC_KAPPA;k++) - { - json_t *info_commit_k; - json_t *info_link_k; - - info_commit_k = json_array (); - for (i=0;i<mc->num_newcoins;i++) - { - const struct TALER_MINTDB_RefreshCommitCoin *cc; - json_t *cc_json; - - cc = &mc->commit_coins[k][i]; - cc_json = json_object (); - json_object_set_new (cc_json, - "coin_ev", - TALER_json_from_data (cc->coin_ev, - cc->coin_ev_size)); - json_object_set_new (cc_json, - "coin_priv_enc", - TALER_json_from_data (cc->refresh_link->coin_priv_enc, - sizeof (struct TALER_CoinSpendPrivateKeyP))); - json_object_set_new (cc_json, - "blinding_key_enc", - TALER_json_from_data (cc->refresh_link->blinding_key_enc, - cc->refresh_link->blinding_key_enc_size)); - - json_array_append_new (info_commit_k, - cc_json); - } - json_array_append_new (info_commit, - info_commit_k); - info_link_k = json_array (); - for (i=0;i<mc->num_newcoins;i++) - { - const struct TALER_MINTDB_RefreshCommitLinkP *cl; - json_t *cl_json; - - cl = &mc->commit_links[k][i]; - cl_json = json_object (); - json_object_set_new (cl_json, - "transfer_pub", - TALER_json_from_data (&cl->transfer_pub, - sizeof (struct TALER_TransferPublicKeyP))); - json_object_set_new (cl_json, - "shared_secret_enc", - TALER_json_from_data (&cl->shared_secret_enc, - sizeof (struct TALER_EncryptedLinkSecretP))); - json_array_append_new (info_link_k, - cl_json); - } - json_array_append_new (info_links, - info_link_k); - } - return TMH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_CONFLICT, - "{s:s, s:i, s:i, s:o, s:o, s:o, s:o, s:s}", - "error", "commitment violation", - "offset", (int) off, - "index", (int) j, - "oldcoin_infos", info_old, - "newcoin_infos", info_new, - "commit_infos", info_commit, - "link_infos", info_links, - "object", missmatch_object); -} - - -/** - * Send a response for "/refresh/link". - * - * @param connection the connection to send the response to - * @param num_sessions number of sessions the coin was used in - * @param sessions array of @a num_session entries with - * information for each session - * @return a MHD result code - */ -int -TMH_RESPONSE_reply_refresh_link_success (struct MHD_Connection *connection, - unsigned int num_sessions, - const struct TMH_RESPONSE_LinkSessionInfo *sessions) -{ - json_t *root; - json_t *mlist; - int res; - unsigned int i; - - mlist = json_array (); - for (i=0;i<num_sessions;i++) - { - const struct TALER_MINTDB_LinkDataList *pos; - json_t *list = json_array (); - - for (pos = sessions[i].ldl; NULL != pos; pos = pos->next) - { - json_t *obj; - - obj = json_object (); - json_object_set_new (obj, - "link_enc", - TALER_json_from_data (pos->link_data_enc->coin_priv_enc, - sizeof (struct TALER_CoinSpendPrivateKeyP) + - pos->link_data_enc->blinding_key_enc_size)); - json_object_set_new (obj, - "denom_pub", - TALER_json_from_rsa_public_key (pos->denom_pub.rsa_public_key)); - json_object_set_new (obj, - "ev_sig", - TALER_json_from_rsa_signature (pos->ev_sig.rsa_signature)); - json_array_append_new (list, - obj); - } - root = json_object (); - json_object_set_new (root, - "new_coins", - list); - json_object_set_new (root, - "transfer_pub", - TALER_json_from_data (&sessions[i].transfer_pub, - sizeof (struct TALER_TransferPublicKeyP))); - json_object_set_new (root, - "secret_enc", - TALER_json_from_data (&sessions[i].shared_secret_enc, - sizeof (struct TALER_EncryptedLinkSecretP))); - json_array_append_new (mlist, - root); - } - res = TMH_RESPONSE_reply_json (connection, - mlist, - MHD_HTTP_OK); - json_decref (mlist); - return res; -} - - /* end of taler-mint-httpd_responses.c */ diff --git a/src/backend/taler-mint-httpd_withdraw.c b/src/backend/taler-mint-httpd_withdraw.c deleted file mode 100644 index 4f558164..00000000 --- a/src/backend/taler-mint-httpd_withdraw.c +++ /dev/null @@ -1,180 +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 Affero 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 Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_withdraw.c - * @brief Handle /withdraw/ requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include "taler-mint-httpd_withdraw.h" -#include "taler-mint-httpd_parsing.h" -#include "taler-mint-httpd_responses.h" -#include "taler-mint-httpd_keystate.h" - - -/** - * Handle a "/withdraw/status" request. Parses the - * given "reserve_pub" argument (which should contain the - * EdDSA public key of a reserve) and then respond with the - * status of the reserve. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_WITHDRAW_handler_withdraw_status (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - struct TALER_ReservePublicKeyP reserve_pub; - int res; - - res = TMH_PARSE_mhd_request_arg_data (connection, - "reserve_pub", - &reserve_pub, - sizeof (struct TALER_ReservePublicKeyP)); - if (GNUNET_SYSERR == res) - return MHD_NO; /* internal error */ - if (GNUNET_NO == res) - return MHD_YES; /* parse error */ - return TMH_DB_execute_withdraw_status (connection, - &reserve_pub); -} - - -/** - * Handle a "/withdraw/sign" request. Parses the "reserve_pub" - * EdDSA key of the reserve and the requested "denom_pub" which - * specifies the key/value of the coin to be withdrawn, and checks - * that the signature "reserve_sig" makes this a valid withdrawl - * request from the specified reserve. If so, the envelope - * with the blinded coin "coin_ev" is passed down to execute the - * withdrawl operation. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_WITHDRAW_handler_withdraw_sign (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) -{ - json_t *root; - struct TALER_WithdrawRequestPS wsrd; - int res; - struct TALER_DenominationPublicKey denomination_pub; - char *blinded_msg; - size_t blinded_msg_len; - struct TALER_Amount amount; - struct TALER_Amount amount_with_fee; - struct TALER_Amount fee_withdraw; - struct TALER_ReserveSignatureP signature; - struct TALER_MINTDB_DenominationKeyIssueInformation *dki; - struct TMH_KS_StateHandle *ks; - - struct TMH_PARSE_FieldSpecification spec[] = { - TMH_PARSE_member_variable ("coin_ev", (void **) &blinded_msg, &blinded_msg_len), - TMH_PARSE_member_fixed ("reserve_pub", &wsrd.reserve_pub), - TMH_PARSE_member_fixed ("reserve_sig", &signature), - TMH_PARSE_member_denomination_public_key ("denom_pub", &denomination_pub), - TMH_PARSE_MEMBER_END - }; - - res = TMH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &root); - if (GNUNET_SYSERR == res) - return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == root) ) - return MHD_YES; - res = TMH_PARSE_json_data (connection, - root, - spec); - json_decref (root); - if (GNUNET_OK != res) - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - ks = TMH_KS_acquire (); - dki = TMH_KS_denomination_key_lookup (ks, - &denomination_pub, - TMH_KS_DKU_WITHDRAW); - if (NULL == dki) - { - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_arg_unknown (connection, - "denom_pub"); - } - TALER_amount_ntoh (&amount, - &dki->issue.properties.value); - TALER_amount_ntoh (&fee_withdraw, - &dki->issue.properties.fee_withdraw); - GNUNET_assert (GNUNET_OK == - TALER_amount_add (&amount_with_fee, - &amount, - &fee_withdraw)); - TALER_amount_hton (&wsrd.amount_with_fee, - &amount_with_fee); - TALER_amount_hton (&wsrd.withdraw_fee, - &fee_withdraw); - TMH_KS_release (ks); - /* verify signature! */ - wsrd.purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS)); - wsrd.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW); - - GNUNET_CRYPTO_rsa_public_key_hash (denomination_pub.rsa_public_key, - &wsrd.h_denomination_pub); - GNUNET_CRYPTO_hash (blinded_msg, - blinded_msg_len, - &wsrd.h_coin_envelope); - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW, - &wsrd.purpose, - &signature.eddsa_signature, - &wsrd.reserve_pub.eddsa_pub)) - { - TALER_LOG_WARNING ("Client supplied invalid signature for /withdraw/sign request\n"); - TMH_PARSE_release_data (spec); - return TMH_RESPONSE_reply_signature_invalid (connection, - "reserve_sig"); - } - res = TMH_DB_execute_withdraw_sign (connection, - &wsrd.reserve_pub, - &denomination_pub, - blinded_msg, - blinded_msg_len, - &signature); - TMH_PARSE_release_data (spec); - return res; -} - -/* end of taler-mint-httpd_withdraw.c */ diff --git a/src/backend/taler-mint-httpd_withdraw.h b/src/backend/taler-mint-httpd_withdraw.h deleted file mode 100644 index 668178b1..00000000 --- a/src/backend/taler-mint-httpd_withdraw.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero 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 Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-mint-httpd_withdraw.h - * @brief Handle /withdraw/ requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#ifndef TALER_MINT_HTTPD_WITHDRAW_H -#define TALER_MINT_HTTPD_WITHDRAW_H - -#include <microhttpd.h> -#include "taler-mint-httpd.h" - -/** - * Handle a "/withdraw/status" request. Parses the - * given "reserve_pub" argument (which should contain the - * EdDSA public key of a reserve) and then respond with the - * status of the reserve. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_WITHDRAW_handler_withdraw_status (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - - -/** - * Handle a "/withdraw/sign" request. Parses the "reserve_pub" - * EdDSA key of the reserve and the requested "denom_pub" which - * specifies the key/value of the coin to be withdrawn, and checks - * that the signature "reserve_sig" makes this a valid withdrawl - * request from the specified reserve. If so, the envelope - * with the blinded coin "coin_ev" is passed down to execute the - * withdrawl operation. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @return MHD result code - */ -int -TMH_WITHDRAW_handler_withdraw_sign (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size); - -#endif |