diff options
author | Christian Grothoff <christian@grothoff.org> | 2015-01-29 17:34:37 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2015-01-29 17:34:37 +0100 |
commit | 41e1dd9738a58ffce765d5f837c32962907707df (patch) | |
tree | b5504190c535578a53ef3b1f6768a74150e3dc33 /src | |
parent | 1e3e6fa5990eb2504a69279039ee776a19ff1ec2 (diff) |
finish cleanup of /refresh/commit parsing
Diffstat (limited to 'src')
-rw-r--r-- | src/include/taler_crypto_lib.h | 12 | ||||
-rw-r--r-- | src/mint/mint_db.c | 10 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_refresh.c | 362 | ||||
-rw-r--r-- | src/util/crypto.c | 26 |
4 files changed, 273 insertions, 137 deletions
diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h index 597c85cdd..3b4f0d8c5 100644 --- a/src/include/taler_crypto_lib.h +++ b/src/include/taler_crypto_lib.h @@ -204,5 +204,17 @@ TALER_refresh_encrypt (const struct TALER_RefreshLinkDecrypted *input, const struct TALER_LinkSecret *secret); +/** + * Decode encrypted refresh link information from buffer. + * + * @param buf buffer with refresh link data + * @param buf_len number of bytes in @a buf + * @return NULL on error (@a buf_len too small) + */ +struct TALER_RefreshLinkEncrypted * +TALER_refresh_link_encrypted_decode (const char *buf, + size_t buf_len); + + #endif diff --git a/src/mint/mint_db.c b/src/mint/mint_db.c index 0e448bf09..5c52948e6 100644 --- a/src/mint/mint_db.c +++ b/src/mint/mint_db.c @@ -1109,14 +1109,8 @@ TALER_MINT_DB_get_refresh_commit_coin (PGconn *db_conn, GNUNET_free (rl_buf); return GNUNET_SYSERR; } - - rl = GNUNET_malloc (sizeof (struct TALER_RefreshLinkEncrypted) + - rl_buf_size - sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)); - rl->blinding_key_enc = (const char *) &rl[1]; - rl->blinding_key_enc_size = rl_buf_size - sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey); - memcpy (rl->coin_priv_enc, - rl_buf, - rl_buf_size); + rl = TALER_refresh_link_encrypted_decode (rl_buf, + rl_buf_size); GNUNET_free (rl_buf); cc->refresh_link = rl; cc->coin_ev = c_buf; diff --git a/src/mint/taler-mint-httpd_refresh.c b/src/mint/taler-mint-httpd_refresh.c index 0abc82eb7..98db2054c 100644 --- a/src/mint/taler-mint-httpd_refresh.c +++ b/src/mint/taler-mint-httpd_refresh.c @@ -242,14 +242,13 @@ get_and_verify_coin_public_info (struct MHD_Connection *connection, struct RefreshMeltConfirmSignRequestBody body; struct MintKeyState *key_state; struct TALER_MINT_DenomKeyIssuePriv *dki; - struct GNUNET_MINT_ParseFieldSpec spec[] = - { - TALER_MINT_PARSE_FIXED ("coin_pub", &r_public_info->coin_pub), - TALER_MINT_PARSE_RSA_SIGNATURE ("denom_sig", &sig), - TALER_MINT_PARSE_RSA_PUBLIC_KEY ("denom_pub", &pk), - TALER_MINT_PARSE_FIXED ("confirm_sig", &melt_sig), - TALER_MINT_PARSE_END - }; + struct GNUNET_MINT_ParseFieldSpec spec[] = { + TALER_MINT_PARSE_FIXED ("coin_pub", &r_public_info->coin_pub), + TALER_MINT_PARSE_RSA_SIGNATURE ("denom_sig", &sig), + TALER_MINT_PARSE_RSA_PUBLIC_KEY ("denom_pub", &pk), + TALER_MINT_PARSE_FIXED ("confirm_sig", &melt_sig), + TALER_MINT_PARSE_END + }; ret = TALER_MINT_parse_json_data (connection, coin_info, @@ -463,108 +462,101 @@ TALER_MINT_handler_refresh_melt (struct RequestHandler *rh, /** - * Handle a "/refresh/commit" request + * Release memory from the @a commit_coin array. * - * @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 -TALER_MINT_handler_refresh_commit (struct RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) + * @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 RefreshCommitCoin **commit_coin, + unsigned int kappa, + unsigned int num_new_coins) { - struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub; - int res; 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, - upload_data, - upload_data_size, - &root); - if (GNUNET_SYSERR == res) - return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == root) ) - 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)); - if (GNUNET_OK != res) + for (i=0;i<kappa;i++) { - GNUNET_break (GNUNET_SYSERR != res); - return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; + 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]); } +} - /* 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) - { - GNUNET_break_op (0); - // FIXME: generate error message - return MHD_NO; - } - res = GNUNET_MINT_parse_navigate_json (connection, root, - JNAV_FIELD, "coin_evs", - 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) +/** + * Release memory from the @a commit_link array. + * + * @param commit_coin array to release + * @param kappa size of 1st dimension + * @param num_old_coins size of 2nd dimension + */ +static void +free_commit_links (struct RefreshCommitLink **commit_link, + unsigned int kappa, + unsigned int num_old_coins) +{ + unsigned int i; + + for (i=0;i<kappa;i++) { - GNUNET_break_op (0); - // FIXME: generate error message - return MHD_NO; + if (NULL == commit_link[i]) + break; + GNUNET_free (commit_link[i]); } - res = GNUNET_MINT_parse_navigate_json (connection, root, - JNAV_FIELD, "transfer_pubs", - JNAV_INDEX, (int) 0, - JNAV_RET_DATA, - JSON_ARRAY, &coin_detail); - if (GNUNET_OK != res) - return res; - num_oldcoins = json_array_size (coin_detail); +} + +/** + * Handle a "/refresh/commit" request. We have the individual JSON + * arrays, now we need to parse their contents and verify the + * commit signature. Then we can commit the data to the database. + * + * @param connection the MHD connection to handle + * @param refresh_session_pub public key of the refresh session + * @param commit_signature signature over the commit + * @param kappa security parameter for cut and choose + * @param num_oldcoins number of coins that are being melted + * @param transfer_pubs @a kappa-dimensional array of @a num_oldcoins transfer keys + * @param secret_encs @a kappa-dimensional array of @a num_oldcoins secrets + * @param num_newcoins number of coins that the refresh will generate + * @param coin_envs @a kappa-dimensional array of @a num_newcoins envelopes to sign + * @param link_encs @a kappa-dimensional array of @a num_newcoins encrypted links + * @return MHD result code + */ +static int +handle_refresh_commit_json (struct MHD_Connection *connection, + const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub, + const json_t *commit_signature, + unsigned int kappa, + 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) +{ + struct GNUNET_HashCode commit_hash; + struct GNUNET_HashContext *hash_context; + struct RefreshCommitSignatureBody body; + struct RefreshCommitCoin *commit_coin[kappa]; + struct RefreshCommitLink *commit_link[kappa]; + unsigned int i; + unsigned int j; + int res; + /* 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)); hash_context = GNUNET_CRYPTO_hash_context_start (); - commit_coin = GNUNET_malloc (kappa * - sizeof (struct RefreshCommitCoin *)); for (i = 0; i < kappa; i++) { commit_coin[i] = GNUNET_malloc (num_newcoins * @@ -574,8 +566,8 @@ TALER_MINT_handler_refresh_commit (struct RequestHandler *rh, char *link_enc; size_t link_enc_size; - res = GNUNET_MINT_parse_navigate_json (connection, root, - JNAV_FIELD, "coin_evs", + res = GNUNET_MINT_parse_navigate_json (connection, + coin_evs, JNAV_INDEX, (int) i, JNAV_INDEX, (int) j, JNAV_RET_DATA_VAR, @@ -584,18 +576,15 @@ TALER_MINT_handler_refresh_commit (struct RequestHandler *rh, if (GNUNET_OK != res) { - // FIXME: return 'internal error'? - GNUNET_break (0); GNUNET_CRYPTO_hash_context_abort (hash_context); + free_commit_coins (commit_coin, kappa, num_newcoins); return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; } - GNUNET_CRYPTO_hash_context_read (hash_context, commit_coin[i][j].coin_ev, commit_coin[i][j].coin_ev_size); - - res = GNUNET_MINT_parse_navigate_json (connection, root, - JNAV_FIELD, "link_encs", + res = GNUNET_MINT_parse_navigate_json (connection, + link_encs, JNAV_INDEX, (int) i, JNAV_INDEX, (int) j, JNAV_RET_DATA_VAR, @@ -603,14 +592,12 @@ TALER_MINT_handler_refresh_commit (struct RequestHandler *rh, &link_enc_size); if (GNUNET_OK != res) { - // FIXME: return 'internal error'? - GNUNET_break (0); GNUNET_CRYPTO_hash_context_abort (hash_context); + free_commit_coins (commit_coin, kappa, num_newcoins); return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; } - // FIXME: convert link_enc / link_enc_size to - // commit_coin[i][j].refresh_link! - + commit_coin[i][j].refresh_link = TALER_refresh_link_encrypted_decode (link_enc, + link_enc_size); GNUNET_CRYPTO_hash_context_read (hash_context, link_enc, @@ -618,16 +605,14 @@ TALER_MINT_handler_refresh_commit (struct RequestHandler *rh, } } - commit_link = GNUNET_malloc (kappa * - sizeof (struct RefreshCommitLink *)); for (i = 0; i < kappa; i++) { commit_link[i] = GNUNET_malloc (num_oldcoins * sizeof (struct RefreshCommitLink)); for (j = 0; j < num_oldcoins; j++) { - res = GNUNET_MINT_parse_navigate_json (connection, root, - JNAV_FIELD, "transfer_pubs", + res = GNUNET_MINT_parse_navigate_json (connection, + transfer_pubs, JNAV_INDEX, (int) i, JNAV_INDEX, (int) j, JNAV_RET_DATA, @@ -638,6 +623,8 @@ TALER_MINT_handler_refresh_commit (struct RequestHandler *rh, { GNUNET_break (GNUNET_SYSERR != res); GNUNET_CRYPTO_hash_context_abort (hash_context); + free_commit_coins (commit_coin, kappa, num_newcoins); + free_commit_links (commit_link, kappa, num_oldcoins); return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; } @@ -645,8 +632,8 @@ TALER_MINT_handler_refresh_commit (struct RequestHandler *rh, &commit_link[i][j].transfer_pub, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - res = GNUNET_MINT_parse_navigate_json (connection, root, - JNAV_FIELD, "secret_encs", + res = GNUNET_MINT_parse_navigate_json (connection, + secret_encs, JNAV_INDEX, (int) i, JNAV_INDEX, (int) j, JNAV_RET_DATA, @@ -657,6 +644,8 @@ TALER_MINT_handler_refresh_commit (struct RequestHandler *rh, { GNUNET_break (GNUNET_SYSERR != res); GNUNET_CRYPTO_hash_context_abort (hash_context); + free_commit_coins (commit_coin, kappa, num_newcoins); + free_commit_links (commit_link, kappa, num_oldcoins); return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; } @@ -667,37 +656,152 @@ TALER_MINT_handler_refresh_commit (struct RequestHandler *rh, } GNUNET_CRYPTO_hash_context_finish (hash_context, &commit_hash); - commit_sig_json = json_object_get (root, "commit_signature"); - if (NULL == commit_sig_json) - { - return TALER_MINT_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s}", - "error", - "commit_signature missing"); - } - - body.commit_hash = commit_hash; + /* verify commit signature */ body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_COMMIT); body.purpose.size = htonl (sizeof (struct RefreshCommitSignatureBody)); + body.commit_hash = commit_hash; if (GNUNET_OK != (res = request_json_check_signature (connection, - commit_sig_json, - &refresh_session_pub, + commit_signature, + refresh_session_pub, &body.purpose))) { + free_commit_coins (commit_coin, kappa, num_newcoins); + free_commit_links (commit_link, kappa, num_oldcoins); return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; } + /* execute commit */ + /* FIXME: we must also store the signature! */ res = TALER_MINT_db_execute_refresh_commit (connection, - &refresh_session_pub, + refresh_session_pub, kappa, num_oldcoins, num_newcoins, commit_coin, commit_link); - // FIXME: free memory + free_commit_coins (commit_coin, kappa, num_newcoins); + free_commit_links (commit_link, kappa, num_oldcoins); + + return res; +} + + +/** + * Handle a "/refresh/commit" request. Parses the top-level JSON to + * determine the dimensions of the problem and then handles handing + * off to #handle_refresh_commit_json() to parse the details of the + * JSON arguments. + * + * @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 +TALER_MINT_handler_refresh_commit (struct RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub; + int res; + unsigned int kappa; + unsigned int num_oldcoins; + unsigned int num_newcoins; + json_t *root; + json_t *coin_evs; + json_t *link_encs; + json_t *transfer_pubs; + json_t *secret_encs; + json_t *coin_detail; + json_t *commit_sig_json; + struct GNUNET_MINT_ParseFieldSpec spec[] = { + TALER_MINT_PARSE_FIXED ("session_pub", &refresh_session_pub), + TALER_MINT_PARSE_ARRAY ("coin_evs", &coin_evs), + TALER_MINT_PARSE_ARRAY ("link_encs", &link_encs), + TALER_MINT_PARSE_ARRAY ("transfer_pubs", &transfer_pubs), + TALER_MINT_PARSE_ARRAY ("secret_encs", &secret_encs), + TALER_MINT_PARSE_OBJECT ("commit_signature", &commit_sig_json), + TALER_MINT_PARSE_END + }; + + res = TALER_MINT_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 = TALER_MINT_parse_json_data (connection, + root, + spec); + if (GNUNET_OK != res) + { + json_decref (root); + return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; + } + + /* Determine dimensionality of the request (kappa, #old and #new coins) */ + kappa = json_array_size (coin_evs); + if (3 > kappa) + { + GNUNET_break_op (0); + json_decref (root); + TALER_MINT_release_parsed_data (spec); + return TALER_MINT_reply_arg_invalid (connection, + "coin_evs"); + } + if (json_array_size (transfer_pubs) != kappa) + { + GNUNET_break_op (0); + json_decref (root); + TALER_MINT_release_parsed_data (spec); + return TALER_MINT_reply_arg_invalid (connection, + "transfer_pubs"); + } + res = GNUNET_MINT_parse_navigate_json (connection, coin_evs, + JNAV_INDEX, (int) 0, + JNAV_RET_DATA, + JSON_ARRAY, &coin_detail); + if (GNUNET_OK != res) + { + json_decref (root); + TALER_MINT_release_parsed_data (spec); + return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; + } + num_newcoins = json_array_size (coin_detail); + res = GNUNET_MINT_parse_navigate_json (connection, root, + JNAV_FIELD, "transfer_pubs", + JNAV_INDEX, (int) 0, + JNAV_RET_DATA, + JSON_ARRAY, &coin_detail); + if (GNUNET_OK != res) + { + json_decref (root); + TALER_MINT_release_parsed_data (spec); + return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; + } + num_oldcoins = json_array_size (coin_detail); + res = handle_refresh_commit_json (connection, + &refresh_session_pub, + commit_sig_json, + kappa, + num_oldcoins, + transfer_pubs, + secret_encs, + num_newcoins, + coin_evs, + link_encs); + TALER_MINT_release_parsed_data (spec); + json_decref (root); return res; } diff --git a/src/util/crypto.c b/src/util/crypto.c index 12f452085..25f951e86 100644 --- a/src/util/crypto.c +++ b/src/util/crypto.c @@ -269,6 +269,32 @@ TALER_refresh_encrypt (const struct TALER_RefreshLinkDecrypted *input, /** + * Decode encrypted refresh link information from buffer. + * + * @param buf buffer with refresh link data + * @param buf_len number of bytes in @a buf + * @return NULL on error (@a buf_len too small) + */ +struct TALER_RefreshLinkEncrypted * +TALER_refresh_link_encrypted_decode (const char *buf, + size_t buf_len) +{ + struct TALER_RefreshLinkEncrypted *rle; + + if (buf_len < sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)) + return NULL; + rle = GNUNET_malloc (sizeof (struct TALER_RefreshLinkEncrypted) + + buf_len - sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)); + rle->blinding_key_enc = (const char *) &rle[1]; + rle->blinding_key_enc_size = buf_len - sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey); + memcpy (rle->coin_priv_enc, + buf, + buf_len); + return rle; +} + + +/** * Check if a coin is valid; that is, whether the denomination key exists, * is not expired, and the signature is correct. * |