diff options
author | Christian Grothoff <christian@grothoff.org> | 2017-06-20 22:30:15 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2017-06-20 22:33:20 +0200 |
commit | 053096475fdb1d6d81aa87bce36f1aceb6264038 (patch) | |
tree | bc5671743770e7560a582d2fe7dd077269327dc7 /src/exchange/taler-exchange-httpd_refresh_reveal.c | |
parent | 39db1ae5dbbd12c0f452cfa56119d9a95f9b1b22 (diff) | |
download | exchange-053096475fdb1d6d81aa87bce36f1aceb6264038.tar.gz exchange-053096475fdb1d6d81aa87bce36f1aceb6264038.tar.bz2 exchange-053096475fdb1d6d81aa87bce36f1aceb6264038.zip |
fixing #5010 for /refresh/reveal
Diffstat (limited to 'src/exchange/taler-exchange-httpd_refresh_reveal.c')
-rw-r--r-- | src/exchange/taler-exchange-httpd_refresh_reveal.c | 674 |
1 files changed, 305 insertions, 369 deletions
diff --git a/src/exchange/taler-exchange-httpd_refresh_reveal.c b/src/exchange/taler-exchange-httpd_refresh_reveal.c index 05422a85a..cfb2b68ac 100644 --- a/src/exchange/taler-exchange-httpd_refresh_reveal.c +++ b/src/exchange/taler-exchange-httpd_refresh_reveal.c @@ -32,95 +32,6 @@ /** - * How often should we retry a transaction before giving up - * (for transactions resulting in serialization/dead locks only). - */ -#define MAX_TRANSACTION_COMMIT_RETRIES 3 - -/** - * Code to begin a transaction, must be inline as we define a block - * that ends with #COMMIT_TRANSACTION() within which we perform a number - * of retries. Note that this code may call "return" internally, so - * it must be called within a function where any cleanup will be done - * by the caller. Furthermore, the function's return value must - * match that of a #TEH_RESPONSE_reply_internal_db_error() status code. - * - * @param session session handle - * @param connection connection handle - */ -#define START_TRANSACTION(session,connection) \ -{ /* start new scope, will be ended by COMMIT_TRANSACTION() */\ - unsigned int transaction_retries = 0; \ - enum GNUNET_DB_QueryStatus transaction_commit_result; \ -transaction_start_label: /* we will use goto for retries */ \ - if (GNUNET_OK != \ - TEH_plugin->start (TEH_plugin->cls, \ - session)) \ - { \ - GNUNET_break (0); \ - return TEH_RESPONSE_reply_internal_db_error (connection, \ - TALER_EC_DB_START_FAILED); \ - } - -/** - * Code to conclude a transaction, dual to #START_TRANSACTION(). Note - * that this code may call "return" internally, so it must be called - * within a function where any cleanup will be done by the caller. - * Furthermore, the function's return value must match that of a - * #TEH_RESPONSE_reply_internal_db_error() status code. - * - * @param session session handle - * @param connection connection handle - */ -#define COMMIT_TRANSACTION(session,connection) \ - transaction_commit_result = \ - TEH_plugin->commit (TEH_plugin->cls, \ - session); \ - if (GNUNET_DB_STATUS_HARD_ERROR == transaction_commit_result) \ - { \ - TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \ - return TEH_RESPONSE_reply_commit_error (connection, \ - TALER_EC_DB_COMMIT_FAILED_HARD); \ - } \ - if (GNUNET_DB_STATUS_SOFT_ERROR == transaction_commit_result) \ - { \ - TALER_LOG_WARNING ("Transaction commit failed in %s\n", __FUNCTION__); \ - if (transaction_retries++ <= MAX_TRANSACTION_COMMIT_RETRIES) \ - goto transaction_start_label; \ - TALER_LOG_WARNING ("Transaction commit failed %u times in %s\n", \ - transaction_retries, \ - __FUNCTION__); \ - return TEH_RESPONSE_reply_commit_error (connection, \ - TALER_EC_DB_COMMIT_FAILED_ON_RETRY); \ - } \ -} /* end of scope opened by BEGIN_TRANSACTION */ - - -/** - * Code to include to retry a transaction, must only be used in between - * #START_TRANSACTION and #COMMIT_TRANSACTION. - * - * @param session session handle - * @param connection connection handle - */ -#define RETRY_TRANSACTION(session,connection) \ - do { \ - TEH_plugin->rollback (TEH_plugin->cls, \ - session); \ - if (transaction_retries++ <= MAX_TRANSACTION_COMMIT_RETRIES) \ - goto transaction_start_label; \ - TALER_LOG_WARNING ("Transaction commit failed %u times in %s\n", \ - transaction_retries, \ - __FUNCTION__); \ - return TEH_RESPONSE_reply_commit_error (connection, \ - TALER_EC_DB_COMMIT_FAILED_ON_RETRY); \ - } while (0) - - - - - -/** * Send a response for "/refresh/reveal". * * @param connection the connection to send the response to @@ -133,14 +44,15 @@ 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 *obj; json_t *list; int ret; list = json_array (); - for (newcoin_index = 0; newcoin_index < num_newcoins; newcoin_index++) + for (unsigned int newcoin_index = 0; + newcoin_index < num_newcoins; + newcoin_index++) { obj = json_object (); json_object_set_new (obj, @@ -182,11 +94,10 @@ reply_refresh_reveal_missmatch (struct MHD_Connection *connection, { json_t *info_new; json_t *info_commit_k; - unsigned int i; info_new = json_array (); info_commit_k = json_array (); - for (i=0;i<session->num_newcoins;i++) + for (unsigned int i=0;i<session->num_newcoins;i++) { const struct TALER_EXCHANGEDB_RefreshCommitCoin *cc; json_t *cc_json; @@ -220,7 +131,6 @@ reply_refresh_reveal_missmatch (struct MHD_Connection *connection, } - /** * Check if the given @a transfer_privs correspond to an honest * commitment for the given session. @@ -253,14 +163,13 @@ check_commitment (struct MHD_Connection *connection, struct GNUNET_HashContext *hash_context) { struct TALER_TransferSecretP transfer_secret; - unsigned int j; TALER_link_reveal_transfer_secret (transfer_priv, &melt->coin.coin_pub, &transfer_secret); /* Check that the commitments for all new coins were correct */ - for (j = 0; j < num_newcoins; j++) + for (unsigned int j = 0; j < num_newcoins; j++) { struct TALER_FreshCoinP fc; struct TALER_CoinSpendPublicKeyP coin_pub; @@ -301,6 +210,58 @@ check_commitment (struct MHD_Connection *connection, /** + * State for a /refresh/reveal operation. + */ +struct RevealContext +{ + + /** + * Hash of the refresh session. + */ + const struct GNUNET_HashCode *session_hash; + + /** + * Database session used to execute the transaction. + */ + struct TALER_EXCHANGEDB_Session *session; + + /** + * Session state from the database. + */ + struct TALER_EXCHANGEDB_RefreshSession refresh_session; + + /** + * Array of denomination public keys used for the refresh. + */ + struct TALER_DenominationPublicKey *denom_pubs; + + /** + * Envelopes with the signatures to be returned. + */ + struct TALER_DenominationSignature *ev_sigs; + + /** + * Commitment data from the DB giving data about original + * commitments, in particular the blinded envelopes (for + * index gamma). + */ + struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins; + + /** + * Transfer public key associated with the gamma value + * selected by the exchange. + */ + struct TALER_TransferPublicKeyP gamma_tp; + + /** + * Transfer private keys revealed to us. + */ + struct TALER_TransferPrivateKeyP transfer_privs[TALER_CNC_KAPPA - 1]; + +}; + + +/** * Exchange a coin as part of a refresh operation. Obtains the * envelope from the database and performs the signing operation. * @@ -311,19 +272,21 @@ check_commitment (struct MHD_Connection *connection, * @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 + * @param[out] ev_sig set to signature over the coin upon success + * @return database transaction status */ -static struct TALER_DenominationSignature +static enum GNUNET_DB_QueryStatus refresh_exchange_coin (struct MHD_Connection *connection, struct TALER_EXCHANGEDB_Session *session, const struct GNUNET_HashCode *session_hash, struct TEH_KS_StateHandle *key_state, const struct TALER_DenominationPublicKey *denom_pub, const struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coin, - unsigned int coin_off) + unsigned int coin_off, + struct TALER_DenominationSignature *ev_sig) { struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki; - struct TALER_DenominationSignature ev_sig; + enum GNUNET_DB_QueryStatus qs; dki = TEH_KS_denomination_key_lookup (key_state, denom_pub, @@ -331,105 +294,91 @@ refresh_exchange_coin (struct MHD_Connection *connection, if (NULL == dki) { GNUNET_break (0); - ev_sig.rsa_signature = NULL; - return ev_sig; + ev_sig->rsa_signature = NULL; + return GNUNET_DB_STATUS_HARD_ERROR; } - if (GNUNET_OK == - TEH_plugin->get_refresh_out (TEH_plugin->cls, - session, - session_hash, - coin_off, - &ev_sig)) + qs = TEH_plugin->get_refresh_out (TEH_plugin->cls, + session, + session_hash, + coin_off, + ev_sig); + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Returning cached reply for /refresh/reveal signature\n"); - return ev_sig; + return qs; } + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != qs) + return qs; - ev_sig.rsa_signature + ev_sig->rsa_signature = GNUNET_CRYPTO_rsa_sign_blinded (dki->denom_priv.rsa_private_key, commit_coin->coin_ev, commit_coin->coin_ev_size); - if (NULL == ev_sig.rsa_signature) + if (NULL == ev_sig->rsa_signature) { GNUNET_break (0); - return ev_sig; + return GNUNET_DB_STATUS_HARD_ERROR; } - if (GNUNET_SYSERR == - TEH_plugin->insert_refresh_out (TEH_plugin->cls, - session, - session_hash, - coin_off, - &ev_sig)) + qs = TEH_plugin->insert_refresh_out (TEH_plugin->cls, + session, + session_hash, + coin_off, + ev_sig); + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) { - GNUNET_break (0); - GNUNET_CRYPTO_rsa_signature_free (ev_sig.rsa_signature); - ev_sig.rsa_signature = NULL; + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); + if (NULL != ev_sig->rsa_signature) + { + GNUNET_CRYPTO_rsa_signature_free (ev_sig->rsa_signature); + ev_sig->rsa_signature = NULL; + } } - - return ev_sig; + return qs; } /** - * The client request was well-formed, now execute the DB transaction - * of a "/refresh/reveal" operation. We use the @a ev_sigs and - * @a commit_coins to clean up resources after this function returns - * as we might experience retries of the database transaction. + * Cleanup state of the transaction stored in @a rc. * - * @param connection the MHD connection to handle - * @param session database session - * @param session_hash hash identifying the refresh session - * @param refresh_session information about the refresh operation we are doing - * @param denom_pubs array of "num_newcoins" denomination keys for the new coins - * @param[out] ev_sigs where to store generated signatures for the new coins, - * array of length "num_newcoins", memory released by the - * caller - * @param[out] commit_coins array of length "num_newcoins" to be used for - * information about the new coins from the commitment. - * @return MHD result code + * @param rc context to clean up */ -static int -execute_refresh_reveal_transaction (struct MHD_Connection *connection, - struct TALER_EXCHANGEDB_Session *session, - const struct GNUNET_HashCode *session_hash, - const struct TALER_EXCHANGEDB_RefreshSession *refresh_session, - const struct TALER_DenominationPublicKey *denom_pubs, - struct TALER_DenominationSignature *ev_sigs, - struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins) +static void +cleanup_rc (struct RevealContext *rc) { - unsigned int j; - struct TEH_KS_StateHandle *key_state; - int ret; - - START_TRANSACTION (session, connection); - key_state = TEH_KS_acquire (); - for (j=0;j<refresh_session->num_newcoins;j++) + if (NULL != rc->denom_pubs) { - if (NULL == ev_sigs[j].rsa_signature) /* could be non-NULL during retries */ - ev_sigs[j] = refresh_exchange_coin (connection, - session, - session_hash, - key_state, - &denom_pubs[j], - &commit_coins[j], - j); - if (NULL == ev_sigs[j].rsa_signature) - { - TEH_plugin->rollback (TEH_plugin->cls, - session); - ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_REFRESH_REVEAL_SIGNING_ERROR); - goto cleanup; - } + for (unsigned int i=0;i<rc->refresh_session.num_newcoins;i++) + if (NULL != rc->denom_pubs[i].rsa_public_key) + GNUNET_CRYPTO_rsa_public_key_free (rc->denom_pubs[i].rsa_public_key); + GNUNET_free (rc->denom_pubs); + rc->denom_pubs = NULL; + } + if (NULL != rc->commit_coins) + { + for (unsigned int j=0;j<rc->refresh_session.num_newcoins;j++) + GNUNET_free_non_null (rc->commit_coins[j].coin_ev); + GNUNET_free (rc->commit_coins); + rc->commit_coins = NULL; + } + if (NULL != rc->ev_sigs) + { + for (unsigned int j=0;j<rc->refresh_session.num_newcoins;j++) + if (NULL != rc->ev_sigs[j].rsa_signature) + GNUNET_CRYPTO_rsa_signature_free (rc->ev_sigs[j].rsa_signature); + GNUNET_free (rc->ev_sigs); + rc->ev_sigs = NULL; + } + if (NULL != rc->refresh_session.melt.coin.denom_sig.rsa_signature) + { + GNUNET_CRYPTO_rsa_signature_free (rc->refresh_session.melt.coin.denom_sig.rsa_signature); + rc->refresh_session.melt.coin.denom_sig.rsa_signature = NULL; + } + if (NULL != rc->refresh_session.melt.coin.denom_pub.rsa_public_key) + { + GNUNET_CRYPTO_rsa_public_key_free (rc->refresh_session.melt.coin.denom_pub.rsa_public_key); + rc->refresh_session.melt.coin.denom_pub.rsa_public_key = NULL; } - COMMIT_TRANSACTION (session, connection); - ret = reply_refresh_reveal_success (connection, - refresh_session->num_newcoins, - ev_sigs); - cleanup: - TEH_KS_release (key_state); - return ret; } @@ -440,94 +389,98 @@ execute_refresh_reveal_transaction (struct MHD_Connection *connection, * 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 transfer_privs array with the revealed transfer keys, - * length must be #TALER_CNC_KAPPA - 1 - * @return MHD result code + * IF it returns a non-error code, the transaction logic MUST + * NOT queue a MHD response. IF it returns an hard error, the + * transaction logic MUST queue a MHD response and set @a mhd_ret. IF + * it returns the soft error code, the function MAY be called again to + * retry and MUST not queue a MHD response. + * + * @param cls closure of type `struct RevealContext` + * @param connection MHD request which triggered the transaction + * @param session database session to use + * @param[out] mhd_ret set to MHD response status for @a connection, + * if transaction failed (!) + * @return transaction status */ -static int -execute_refresh_reveal (struct MHD_Connection *connection, - const struct GNUNET_HashCode *session_hash, - struct TALER_TransferPrivateKeyP *transfer_privs) +static enum GNUNET_DB_QueryStatus +refresh_reveal_transaction (void *cls, + struct MHD_Connection *connection, + struct TALER_EXCHANGEDB_Session *session, + int *mhd_ret) { - int res; - struct TALER_EXCHANGEDB_Session *session; - struct TALER_EXCHANGEDB_RefreshSession refresh_session; - struct TALER_DenominationPublicKey *denom_pubs; - struct TALER_DenominationSignature *ev_sigs; - struct TALER_EXCHANGEDB_RefreshCommitCoin *commit_coins; - unsigned int i; - unsigned int j; + struct RevealContext *rc = cls; unsigned int off; struct GNUNET_HashContext *hash_context; struct GNUNET_HashCode sh_check; - int ret; - struct TALER_TransferPublicKeyP gamma_tp; - - if (NULL == (session = TEH_plugin->get_session (TEH_plugin->cls))) + enum GNUNET_DB_QueryStatus qs; + + rc->session = session; + qs = TEH_plugin->get_refresh_session (TEH_plugin->cls, + session, + rc->session_hash, + &rc->refresh_session); + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + { + *mhd_ret = TEH_RESPONSE_reply_arg_invalid (connection, + TALER_EC_REFRESH_REVEAL_SESSION_UNKNOWN, + "session_hash"); + return GNUNET_DB_STATUS_HARD_ERROR; + } + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + return qs; + if ( (GNUNET_DB_STATUS_HARD_ERROR == qs) || + (rc->refresh_session.noreveal_index >= TALER_CNC_KAPPA) ) { GNUNET_break (0); - return TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_DB_SETUP_FAILED); + cleanup_rc (rc); + *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_REFRESH_REVEAL_DB_FETCH_SESSION_ERROR); + return GNUNET_DB_STATUS_HARD_ERROR; } - - res = TEH_plugin->get_refresh_session (TEH_plugin->cls, - session, - session_hash, - &refresh_session); - if (GNUNET_NO == res) - return TEH_RESPONSE_reply_arg_invalid (connection, - TALER_EC_REFRESH_REVEAL_SESSION_UNKNOWN, - "session_hash"); - if ( (GNUNET_SYSERR == res) || - (refresh_session.noreveal_index >= TALER_CNC_KAPPA) ) - return TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_REFRESH_REVEAL_DB_FETCH_SESSION_ERROR); - denom_pubs = GNUNET_new_array (refresh_session.num_newcoins, - struct TALER_DenominationPublicKey); - if (GNUNET_OK != - TEH_plugin->get_refresh_order (TEH_plugin->cls, - session, - session_hash, - refresh_session.num_newcoins, - denom_pubs)) + rc->denom_pubs = GNUNET_new_array (rc->refresh_session.num_newcoins, + struct TALER_DenominationPublicKey); + qs = TEH_plugin->get_refresh_order (TEH_plugin->cls, + session, + rc->session_hash, + rc->refresh_session.num_newcoins, + rc->denom_pubs); + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) { + cleanup_rc (rc); + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + return qs; GNUNET_break (0); - GNUNET_free (denom_pubs); - GNUNET_CRYPTO_rsa_signature_free (refresh_session.melt.coin.denom_sig.rsa_signature); - GNUNET_CRYPTO_rsa_public_key_free (refresh_session.melt.coin.denom_pub.rsa_public_key); - return (MHD_YES == TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_REFRESH_REVEAL_DB_FETCH_ORDER_ERROR)) - ? GNUNET_NO : GNUNET_SYSERR; + *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_REFRESH_REVEAL_DB_FETCH_ORDER_ERROR); + return GNUNET_DB_STATUS_HARD_ERROR; } hash_context = GNUNET_CRYPTO_hash_context_start (); /* first, iterate over transfer public keys for hash_context */ off = 0; - for (i=0;i<TALER_CNC_KAPPA;i++) + for (unsigned int i=0;i<TALER_CNC_KAPPA;i++) { - if (i == refresh_session.noreveal_index) + if (i == rc->refresh_session.noreveal_index) { off = 1; /* obtain gamma_tp from db */ - if (GNUNET_OK != - TEH_plugin->get_refresh_transfer_public_key (TEH_plugin->cls, - session, - session_hash, - &gamma_tp)) + qs = TEH_plugin->get_refresh_transfer_public_key (TEH_plugin->cls, + session, + rc->session_hash, + &rc->gamma_tp); + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) { - GNUNET_break (0); - GNUNET_free (denom_pubs); - GNUNET_CRYPTO_rsa_signature_free (refresh_session.melt.coin.denom_sig.rsa_signature); - GNUNET_CRYPTO_rsa_public_key_free (refresh_session.melt.coin.denom_pub.rsa_public_key); GNUNET_CRYPTO_hash_context_abort (hash_context); - return (MHD_YES == TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_REFRESH_REVEAL_DB_FETCH_TRANSFER_ERROR)) - ? GNUNET_NO : GNUNET_SYSERR; + cleanup_rc (rc); + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + return qs; + GNUNET_break (0); + *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_REFRESH_REVEAL_DB_FETCH_TRANSFER_ERROR); + return GNUNET_DB_STATUS_HARD_ERROR; } GNUNET_CRYPTO_hash_context_read (hash_context, - &gamma_tp, + &rc->gamma_tp, sizeof (struct TALER_TransferPublicKeyP)); } else @@ -535,7 +488,7 @@ execute_refresh_reveal (struct MHD_Connection *connection, /* compute tp from private key */ struct TALER_TransferPublicKeyP tp; - GNUNET_CRYPTO_ecdhe_key_get_public (&transfer_privs[i - off].ecdhe_priv, + GNUNET_CRYPTO_ecdhe_key_get_public (&rc->transfer_privs[i - off].ecdhe_priv, &tp.ecdhe_pub); GNUNET_CRYPTO_hash_context_read (hash_context, &tp, @@ -545,38 +498,17 @@ execute_refresh_reveal (struct MHD_Connection *connection, /* next, add all of the hashes from the denomination keys to the hash_context */ + for (unsigned int i=0;i<rc->refresh_session.num_newcoins;i++) { - struct TALER_DenominationPublicKey denom_pubs[refresh_session.num_newcoins]; - - if (GNUNET_OK != - TEH_plugin->get_refresh_order (TEH_plugin->cls, - session, - session_hash, - refresh_session.num_newcoins, - denom_pubs)) - { - GNUNET_break (0); - GNUNET_free (denom_pubs); - GNUNET_CRYPTO_rsa_signature_free (refresh_session.melt.coin.denom_sig.rsa_signature); - GNUNET_CRYPTO_rsa_public_key_free (refresh_session.melt.coin.denom_pub.rsa_public_key); - GNUNET_CRYPTO_hash_context_abort (hash_context); - return (MHD_YES == TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_REFRESH_REVEAL_DB_FETCH_ORDER_ERROR)) - ? GNUNET_NO : GNUNET_SYSERR; - } - for (i=0;i<refresh_session.num_newcoins;i++) - { - char *buf; - size_t buf_size; + char *buf; + size_t buf_size; - 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); - GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[i].rsa_public_key); - } + buf_size = GNUNET_CRYPTO_rsa_public_key_encode (rc->denom_pubs[i].rsa_public_key, + &buf); + GNUNET_CRYPTO_hash_context_read (hash_context, + buf, + buf_size); + GNUNET_free (buf); } /* next, add public key of coin and amount being refreshed */ @@ -584,71 +516,67 @@ execute_refresh_reveal (struct MHD_Connection *connection, struct TALER_AmountNBO melt_amountn; GNUNET_CRYPTO_hash_context_read (hash_context, - &refresh_session.melt.coin.coin_pub, + &rc->refresh_session.melt.coin.coin_pub, sizeof (struct TALER_CoinSpendPublicKeyP)); TALER_amount_hton (&melt_amountn, - &refresh_session.melt.amount_with_fee); + &rc->refresh_session.melt.amount_with_fee); GNUNET_CRYPTO_hash_context_read (hash_context, &melt_amountn, sizeof (struct TALER_AmountNBO)); } - commit_coins = GNUNET_new_array (refresh_session.num_newcoins, - struct TALER_EXCHANGEDB_RefreshCommitCoin); + rc->commit_coins = GNUNET_new_array (rc->refresh_session.num_newcoins, + struct TALER_EXCHANGEDB_RefreshCommitCoin); off = 0; - for (i=0;i<TALER_CNC_KAPPA;i++) + for (unsigned int i=0;i<TALER_CNC_KAPPA;i++) { - if (i == refresh_session.noreveal_index) + int res; + + if (i == rc->refresh_session.noreveal_index) { off = 1; /* obtain commit_coins for the selected gamma value from DB */ - if (GNUNET_OK != - TEH_plugin->get_refresh_commit_coins (TEH_plugin->cls, - session, - session_hash, - refresh_session.num_newcoins, - commit_coins)) - { - GNUNET_break (0); - GNUNET_free (denom_pubs); - GNUNET_CRYPTO_rsa_signature_free (refresh_session.melt.coin.denom_sig.rsa_signature); - GNUNET_CRYPTO_rsa_public_key_free (refresh_session.melt.coin.denom_pub.rsa_public_key); + qs = TEH_plugin->get_refresh_commit_coins (TEH_plugin->cls, + session, + rc->session_hash, + rc->refresh_session.num_newcoins, + rc->commit_coins); + if (0 >= qs) + { + cleanup_rc (rc); GNUNET_CRYPTO_hash_context_abort (hash_context); - return TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_REFRESH_REVEAL_DB_FETCH_COMMIT_ERROR); + if (GNUNET_DB_STATUS_SOFT_ERROR == qs) + return qs; + GNUNET_break (0); + *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_REFRESH_REVEAL_DB_FETCH_COMMIT_ERROR); + return GNUNET_DB_STATUS_HARD_ERROR; } /* add envelopes to hash_context */ - for (j=0;j<refresh_session.num_newcoins;j++) + for (unsigned int j=0;j<rc->refresh_session.num_newcoins;j++) { GNUNET_CRYPTO_hash_context_read (hash_context, - commit_coins[j].coin_ev, - commit_coins[j].coin_ev_size); + rc->commit_coins[j].coin_ev, + rc->commit_coins[j].coin_ev_size); } continue; } if (GNUNET_OK != (res = check_commitment (connection, session, - session_hash, + rc->session_hash, i, - &transfer_privs[i - off], - &refresh_session.melt, - refresh_session.num_newcoins, - denom_pubs, + &rc->transfer_privs[i - off], + &rc->refresh_session.melt, + rc->refresh_session.num_newcoins, + rc->denom_pubs, hash_context))) { GNUNET_break_op (0); - for (j=0;j<refresh_session.num_newcoins;j++) - { - GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); - GNUNET_free (commit_coins[j].coin_ev); - } - GNUNET_free (commit_coins); - GNUNET_free (denom_pubs); - GNUNET_CRYPTO_rsa_signature_free (refresh_session.melt.coin.denom_sig.rsa_signature); - GNUNET_CRYPTO_rsa_public_key_free (refresh_session.melt.coin.denom_pub.rsa_public_key); + cleanup_rc (rc); GNUNET_CRYPTO_hash_context_abort (hash_context); - return (GNUNET_NO == res) ? MHD_YES : MHD_NO; + *mhd_ret = (GNUNET_NO == res) ? MHD_YES : MHD_NO; + return GNUNET_DB_STATUS_HARD_ERROR; } } @@ -656,56 +584,53 @@ execute_refresh_reveal (struct MHD_Connection *connection, GNUNET_CRYPTO_hash_context_finish (hash_context, &sh_check); if (0 != memcmp (&sh_check, - session_hash, + rc->session_hash, sizeof (struct GNUNET_HashCode))) { GNUNET_break_op (0); - ret = reply_refresh_reveal_missmatch (connection, - &refresh_session, - commit_coins, - denom_pubs, - &gamma_tp); - for (j=0;j<refresh_session.num_newcoins;j++) + *mhd_ret = reply_refresh_reveal_missmatch (connection, + &rc->refresh_session, + rc->commit_coins, + rc->denom_pubs, + &rc->gamma_tp); + cleanup_rc (rc); + return GNUNET_DB_STATUS_HARD_ERROR; + } + + /* Client request OK, sign coins */ + rc->ev_sigs = GNUNET_new_array (rc->refresh_session.num_newcoins, + struct TALER_DenominationSignature); + { + struct TEH_KS_StateHandle *key_state; + + key_state = TEH_KS_acquire (); + for (unsigned int j=0;j<rc->refresh_session.num_newcoins;j++) { - GNUNET_free (commit_coins[j].coin_ev); - GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); + qs = refresh_exchange_coin (connection, + session, + rc->session_hash, + key_state, + &rc->denom_pubs[j], + &rc->commit_coins[j], + j, + &rc->ev_sigs[j]); + if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) || + (NULL == rc->ev_sigs[j].rsa_signature) ) + { + *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, + TALER_EC_REFRESH_REVEAL_SIGNING_ERROR); + qs = GNUNET_DB_STATUS_HARD_ERROR; + break; + } } - GNUNET_free (commit_coins); - GNUNET_free (denom_pubs); - GNUNET_CRYPTO_rsa_signature_free (refresh_session.melt.coin.denom_sig.rsa_signature); - GNUNET_CRYPTO_rsa_public_key_free (refresh_session.melt.coin.denom_pub.rsa_public_key); - - return ret; + TEH_KS_release (key_state); } - - /* Client request OK, start transaction */ - ev_sigs = GNUNET_new_array (refresh_session.num_newcoins, - struct TALER_DenominationSignature); - - /* FIXME: might need to store revealed transfer private keys for - the auditor for later; should pass them as arguments here! #4792*/ - res = execute_refresh_reveal_transaction (connection, - session, - session_hash, - &refresh_session, - denom_pubs, - ev_sigs, - commit_coins); - for (i=0;i<refresh_session.num_newcoins;i++) + if (0 >= qs) { - if (NULL != ev_sigs[i].rsa_signature) - GNUNET_CRYPTO_rsa_signature_free (ev_sigs[i].rsa_signature); - GNUNET_free (commit_coins[i].coin_ev); + cleanup_rc (rc); + return qs; } - for (j=0;j<refresh_session.num_newcoins;j++) - if (NULL != denom_pubs[j].rsa_public_key) - GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key); - GNUNET_CRYPTO_rsa_signature_free (refresh_session.melt.coin.denom_sig.rsa_signature); - GNUNET_CRYPTO_rsa_public_key_free (refresh_session.melt.coin.denom_pub.rsa_public_key); - GNUNET_free (ev_sigs); - GNUNET_free (denom_pubs); - GNUNET_free (commit_coins); - return res; + return qs; } @@ -726,37 +651,47 @@ handle_refresh_reveal_json (struct MHD_Connection *connection, const struct GNUNET_HashCode *session_hash, const json_t *tp_json) { - struct TALER_TransferPrivateKeyP transfer_privs[TALER_CNC_KAPPA - 1]; - unsigned int i; - int res; + struct RevealContext rc; + int mhd_ret; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "reveal request for session %s\n", GNUNET_h2s (session_hash)); - - res = GNUNET_OK; - for (i = 0; i < TALER_CNC_KAPPA - 1; i++) + memset (&rc, + 0, + sizeof (rc)); + rc.session_hash = session_hash; + for (unsigned int i = 0; i < TALER_CNC_KAPPA - 1; i++) { struct GNUNET_JSON_Specification tp_spec[] = { - GNUNET_JSON_spec_fixed_auto (NULL, &transfer_privs[i]), + GNUNET_JSON_spec_fixed_auto (NULL, &rc.transfer_privs[i]), GNUNET_JSON_spec_end () }; + int res; - if (GNUNET_OK != res) - break; res = TEH_PARSE_json_array (connection, tp_json, tp_spec, - i, -1); + i, + -1); GNUNET_break_op (GNUNET_OK == res); + if (GNUNET_OK != res) + return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; } - if (GNUNET_OK != res) - res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - else - res = execute_refresh_reveal (connection, - session_hash, - transfer_privs); - return res; + if (GNUNET_OK != + TEH_DB_run_transaction (connection, + &mhd_ret, + &refresh_reveal_transaction, + &rc)) + { + cleanup_rc (&rc); + return mhd_ret; + } + mhd_ret = reply_refresh_reveal_success (connection, + rc.refresh_session.num_newcoins, + rc.ev_sigs); + cleanup_rc (&rc); + return mhd_ret; } @@ -800,7 +735,8 @@ TEH_REFRESH_handler_refresh_reveal (struct TEH_RequestHandler *rh, &root); if (GNUNET_SYSERR == res) return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == root) ) + if ( (GNUNET_NO == res) || + (NULL == root) ) return MHD_YES; res = TEH_PARSE_json_data (connection, |