summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-01-29 17:34:37 +0100
committerChristian Grothoff <christian@grothoff.org>2015-01-29 17:34:37 +0100
commit41e1dd9738a58ffce765d5f837c32962907707df (patch)
treeb5504190c535578a53ef3b1f6768a74150e3dc33
parent1e3e6fa5990eb2504a69279039ee776a19ff1ec2 (diff)
downloadexchange-41e1dd9738a58ffce765d5f837c32962907707df.tar.gz
exchange-41e1dd9738a58ffce765d5f837c32962907707df.tar.bz2
exchange-41e1dd9738a58ffce765d5f837c32962907707df.zip
finish cleanup of /refresh/commit parsing
-rw-r--r--src/include/taler_crypto_lib.h12
-rw-r--r--src/mint/mint_db.c10
-rw-r--r--src/mint/taler-mint-httpd_refresh.c362
-rw-r--r--src/util/crypto.c26
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.
*