summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-03-10 17:00:12 +0100
committerChristian Grothoff <christian@grothoff.org>2015-03-10 17:00:12 +0100
commit7e26ae385896a974d8a90234a155c32b383e70f7 (patch)
tree1bbcf3e317744c9fa024bba5a6e46c84520dc9e5
parente3b8f5117e8028f3183871ab0efb0c6f2ff959eb (diff)
downloadexchange-7e26ae385896a974d8a90234a155c32b383e70f7.tar.gz
exchange-7e26ae385896a974d8a90234a155c32b383e70f7.tar.bz2
exchange-7e26ae385896a974d8a90234a155c32b383e70f7.zip
clean up refresh logic and use of signatures
-rw-r--r--src/include/taler_signatures.h48
-rw-r--r--src/mint/taler-mint-httpd_refresh.c293
-rw-r--r--src/mint/taler-mint-httpd_responses.c7
3 files changed, 145 insertions, 203 deletions
diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h
index 9e3068a78..b1b578236 100644
--- a/src/include/taler_signatures.h
+++ b/src/include/taler_signatures.h
@@ -65,7 +65,7 @@
* Signature where the refresh session confirms
* the commits.
*/
-#define TALER_SIGNATURE_REFRESH_MELT 6
+#define TALER_SIGNATURE_REFRESH_MELT_SESSION 6
/**
* Signature where the mint (current signing key)
@@ -221,7 +221,7 @@ struct TALER_DepositConfirmation
struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub;
/**
- * The Merachant's public key.
+ * The Merchant's public key.
*/
struct GNUNET_CRYPTO_EddsaPublicKey merchant;
@@ -232,7 +232,7 @@ struct TALER_DepositConfirmation
* Message signed by a coin to indicate that the coin should
* be melted.
*/
-struct RefreshMeltSignatureBody
+struct RefreshMeltCoinSignature
{
/**
* Purpose is #TALER_SIGNATURE_REFRESH_MELT_COIN.
@@ -245,42 +245,46 @@ struct RefreshMeltSignatureBody
struct GNUNET_HashCode melt_hash;
/**
- * Signature of the client over the melt request (thereby
- * indirectly including all of the information the client
- * sent).
- */
- struct GNUNET_CRYPTO_EddsaSignature melt_client_signature;
-
- /**
- * Public key of the refresh session for which
- * @e melt_client_signature must be a valid signature.
- */
- struct GNUNET_CRYPTO_EddsaPublicKey session_key;
-
- /**
* How much of the value of the coin should 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_AmountNBO amount;
+
+ /**
+ * The coin's public key.
+ */
+ struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub;
};
/**
- * Message signed during melting committing the client to the
- * hashed inputs.
+ * Message signed by a coin to indicate that the coin should
+ * be melted.
*/
-struct RefreshCommitSignatureBody
+struct RefreshMeltSessionSignature
{
/**
- * Purpose is #TALER_SIGNATURE_REFRESH_MELT.
+ * Purpose is #TALER_SIGNATURE_REFRESH_MELT_SESSION
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/**
- * Session state the client commits itself to.
+ * Which melting operation should the coin become a part of.
+ */
+ struct GNUNET_HashCode melt_hash;
+
+ /**
+ * Public key of the refresh session for which
+ * @e melt_client_signature must be a valid signature.
*/
- struct GNUNET_HashCode commit_hash;
+ struct GNUNET_CRYPTO_EddsaPublicKey session_key;
+
+ /**
+ * What is the total value of the coins created during the
+ * refresh, excluding fees?
+ */
+ struct TALER_AmountNBO amount;
};
diff --git a/src/mint/taler-mint-httpd_refresh.c b/src/mint/taler-mint-httpd_refresh.c
index 6c3cbbc71..d36e42085 100644
--- a/src/mint/taler-mint-httpd_refresh.c
+++ b/src/mint/taler-mint-httpd_refresh.c
@@ -36,109 +36,6 @@
/**
- * Verify a signature that is encoded in a JSON object. Extracts
- * the signature and its associated purpose and checks that it
- * matches the specified @a purpose and @a pub public key. Any
- * errors are reported via appropriate response messages.
- *
- * @param connection the connection to send errors to
- * @param json_sig the JSON object with the signature
- * @param the public key that the signature was created with
- * @param purpose the signed message
- * @return #GNUNET_YES if the signature was valid
- * #GNUNET_NO if the signature was invalid
- * #GNUNET_SYSERR on internal error
- */
-static int
-request_json_check_signature (struct MHD_Connection *connection,
- const json_t *json_sig,
- const struct GNUNET_CRYPTO_EddsaPublicKey *pub,
- const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
-{
- struct GNUNET_CRYPTO_EddsaSignature signature;
- int size;
- uint32_t purpose_num;
- int res;
- json_t *el;
-
- /* TODO: use specification array to simplify the parsing! */
- res = GNUNET_MINT_parse_navigate_json (connection,
- json_sig,
- JNAV_FIELD,
- "sig",
- JNAV_RET_DATA,
- &signature,
- sizeof (struct GNUNET_CRYPTO_EddsaSignature));
-
- if (GNUNET_OK != res)
- return res;
-
- res = GNUNET_MINT_parse_navigate_json (connection,
- json_sig,
- JNAV_FIELD,
- "purpose",
- JNAV_RET_TYPED_JSON,
- JSON_INTEGER,
- &el);
-
- if (GNUNET_OK != res)
- return res;
-
- purpose_num = json_integer_value (el);
-
- if (purpose_num != ntohl (purpose->purpose))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "signature invalid (purpose wrong)\n");
- return TALER_MINT_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- "{s:s}",
- "error", "signature invalid (purpose)");
- }
-
- res = GNUNET_MINT_parse_navigate_json (connection,
- json_sig,
- JNAV_FIELD, "size",
- JNAV_RET_TYPED_JSON,
- JSON_INTEGER,
- &el);
-
- if (GNUNET_OK != res)
- return res;
-
- size = json_integer_value (el);
-
- if (size != ntohl (purpose->size))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "signature invalid (size wrong)\n");
- return TALER_MINT_reply_json_pack (connection,
- MHD_HTTP_BAD_REQUEST,
- GNUNET_NO, GNUNET_SYSERR,
- "{s:s}",
- "error",
- "signature invalid (size)");
- }
-
- if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (purpose_num,
- purpose,
- &signature,
- pub))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "signature invalid (did not verify)\n");
- return TALER_MINT_reply_json_pack (connection,
- MHD_HTTP_UNAUTHORIZED,
- "{s:s}",
- "error",
- "invalid signature (verification)");
- }
-
- return GNUNET_OK;
-}
-
-
-/**
* 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.
@@ -150,7 +47,7 @@ request_json_check_signature (struct MHD_Connection *connection,
* @param coin_count number of coins to be melted, size of y-dimension of @commit_coin array
* @param coin_public_infos array with @a coin_count entries about the coins
* @param coin_melt_details array with @a coin_count entries with melting details
- * @param melt_sig_json signature affirming the overall melt operation
+ * @param commit_hash hash over the data that the client commits to
* @param commit_client_sig signature of the client over this commitment
* @param kappa size of x-dimension of @commit_coin and @commit_link arrays
* @param commit_coin 2d array of coin commitments (what the mint is to sign
@@ -168,18 +65,17 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
unsigned int coin_count,
struct TALER_CoinPublicInfo *coin_public_infos,
const struct MeltDetails *coin_melt_details,
- const json_t *melt_sig_json,
+ const struct GNUNET_HashCode *commit_hash,
const struct GNUNET_CRYPTO_EddsaSignature *commit_client_sig,
unsigned int kappa,
struct RefreshCommitCoin *const* commit_coin,
struct RefreshCommitLink *const* commit_link)
{
- int res;
unsigned int i;
struct GNUNET_HashContext *hash_context;
struct GNUNET_HashCode melt_hash;
- struct RefreshMeltSignatureBody body;
+ struct RefreshMeltSessionSignature body;
char *buf;
size_t buf_size;
struct MintKeyState *key_state;
@@ -207,18 +103,26 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
GNUNET_CRYPTO_hash_context_finish (hash_context,
&melt_hash);
+ // FIXME: what about the `commit_hash`?
- body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT);
- body.purpose.size = htonl (sizeof (struct RefreshMeltSignatureBody));
+ body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_SESSION);
+ body.purpose.size = htonl (sizeof (struct RefreshMeltSessionSignature));
body.melt_hash = melt_hash;
body.amount = TALER_amount_hton (coin_melt_details->melt_amount);
- if (GNUNET_OK !=
- (res = request_json_check_signature (connection,
- melt_sig_json,
- refresh_session_pub,
- &body.purpose)))
- return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+ if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_REFRESH_MELT_SESSION,
+ &body.purpose,
+ commit_client_sig,
+ refresh_session_pub))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "signature invalid (did not verify)\n");
+ return TALER_MINT_reply_json_pack (connection,
+ MHD_HTTP_UNAUTHORIZED,
+ "{s:s}",
+ "error",
+ "invalid signature (verification)");
+ }
// FIXME: badness, use proper way to set to zero...
key_state = TALER_MINT_key_state_acquire ();
@@ -276,15 +180,9 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
/**
- * Extract public coin information from a JSON object and 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.
+ * Extract public coin information from a JSON object.
*
* @param connection the connection to send error responses to
- * @param session_pub public key of the session the coin is melted into
* @param coin_info the JSON object to extract the coin info from
* @param r_public_info[OUT] set to the coin's public information
* @param r_melt_detail[OUT] set to details about the coin's melting permission (if valid)
@@ -293,19 +191,15 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
* #GNUNET_SYSERR on internal error
*/
static int
-get_and_verify_coin_public_info (struct MHD_Connection *connection,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
- json_t *coin_info,
- struct TALER_CoinPublicInfo *r_public_info,
- struct MeltDetails *r_melt_detail)
+get_coin_public_info (struct MHD_Connection *connection,
+ json_t *coin_info,
+ struct TALER_CoinPublicInfo *r_public_info,
+ struct MeltDetails *r_melt_detail)
{
int ret;
struct GNUNET_CRYPTO_EcdsaSignature melt_sig;
struct GNUNET_CRYPTO_rsa_Signature *sig;
struct GNUNET_CRYPTO_rsa_PublicKey *pk;
- struct RefreshMeltConfirmSignRequestBody body;
- struct MintKeyState *key_state;
- struct TALER_MINT_DenomKeyIssuePriv *dki;
struct TALER_Amount amount;
struct GNUNET_MINT_ParseFieldSpec spec[] = {
TALER_MINT_PARSE_FIXED ("coin_pub", &r_public_info->coin_pub),
@@ -316,6 +210,7 @@ get_and_verify_coin_public_info (struct MHD_Connection *connection,
TALER_MINT_PARSE_END
};
+ memset (&amount, 0, sizeof (amount)); // FIXME: #3636!
ret = TALER_MINT_parse_json_data (connection,
coin_info,
spec);
@@ -323,17 +218,68 @@ get_and_verify_coin_public_info (struct MHD_Connection *connection,
return ret;
/* FIXME: include amount of coin value to be melted here (#3636!) and
in what we return!? */
- memset (&amount, 0, sizeof (amount)); // FIXME: #3636!
- body.purpose.size = htonl (sizeof (struct RefreshMeltConfirmSignRequestBody));
- body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_CONFIRM);
- body.session_pub = *session_pub;
+
+ /* check mint signature on the coin */
+ r_public_info->denom_sig = sig;
+ r_public_info->denom_pub = pk;
if (GNUNET_OK !=
- GNUNET_CRYPTO_ecdsa_verify (TALER_SIGNATURE_REFRESH_MELT_CONFIRM,
+ TALER_test_coin_valid (r_public_info))
+ {
+ TALER_MINT_release_parsed_data (spec);
+ r_public_info->denom_sig = NULL;
+ r_public_info->denom_pub = NULL;
+ return (MHD_YES ==
+ TALER_MINT_reply_json_pack (connection,
+ MHD_HTTP_NOT_FOUND,
+ "{s:s}",
+ "error", "coin invalid"))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ }
+ r_melt_detail->melt_sig = melt_sig;
+ r_melt_detail->melt_amount = amount;
+ TALER_MINT_release_parsed_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 melt_hash hash over refresh session the coin is melted into
+ * @param r_public_info the coin's public information
+ * @param r_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 *melt_hash,
+ const struct TALER_CoinPublicInfo *r_public_info,
+ const struct MeltDetails *r_melt_detail)
+{
+ struct RefreshMeltCoinSignature body;
+ struct MintKeyState *key_state;
+ struct TALER_MINT_DenomKeyIssuePriv *dki;
+
+ /* FIXME: include amount of coin value to be melted here (#3636!) and
+ in what we return!? */
+ body.purpose.size = htonl (sizeof (struct RefreshMeltCoinSignature));
+ body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_COIN);
+ body.melt_hash = *melt_hash;
+ body.amount = TALER_amount_hton (r_melt_detail->melt_amount);
+ body.coin_pub = r_public_info->coin_pub;
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_ecdsa_verify (TALER_SIGNATURE_REFRESH_MELT_COIN,
&body.purpose,
- &melt_sig,
+ &r_melt_detail->melt_sig,
&r_public_info->coin_pub))
{
- TALER_MINT_release_parsed_data (spec);
if (MHD_YES !=
TALER_MINT_reply_json_pack (connection,
MHD_HTTP_UNAUTHORIZED,
@@ -344,7 +290,7 @@ get_and_verify_coin_public_info (struct MHD_Connection *connection,
}
key_state = TALER_MINT_key_state_acquire ();
dki = TALER_MINT_get_denom_key (key_state,
- pk);
+ r_public_info->denom_pub);
/* FIXME: need to check if denomination key is still
valid for issuing! (#3634) */
if (NULL == dki)
@@ -355,25 +301,6 @@ get_and_verify_coin_public_info (struct MHD_Connection *connection,
"denom_pub");
}
TALER_MINT_key_state_release (key_state);
-
- /* check mint signature on the coin */
- r_public_info->denom_sig = sig;
- r_public_info->denom_pub = pk;
- if (GNUNET_OK !=
- TALER_test_coin_valid (r_public_info))
- {
- TALER_MINT_release_parsed_data (spec);
- r_public_info->denom_sig = NULL;
- r_public_info->denom_pub = NULL;
- return (MHD_YES ==
- TALER_MINT_reply_json_pack (connection,
- MHD_HTTP_NOT_FOUND,
- "{s:s}",
- "error", "coin invalid"))
- ? GNUNET_NO : GNUNET_SYSERR;
- }
- r_melt_detail->melt_sig = melt_sig;
- r_melt_detail->melt_amount = amount;
return GNUNET_OK;
}
@@ -478,9 +405,9 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
unsigned int coin_count;
struct GNUNET_HashCode commit_hash;
struct GNUNET_HashContext *hash_context;
- struct RefreshCommitSignatureBody body;
struct RefreshCommitCoin *commit_coin[kappa];
struct RefreshCommitLink *commit_link[kappa];
+ const struct GNUNET_CRYPTO_EddsaSignature commit_client_sig;
num_new_denoms = json_array_size (new_denoms);
denom_pubs = GNUNET_malloc (num_new_denoms *
@@ -509,11 +436,10 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
for (i=0;i<coin_count;i++)
{
/* decode JSON data on coin to melt */
- res = get_and_verify_coin_public_info (connection,
- refresh_session_pub,
- json_array_get (melt_coins, i),
- &coin_public_infos[i],
- &coin_melt_details[i]);
+ res = get_coin_public_info (connection,
+ json_array_get (melt_coins, i),
+ &coin_public_infos[i],
+ &coin_melt_details[i]);
if (GNUNET_OK != res)
{
for (j=0;j<i;j++)
@@ -635,24 +561,34 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
}
GNUNET_CRYPTO_hash_context_finish (hash_context, &commit_hash);
- /* verify commit signature */
- body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT);
- body.purpose.size = htonl (sizeof (struct RefreshCommitSignatureBody));
- body.commit_hash = commit_hash;
- if (GNUNET_OK !=
- (res = request_json_check_signature (connection,
- commit_signature,
- refresh_session_pub,
- &body.purpose)))
+ res = GNUNET_MINT_parse_navigate_json (connection,
+ commit_signature,
+ JNAV_FIELD,
+ "sig",
+ JNAV_RET_DATA,
+ &commit_client_sig,
+ sizeof (struct GNUNET_CRYPTO_EddsaSignature));
+
+ if (GNUNET_OK != res)
+ return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+
+
+ for (i=0;i<coin_count;i++)
{
- free_commit_coins (commit_coin, kappa, num_newcoins);
- free_commit_links (commit_link, kappa, num_oldcoins);
- return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
+ /* verify signatures ons coin to melt */
+ res = verify_coin_public_info (connection,
+ &commit_hash,
+ &coin_public_infos[i],
+ &coin_melt_details[i]);
+ if (GNUNET_OK != res)
+ {
+ res = (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+ goto cleanup;
+ }
}
/* execute commit */
- /* FIXME: we must also store the signature! (#3635) */
res = handle_refresh_melt_binary (connection,
refresh_session_pub,
num_new_denoms,
@@ -660,11 +596,12 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
coin_count,
coin_public_infos,
coin_melt_details,
- melt_sig_json,
- NULL /* FIXME: 3635! */,
+ &commit_hash,
+ &commit_client_sig,
kappa,
commit_coin,
commit_link);
+ cleanup:
free_commit_coins (commit_coin, kappa, num_newcoins);
free_commit_links (commit_link, kappa, num_oldcoins);
for (j=0;j<coin_count;j++)
diff --git a/src/mint/taler-mint-httpd_responses.c b/src/mint/taler-mint-httpd_responses.c
index 83c81e800..2faeb5ca8 100644
--- a/src/mint/taler-mint-httpd_responses.c
+++ b/src/mint/taler-mint-httpd_responses.c
@@ -355,15 +355,16 @@ compile_transaction_history (const struct TALER_MINT_DB_TransactionList *tl)
}
case TALER_MINT_DB_TT_REFRESH_MELT:
{
- struct RefreshMeltSignatureBody ms;
+ struct RefreshMeltCoinSignature ms;
const struct RefreshMelt *melt = pos->details.melt;
type = "melt";
value = melt->amount;
- ms.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT);
- ms.purpose.size = htonl (sizeof (struct RefreshMeltSignatureBody));
+ ms.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_COIN);
+ ms.purpose.size = htonl (sizeof (struct RefreshMeltCoinSignature));
ms.melt_hash = melt->melt_hash;
ms.amount = TALER_amount_hton (melt->amount);
+ ms.coin_pub = melt->coin.coin_pub;
transaction = TALER_JSON_from_ecdsa_sig (&ms.purpose,
&melt->coin_sig);
}