From 4d8f4903db35e9ef6492864c018238e89033ccc7 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 21 Jan 2015 13:31:05 +0100 Subject: [PATCH] properly separate DB logic from parsing logic for /refresh/commit --- src/mint/mint_db.c | 6 +- src/mint/mint_db.h | 6 +- src/mint/taler-mint-httpd_db.c | 121 ++++++++++++ src/mint/taler-mint-httpd_db.h | 19 ++ src/mint/taler-mint-httpd_refresh.c | 289 ++++++++++++---------------- 5 files changed, 276 insertions(+), 165 deletions(-) diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c index af900b5d7..6ce60fc45 100644 --- a/src/mint/mint_db.c +++ b/src/mint/mint_db.c @@ -1087,7 +1087,8 @@ TALER_MINT_DB_upsert_known_coin (PGconn *db_conn, struct KnownCoin *known_coin) int -TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn, struct RefreshCommitLink *commit_link) +TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn, + const struct RefreshCommitLink *commit_link) { uint16_t cnc_index_nbo = htons (commit_link->cnc_index); uint16_t oldcoin_index_nbo = htons (commit_link->oldcoin_index); @@ -1121,7 +1122,8 @@ TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn, struct RefreshCommitL int -TALER_MINT_DB_insert_refresh_commit_coin (PGconn *db_conn, struct RefreshCommitCoin *commit_coin) +TALER_MINT_DB_insert_refresh_commit_coin (PGconn *db_conn, + const struct RefreshCommitCoin *commit_coin) { uint16_t cnc_index_nbo = htons (commit_coin->cnc_index); uint16_t newcoin_index_nbo = htons (commit_coin->newcoin_index); diff --git a/src/mint/mint_db.h b/src/mint/mint_db.h index 5eaa367d7..7998a01cf 100644 --- a/src/mint/mint_db.h +++ b/src/mint/mint_db.h @@ -91,10 +91,12 @@ TALER_MINT_DB_upsert_known_coin (PGconn *db_conn, struct KnownCoin *known_coin); int -TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn, struct RefreshCommitLink *commit_link); +TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn, + const struct RefreshCommitLink *commit_link); int -TALER_MINT_DB_insert_refresh_commit_coin (PGconn *db_conn, struct RefreshCommitCoin *commit_coin); +TALER_MINT_DB_insert_refresh_commit_coin (PGconn *db_conn, + const struct RefreshCommitCoin *commit_coin); int diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c index 60218ab66..2beaa8f97 100644 --- a/src/mint/taler-mint-httpd_db.c +++ b/src/mint/taler-mint-httpd_db.c @@ -686,3 +686,124 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection, } + + +/** + * Execute a /refresh/commit. + * + * @param connection the MHD connection to handle + * @param kappa size of x-dimension of @commit_coin and @commit_link arrays + * @param num_oldcoins size of y-dimension of @commit_coin and @commit_link arrays + * @param num_newcoins size of y-dimension of @commit_coin and @commit_link arrays + * @return MHD result code + */ +int +TALER_MINT_db_execute_refresh_commit (struct MHD_Connection *connection, + const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub, + unsigned int kappa, + unsigned int num_oldcoins, + unsigned int num_newcoins, + struct RefreshCommitCoin *const*commit_coin, + struct RefreshCommitLink *const*commit_link) + +{ + PGconn *db_conn; + struct RefreshSession refresh_session; + unsigned int i; + unsigned int j; + int res; + + if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) + { + // FIXME: return 'internal error'? + GNUNET_break (0); + return MHD_NO; + } + + /* Send response immediately if we already know the session. + * Do _not_ care about fields other than session_pub in this case. */ + + res = TALER_MINT_DB_get_refresh_session (db_conn, + refresh_session_pub, + &refresh_session); + // FIXME: this should check that kappa and num_newcoins match + // our expectations from refresh_session! + + for (i = 0; i < refresh_session.kappa; i++) + { + for (j = 0; j < refresh_session.num_newcoins; j++) + { + if (GNUNET_OK != + TALER_MINT_DB_insert_refresh_commit_coin (db_conn, + &commit_coin[i][j])) + { + // FIXME: return 'internal error'? + GNUNET_break (0); + GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn)); + return MHD_NO; + } + + if (GNUNET_OK != + TALER_MINT_DB_insert_refresh_commit_link (db_conn, &commit_link[i][j])) + { + // FIXME: return 'internal error'? + GNUNET_break (0); + GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn)); + return MHD_NO; + } + } + } + + + + + + if ( (GNUNET_YES == res) && + (GNUNET_YES == refresh_session.has_commit_sig) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "sending cached commit response\n"); + res = TALER_MINT_reply_refresh_commit_success (connection, + &refresh_session); + GNUNET_break (res != GNUNET_SYSERR); + return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; + } + if (GNUNET_SYSERR == res) + { + // FIXME: return 'internal error'? + GNUNET_break (0); + return MHD_NO; + } + + if (GNUNET_OK != TALER_MINT_DB_transaction (db_conn)) + { + // FIXME: return 'internal error'? + GNUNET_break (0); + return MHD_NO; + } + + /* Re-fetch the session information from the database, + * in case a concurrent transaction modified it. */ + + res = TALER_MINT_DB_get_refresh_session (db_conn, + refresh_session_pub, + &refresh_session); + if (GNUNET_OK != res) + { + // FIXME: return 'internal error'? + GNUNET_break (GNUNET_SYSERR != res); + GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn)); + return MHD_NO; + } + + + + if (GNUNET_OK != TALER_MINT_DB_commit (db_conn)) + { + // FIXME: return 'internal error'? + GNUNET_break (0); + return MHD_NO; + } + + return TALER_MINT_reply_refresh_commit_success (connection, &refresh_session); + } diff --git a/src/mint/taler-mint-httpd_db.h b/src/mint/taler-mint-httpd_db.h index ce2488be5..307400b47 100644 --- a/src/mint/taler-mint-httpd_db.h +++ b/src/mint/taler-mint-httpd_db.h @@ -91,4 +91,23 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection, const struct TALER_CoinPublicInfo *coin_public_infos); +/** + * Execute a /refresh/commit. + * + * @param connection the MHD connection to handle + * @param kappa size of x-dimension of @commit_coin and @commit_link arrays + * @param num_oldcoins size of y-dimension of @commit_coin and @commit_link arrays + * @param num_newcoins size of y-dimension of @commit_coin and @commit_link arrays + * @return MHD result code + */ +int +TALER_MINT_db_execute_refresh_commit (struct MHD_Connection *connection, + const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub, + unsigned int kappa, + unsigned int num_oldcoins, + unsigned int num_newcoins, + struct RefreshCommitCoin *const* commit_coin, + struct RefreshCommitLink *const* commit_link); + + #endif /* _NEURO_MINT_DB_H */ diff --git a/src/mint/taler-mint-httpd_refresh.c b/src/mint/taler-mint-httpd_refresh.c index 52bf089b1..3751ee17d 100644 --- a/src/mint/taler-mint-httpd_refresh.c +++ b/src/mint/taler-mint-httpd_refresh.c @@ -460,12 +460,21 @@ TALER_MINT_handler_refresh_commit (struct RequestHandler *rh, { struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub; int res; - PGconn *db_conn; - struct RefreshSession refresh_session; - int i; + unsigned int i; + unsigned int j; + unsigned int kappa; + unsigned int num_oldcoins; + unsigned int num_newcoins; struct GNUNET_HashCode commit_hash; struct GNUNET_HashContext *hash_context; json_t *root; + struct RefreshCommitSignatureBody body; + json_t *commit_sig_json; + struct RefreshCommitCoin **commit_coin; + struct RefreshCommitLink **commit_link; + json_t *coin_evs; + json_t *transfer_pubs; + json_t *coin_detail; res = TALER_MINT_parse_post_json (connection, connection_cls, @@ -478,238 +487,196 @@ TALER_MINT_handler_refresh_commit (struct RequestHandler *rh, return MHD_YES; res = GNUNET_MINT_parse_navigate_json (connection, root, - JNAV_FIELD, "session_pub", - JNAV_RET_DATA, - &refresh_session_pub, - sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); + JNAV_FIELD, "session_pub", + JNAV_RET_DATA, + &refresh_session_pub, + sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); if (GNUNET_OK != res) { GNUNET_break (GNUNET_SYSERR != res); return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; } - if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) - { - // FIXME: return 'internal error'? - GNUNET_break (0); - return MHD_NO; - } - - /* Send response immediately if we already know the session. - * Do _not_ care about fields other than session_pub in this case. */ - - res = TALER_MINT_DB_get_refresh_session (db_conn, - &refresh_session_pub, - &refresh_session); - if ( (GNUNET_YES == res) && - (GNUNET_YES == refresh_session.has_commit_sig) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "sending cached commit response\n"); - res = TALER_MINT_reply_refresh_commit_success (connection, - &refresh_session); - GNUNET_break (res != GNUNET_SYSERR); - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - } - if (GNUNET_SYSERR == res) - { - // FIXME: return 'internal error'? - GNUNET_break (0); - return MHD_NO; - } - - if (GNUNET_OK != TALER_MINT_DB_transaction (db_conn)) - { - // FIXME: return 'internal error'? - GNUNET_break (0); - return MHD_NO; - } - - /* Re-fetch the session information from the database, - * in case a concurrent transaction modified it. */ - - res = TALER_MINT_DB_get_refresh_session (db_conn, - &refresh_session_pub, - &refresh_session); + /* Determine dimensionality of the request (kappa, #old and #new coins) */ + res = GNUNET_MINT_parse_navigate_json (connection, root, + JNAV_FIELD, "coin_evs", + JNAV_RET_TYPED_JSON, JSON_ARRAY, &coin_evs); if (GNUNET_OK != res) + return res; + kappa = json_array_size (coin_evs); + if (3 > kappa) { - // FIXME: return 'internal error'? - GNUNET_break (GNUNET_SYSERR != res); - GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn)); + GNUNET_break_op (0); + // FIXME: generate error message return MHD_NO; } + res = GNUNET_MINT_parse_navigate_json (connection, root, + JNAV_INDEX, (int) 0, + JNAV_RET_DATA, + JSON_ARRAY, &coin_detail); + if (GNUNET_OK != res) + return res; + num_newcoins = json_array_size (coin_detail); + + res = GNUNET_MINT_parse_navigate_json (connection, root, + JNAV_FIELD, "transfer_pubs", + JNAV_RET_TYPED_JSON, JSON_ARRAY, &transfer_pubs); + if (GNUNET_OK != res) + return res; + if (json_array_size (transfer_pubs) != kappa) + { + GNUNET_break_op (0); + // FIXME: generate error message + return MHD_NO; + } + res = GNUNET_MINT_parse_navigate_json (connection, root, + JNAV_INDEX, (int) 0, + JNAV_RET_DATA, + JSON_ARRAY, &coin_detail); + if (GNUNET_OK != res) + return res; + num_oldcoins = json_array_size (coin_detail); + + hash_context = GNUNET_CRYPTO_hash_context_start (); - - for (i = 0; i < refresh_session.kappa; i++) + commit_coin = GNUNET_malloc (kappa * + sizeof (struct RefreshCommitCoin *)); + for (i = 0; i < kappa; i++) { - unsigned int j; - - for (j = 0; j < refresh_session.num_newcoins; j++) + commit_coin[i] = GNUNET_malloc (num_newcoins * + sizeof (struct RefreshCommitCoin)); + for (j = 0; j < num_newcoins; j++) { - struct RefreshCommitCoin commit_coin; - res = GNUNET_MINT_parse_navigate_json (connection, root, - JNAV_FIELD, "coin_evs", - JNAV_INDEX, (int) i, - JNAV_INDEX, (int) j, - JNAV_RET_DATA, - &commit_coin.coin_ev, - sizeof (struct TALER_RSA_BlindedSignaturePurpose)); + JNAV_FIELD, "coin_evs", + JNAV_INDEX, (int) i, + JNAV_INDEX, (int) j, + JNAV_RET_DATA, + commit_coin[i][j].coin_ev, + sizeof (struct TALER_RSA_BlindedSignaturePurpose)); if (GNUNET_OK != res) { // FIXME: return 'internal error'? GNUNET_break (0); - GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn)); GNUNET_CRYPTO_hash_context_abort (hash_context); return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; } GNUNET_CRYPTO_hash_context_read (hash_context, - &commit_coin.coin_ev, - sizeof (struct TALER_RSA_BlindedSignaturePurpose)); + &commit_coin[i][j].coin_ev, + sizeof (struct TALER_RSA_BlindedSignaturePurpose)); res = GNUNET_MINT_parse_navigate_json (connection, root, - JNAV_FIELD, "link_encs", - JNAV_INDEX, (int) i, - JNAV_INDEX, (int) j, - JNAV_RET_DATA, - commit_coin.link_enc, - TALER_REFRESH_LINK_LENGTH); + JNAV_FIELD, "link_encs", + JNAV_INDEX, (int) i, + JNAV_INDEX, (int) j, + JNAV_RET_DATA, + commit_coin[i][j].link_enc, + TALER_REFRESH_LINK_LENGTH); if (GNUNET_OK != res) { // FIXME: return 'internal error'? GNUNET_break (0); - GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn)); GNUNET_CRYPTO_hash_context_abort (hash_context); return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; } GNUNET_CRYPTO_hash_context_read (hash_context, - commit_coin.link_enc, - TALER_REFRESH_LINK_LENGTH); - - commit_coin.cnc_index = i; - commit_coin.newcoin_index = j; - commit_coin.session_pub = refresh_session_pub; - - if (GNUNET_OK != - TALER_MINT_DB_insert_refresh_commit_coin (db_conn, - &commit_coin)) - { - // FIXME: return 'internal error'? - GNUNET_break (0); - GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn)); - GNUNET_CRYPTO_hash_context_abort (hash_context); - return MHD_NO; - } + commit_coin[i][j].link_enc, + TALER_REFRESH_LINK_LENGTH); + commit_coin[i][j].cnc_index = i; + commit_coin[i][j].newcoin_index = j; + commit_coin[i][j].session_pub = refresh_session_pub; } } - for (i = 0; i < refresh_session.kappa; i++) + commit_link = GNUNET_malloc (kappa * + sizeof (struct RefreshCommitLink *)); + for (i = 0; i < kappa; i++) { - unsigned int j; - for (j = 0; j < refresh_session.num_oldcoins; j++) + commit_link[i] = GNUNET_malloc (num_oldcoins * + sizeof (struct RefreshCommitLink)); + for (j = 0; j < num_oldcoins; j++) { - struct RefreshCommitLink commit_link; - res = GNUNET_MINT_parse_navigate_json (connection, root, - JNAV_FIELD, "transfer_pubs", - JNAV_INDEX, (int) i, - JNAV_INDEX, (int) j, - JNAV_RET_DATA, - &commit_link.transfer_pub, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + JNAV_FIELD, "transfer_pubs", + JNAV_INDEX, (int) i, + JNAV_INDEX, (int) j, + JNAV_RET_DATA, + &commit_link[i][j].transfer_pub, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); if (GNUNET_OK != res) { GNUNET_break (GNUNET_SYSERR != res); - GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn)); GNUNET_CRYPTO_hash_context_abort (hash_context); return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; } GNUNET_CRYPTO_hash_context_read (hash_context, - &commit_link.transfer_pub, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + &commit_link[i][j].transfer_pub, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); res = GNUNET_MINT_parse_navigate_json (connection, root, - JNAV_FIELD, "secret_encs", - JNAV_INDEX, (int) i, - JNAV_INDEX, (int) j, - JNAV_RET_DATA, - commit_link.shared_secret_enc, - TALER_REFRESH_SHARED_SECRET_LENGTH); + JNAV_FIELD, "secret_encs", + JNAV_INDEX, (int) i, + JNAV_INDEX, (int) j, + JNAV_RET_DATA, + commit_link[i][j].shared_secret_enc, + TALER_REFRESH_SHARED_SECRET_LENGTH); if (GNUNET_OK != res) { GNUNET_break (GNUNET_SYSERR != res); - GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn)); GNUNET_CRYPTO_hash_context_abort (hash_context); return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; } GNUNET_CRYPTO_hash_context_read (hash_context, - commit_link.shared_secret_enc, - TALER_REFRESH_SHARED_SECRET_LENGTH); + commit_link[i][j].shared_secret_enc, + TALER_REFRESH_SHARED_SECRET_LENGTH); - commit_link.cnc_index = i; - commit_link.oldcoin_index = j; - commit_link.session_pub = refresh_session_pub; + commit_link[i][j].cnc_index = i; + commit_link[i][j].oldcoin_index = j; + commit_link[i][j].session_pub = refresh_session_pub; - if (GNUNET_OK != TALER_MINT_DB_insert_refresh_commit_link (db_conn, &commit_link)) - { - // FIXME: return 'internal error'? - GNUNET_break (0); - GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn)); - GNUNET_CRYPTO_hash_context_abort (hash_context); - - return MHD_NO; - } } } - GNUNET_CRYPTO_hash_context_finish (hash_context, &commit_hash); + commit_sig_json = json_object_get (root, "commit_signature"); + if (NULL == commit_sig_json) { - struct RefreshCommitSignatureBody body; - json_t *commit_sig_json; - - commit_sig_json = json_object_get (root, "commit_signature"); - if (NULL == commit_sig_json) - { - GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn)); - return TALER_MINT_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s}", - "error", - "commit_signature missing"); - } - - body.commit_hash = commit_hash; - - body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_COMMIT); - body.purpose.size = htonl (sizeof (struct RefreshCommitSignatureBody)); - - if (GNUNET_OK != (res = request_json_check_signature (connection, - commit_sig_json, - &refresh_session_pub, - &body.purpose))) - { - GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn)); - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; - } + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s}", + "error", + "commit_signature missing"); } - if (GNUNET_OK != TALER_MINT_DB_commit (db_conn)) + body.commit_hash = commit_hash; + body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_COMMIT); + body.purpose.size = htonl (sizeof (struct RefreshCommitSignatureBody)); + + if (GNUNET_OK != (res = request_json_check_signature (connection, + commit_sig_json, + &refresh_session_pub, + &body.purpose))) { - // FIXME: return 'internal error'? - GNUNET_break (0); - return MHD_NO; + return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; } - return TALER_MINT_reply_refresh_commit_success (connection, &refresh_session); + res = TALER_MINT_db_execute_refresh_commit (connection, + &refresh_session_pub, + kappa, + num_oldcoins, + num_newcoins, + commit_coin, + commit_link); + // FIXME: free memory + return res; }