summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-03-09 12:29:41 +0100
committerChristian Grothoff <christian@grothoff.org>2015-03-09 12:29:41 +0100
commit579f465c9b2ed1cd4602ee102073d633fda60cb9 (patch)
tree99b546c629bfa876ccbe4f829a68c3fe8d80624a
parent7b0ae9c1d0a3c3165a8cef8cc12d04d207a49ce2 (diff)
downloadexchange-579f465c9b2ed1cd4602ee102073d633fda60cb9.tar.gz
exchange-579f465c9b2ed1cd4602ee102073d633fda60cb9.tar.bz2
exchange-579f465c9b2ed1cd4602ee102073d633fda60cb9.zip
implementing #3632: generate proof of insufficient funds by converting transaction history to JSON
-rw-r--r--src/include/taler_json_lib.h30
-rw-r--r--src/include/taler_signatures.h105
-rw-r--r--src/mint/mint_db.h13
-rw-r--r--src/mint/taler-mint-httpd_db.c15
-rw-r--r--src/mint/taler-mint-httpd_db.h5
-rw-r--r--src/mint/taler-mint-httpd_refresh.c4
-rw-r--r--src/mint/taler-mint-httpd_responses.c68
-rw-r--r--src/util/json.c50
8 files changed, 223 insertions, 67 deletions
diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h
index f0ae923f4..2b9d51875 100644
--- a/src/include/taler_json_lib.h
+++ b/src/include/taler_json_lib.h
@@ -60,8 +60,20 @@ TALER_JSON_from_abs (struct GNUNET_TIME_Absolute stamp);
* @return the JSON reporesentation of the signature with purpose
*/
json_t *
-TALER_JSON_from_sig (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
- const struct GNUNET_CRYPTO_EddsaSignature *signature);
+TALER_JSON_from_eddsa_sig (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+ const struct GNUNET_CRYPTO_EddsaSignature *signature);
+
+
+/**
+ * Convert a signature (with purpose) to a JSON object representation.
+ *
+ * @param purpose purpose of the signature
+ * @param signature the signature
+ * @return the JSON reporesentation of the signature with purpose
+ */
+json_t *
+TALER_JSON_from_ecdsa_sig (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+ const struct GNUNET_CRYPTO_EcdsaSignature *signature);
/**
@@ -77,6 +89,17 @@ TALER_JSON_from_data (const void *data, size_t size);
/**
+ * Convert binary hash to a JSON string with the base32crockford
+ * encoding.
+ *
+ * @param hc binary data
+ * @return json string that encodes @a hc
+ */
+json_t *
+TALER_JSON_from_hash (const struct GNUNET_HashCode *hc);
+
+
+/**
* Parse given JSON object to Amount
*
* @param json the json object representing Amount
@@ -119,7 +142,8 @@ TALER_JSON_to_data (json_t *json,
* @return 1 if correctly formatted; 0 if not
*/
int
-TALER_JSON_validate_wireformat (const char *type, json_t *wire);
+TALER_JSON_validate_wireformat (const char *type,
+ json_t *wire);
#endif /* TALER_JSON_LIB_H_ */
diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h
index 905d1ed23..8984165e6 100644
--- a/src/include/taler_signatures.h
+++ b/src/include/taler_signatures.h
@@ -266,83 +266,120 @@ struct RefreshMeltResponseSignatureBody
};
-
-
-
/**
- * FIXME
+ * Message signed by a coin to indicate that the coin should
+ * be melted.
*/
-struct TALER_MINT_SignKeyIssue
+struct RefreshMeltSignatureBody
{
- struct GNUNET_CRYPTO_EddsaSignature signature;
+ /**
+ * Purpose is #TALER_SIGNATURE_REFRESH_MELT.
+ */
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_CRYPTO_EddsaPublicKey master_pub;
- struct GNUNET_TIME_AbsoluteNBO start;
- struct GNUNET_TIME_AbsoluteNBO expire;
- struct GNUNET_CRYPTO_EddsaPublicKey signkey_pub;
+
+ /**
+ * Which melting operation should the coin become a part of.
+ */
+ struct GNUNET_HashCode melt_hash;
+
+ /**
+ * 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;
};
/**
- * FIXME
+ * Message signed during melting committing the client to the
+ * hashed inputs.
*/
-struct TALER_MINT_DenomKeyIssue
+struct RefreshCommitSignatureBody
{
- struct GNUNET_CRYPTO_EddsaSignature signature;
+ /**
+ * Purpose is #TALER_SIGNATURE_REFRESH_COMMIT.
+ */
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_CRYPTO_EddsaPublicKey master;
- struct GNUNET_TIME_AbsoluteNBO start;
- struct GNUNET_TIME_AbsoluteNBO expire_withdraw;
- struct GNUNET_TIME_AbsoluteNBO expire_spend;
- // FIXME: does not work like this:
- struct GNUNET_CRYPTO_rsa_PublicKey * denom_pub;
- struct TALER_AmountNBO value;
- struct TALER_AmountNBO fee_withdraw;
- struct TALER_AmountNBO fee_deposit;
- struct TALER_AmountNBO fee_refresh;
+
+ /**
+ * Session state the client commits itself to.
+ */
+ struct GNUNET_HashCode commit_hash;
};
/**
- * FIXME
+ * Message signed by the mint, committing it to a particular
+ * index to not be revealed during the refresh.
*/
-struct RefreshMeltSignatureBody
+struct RefreshCommitResponseSignatureBody
{
+ /**
+ * Purpose is #TALER_SIGNATURE_REFRESH_MELT_RESPONSE.
+ */
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_HashCode melt_hash;
+
+ /**
+ * Index that the client will not have to reveal.
+ */
+ uint16_t noreveal_index GNUNET_PACKED;
};
+
/**
- * FIXME
+ * Message signed by the client requesting the final
+ * result of the melting operation.
*/
-struct RefreshCommitSignatureBody
+struct RefreshMeltConfirmSignRequestBody
{
+ /**
+ * Purpose is #TALER_SIGNATURE_REFRESH_MELT_CONFIRM.
+ */
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_HashCode commit_hash;
+
+ /**
+ * FIXME.
+ */
+ struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
};
/**
* FIXME
*/
-struct RefreshCommitResponseSignatureBody
+struct TALER_MINT_SignKeyIssue
{
+ struct GNUNET_CRYPTO_EddsaSignature signature;
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- uint16_t noreveal_index;
+ struct GNUNET_CRYPTO_EddsaPublicKey master_pub;
+ struct GNUNET_TIME_AbsoluteNBO start;
+ struct GNUNET_TIME_AbsoluteNBO expire;
+ struct GNUNET_CRYPTO_EddsaPublicKey signkey_pub;
};
-
/**
* FIXME
*/
-struct RefreshMeltConfirmSignRequestBody
+struct TALER_MINT_DenomKeyIssue
{
+ struct GNUNET_CRYPTO_EddsaSignature signature;
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
+ struct GNUNET_CRYPTO_EddsaPublicKey master;
+ struct GNUNET_TIME_AbsoluteNBO start;
+ struct GNUNET_TIME_AbsoluteNBO expire_withdraw;
+ struct GNUNET_TIME_AbsoluteNBO expire_spend;
+ // FIXME: does not work like this:
+ struct GNUNET_CRYPTO_rsa_PublicKey * denom_pub;
+ struct TALER_AmountNBO value;
+ struct TALER_AmountNBO fee_withdraw;
+ struct TALER_AmountNBO fee_deposit;
+ struct TALER_AmountNBO fee_refresh;
};
+
GNUNET_NETWORK_STRUCT_END
#endif
diff --git a/src/mint/mint_db.h b/src/mint/mint_db.h
index 74f0c2d14..c3a300a57 100644
--- a/src/mint/mint_db.h
+++ b/src/mint/mint_db.h
@@ -222,8 +222,6 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db,
const struct TALER_Amount balance,
const struct GNUNET_TIME_Absolute expiry);
-/* FIXME: need call to convert CollectableBlindcoin to JSON (#3527) */
-
/**
* Locate the response for a /withdraw request under the
@@ -529,10 +527,8 @@ TALER_MINT_DB_update_refresh_session (PGconn *db_conn,
/**
* Specification for coin in a /refresh/melt operation.
- * FIXME: same as `struct MeltDetails`, and not by accident!
- * We should merge the structs!
*/
-struct RefreshMelt /* FIXME: name to make it clearer this is about ONE coin! */
+struct RefreshMelt
{
/**
* Information about the coin that is being melted.
@@ -545,7 +541,14 @@ struct RefreshMelt /* FIXME: name to make it clearer this is about ONE coin! */
struct GNUNET_CRYPTO_EcdsaSignature coin_sig;
/**
+ * Which melting operation should the coin become a part of.
+ */
+ struct GNUNET_HashCode melt_hash;
+
+ /**
* How much value is being 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_Amount amount;
diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c
index e3f7b754c..ed9119313 100644
--- a/src/mint/taler-mint-httpd_db.c
+++ b/src/mint/taler-mint-httpd_db.c
@@ -22,10 +22,6 @@
* - actually abstract DB implementation (i.e. via plugin logic)
* (this file should remain largely unchanged with the exception
* of the PQ-specific DB handle types)
- * - /refresh/link:
- * + check low-level API
- * + separate DB logic from response generation
- * + check for leaks
*/
#include "platform.h"
#include <pthread.h>
@@ -354,8 +350,8 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
break;
}
}
-
- /* FIXME: good place to assert deposit_total > withdraw_total... */
+ GNUNET_break (0 > TALER_amount_cmp (withdraw_total,
+ deposit_total));
balance = TALER_amount_subtract (deposit_total,
withdraw_total);
if (0 < TALER_amount_cmp (amount_required,
@@ -382,8 +378,6 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
return TALER_MINT_reply_internal_error (connection,
"Internal error");
}
-
- // FIXME: can we avoid the cast?
collectable.denom_pub = (struct GNUNET_CRYPTO_rsa_PublicKey *) denomination_pub;
collectable.sig = sig;
collectable.reserve_pub = *reserve;
@@ -430,6 +424,7 @@ static int
refresh_accept_melts (struct MHD_Connection *connection,
PGconn *db_conn,
const struct MintKeyState *key_state,
+ const struct GNUNET_HashCode *melt_hash,
const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
const struct TALER_CoinPublicInfo *coin_public_info,
const struct MeltDetails *coin_details,
@@ -474,6 +469,7 @@ refresh_accept_melts (struct MHD_Connection *connection,
melt.coin = *coin_public_info;
melt.coin_sig = coin_details->melt_sig;
+ melt.melt_hash = *melt_hash;
melt.amount = coin_details->melt_amount;
if (GNUNET_OK !=
TALER_MINT_DB_insert_refresh_melt (db_conn,
@@ -496,6 +492,7 @@ refresh_accept_melts (struct MHD_Connection *connection,
* melted and confirm the melting operation to the client.
*
* @param connection the MHD connection to handle
+ * @param melt_hash hash code of the session the coins are melted into
* @param refresh_session_pub public key of the refresh session
* @param client_signature signature of the client (matching @a refresh_session_pub)
* over the melting request
@@ -508,6 +505,7 @@ refresh_accept_melts (struct MHD_Connection *connection,
*/
int
TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
+ const struct GNUNET_HashCode *melt_hash,
const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
const struct GNUNET_CRYPTO_EddsaSignature *client_signature,
unsigned int num_new_denoms,
@@ -558,6 +556,7 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
(res = refresh_accept_melts (connection,
db_conn,
key_state,
+ melt_hash,
refresh_session_pub,
&coin_public_infos[i],
&coin_melt_details[i],
diff --git a/src/mint/taler-mint-httpd_db.h b/src/mint/taler-mint-httpd_db.h
index b945a7f65..dcd5e6fa0 100644
--- a/src/mint/taler-mint-httpd_db.h
+++ b/src/mint/taler-mint-httpd_db.h
@@ -93,7 +93,8 @@ struct MeltDetails
/**
* How much of the coin's value did the client allow to be melted?
- * (FIXME: are the fees included here!?)
+ * 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_Amount melt_amount;
};
@@ -107,6 +108,7 @@ struct MeltDetails
* melted and confirm the melting operation to the client.
*
* @param connection the MHD connection to handle
+ * @param melt_hash hash code of the session the coins are melted into
* @param refresh_session_pub public key of the refresh session
* @param client_signature signature of the client (matching @a refresh_session_pub)
* over the melting request
@@ -119,6 +121,7 @@ struct MeltDetails
*/
int
TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
+ const struct GNUNET_HashCode *melt_hash,
const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
const struct GNUNET_CRYPTO_EddsaSignature *client_signature,
unsigned int num_new_denoms,
diff --git a/src/mint/taler-mint-httpd_refresh.c b/src/mint/taler-mint-httpd_refresh.c
index cae001acc..5625dc8c7 100644
--- a/src/mint/taler-mint-httpd_refresh.c
+++ b/src/mint/taler-mint-httpd_refresh.c
@@ -195,9 +195,10 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
GNUNET_CRYPTO_hash_context_finish (hash_context,
&melt_hash);
- body.melt_hash = melt_hash;
body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT);
body.purpose.size = htonl (sizeof (struct RefreshMeltSignatureBody));
+ body.melt_hash = melt_hash;
+ body.amount = TALER_amount_hton (coin_melt_details->melt_amount);
if (GNUNET_OK !=
(res = request_json_check_signature (connection,
@@ -247,6 +248,7 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
/* FIXME: we must also store the signature over the melt! (#3635) */
return TALER_MINT_db_execute_refresh_melt (connection,
+ &melt_hash,
refresh_session_pub,
NULL, /* FIXME: #3635! */
num_new_denoms,
diff --git a/src/mint/taler-mint-httpd_responses.c b/src/mint/taler-mint-httpd_responses.c
index 77cdb4078..ec8fdc03b 100644
--- a/src/mint/taler-mint-httpd_responses.c
+++ b/src/mint/taler-mint-httpd_responses.c
@@ -305,7 +305,7 @@ TALER_MINT_reply_deposit_success (struct MHD_Connection *connection,
dc.merchant = *merchant;
TALER_MINT_keys_sign (&dc.purpose,
&sig);
- sig_json = TALER_JSON_from_sig (&dc.purpose, &sig);
+ sig_json = TALER_JSON_from_eddsa_sig (&dc.purpose, &sig);
ret = TALER_MINT_reply_json_pack (connection,
MHD_HTTP_OK,
"{s:s, s:o}",
@@ -332,28 +332,72 @@ TALER_MINT_reply_insufficient_funds (struct MHD_Connection *connection,
{
const struct TALER_MINT_DB_TransactionList *pos;
int ret;
+ json_t *history;
+ json_t *transaction;
+ const char *type;
+ struct TALER_Amount value;
- // FIXME: implement properly! (#3632)
+ history = json_array ();
for (pos = tl; NULL != pos; pos = pos->next)
{
switch (pos->type)
{
case TALER_MINT_DB_TT_DEPOSIT:
- /* FIXME: add operation details to json reply */
- break;
+ {
+ struct TALER_DepositRequest dr;
+ const struct Deposit *deposit = pos->details.deposit;
+
+ type = "deposit";
+ value = deposit->amount;
+ dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_DEPOSIT);
+ dr.purpose.size = htonl (sizeof (struct TALER_DepositRequest));
+ dr.h_contract = deposit->h_contract;
+ dr.h_wire = deposit->h_wire;
+ dr.transaction_id = GNUNET_htonll (deposit->transaction_id);
+ dr.amount = TALER_amount_hton (deposit->amount);
+ dr.coin_pub = deposit->coin.coin_pub;
+ transaction = TALER_JSON_from_ecdsa_sig (&dr.purpose,
+ &deposit->csig);
+ break;
+ }
case TALER_MINT_DB_TT_REFRESH_MELT:
- /* FIXME: add operation details to json reply */
+ {
+ struct RefreshMeltSignatureBody 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.melt_hash = melt->melt_hash;
+ ms.amount = TALER_amount_hton (melt->amount);
+ transaction = TALER_JSON_from_ecdsa_sig (&ms.purpose,
+ &melt->coin_sig);
+ }
break;
case TALER_MINT_DB_TT_LOCK:
- /* FIXME: add operation details to json reply */
- break;
+ {
+ type = "lock";
+ value = pos->details.lock->amount;
+ transaction = NULL;
+ GNUNET_break (0); /* #3625: Lock NOT implemented! */
+ break;
+ }
+ default:
+ GNUNET_assert (0);
}
+ json_array_append_new (history,
+ json_pack ("{s:s, s:o}",
+ "type", type,
+ "amount", TALER_JSON_from_amount (value),
+ "signature", transaction));
}
ret = TALER_MINT_reply_json_pack (connection,
MHD_HTTP_FORBIDDEN,
- "{s:s}",
- "error", "insufficient funds");
+ "{s:s, s:o}",
+ "error", "insufficient funds",
+ "history", history);
return ret;
}
@@ -517,7 +561,7 @@ TALER_MINT_reply_withdraw_sign_success (struct MHD_Connection *connection,
char *sig_buf;
int ret;
- /* FIXME: use TALER_JSON_from_sig here instead!? */
+ /* FIXME: use TALER_JSON_from_eddsa_sig here instead!? */
sig_buf_size = GNUNET_CRYPTO_rsa_signature_encode (collectable->sig,
&sig_buf);
sig_json = TALER_JSON_from_data (sig_buf,
@@ -561,7 +605,7 @@ TALER_MINT_reply_refresh_melt_success (struct MHD_Connection *connection,
body.kappa = htonl (kappa);
TALER_MINT_keys_sign (&body.purpose,
&sig);
- sig_json = TALER_JSON_from_sig (&body.purpose, &sig);
+ sig_json = TALER_JSON_from_eddsa_sig (&body.purpose, &sig);
ret = TALER_MINT_reply_json_pack (connection,
MHD_HTTP_OK,
"{s:o, s:i}",
@@ -595,7 +639,7 @@ TALER_MINT_reply_refresh_commit_success (struct MHD_Connection *connection,
body.noreveal_index = htons (refresh_session->noreveal_index);
TALER_MINT_keys_sign (&body.purpose,
&sig);
- sig_json = TALER_JSON_from_sig (&body.purpose, &sig);
+ sig_json = TALER_JSON_from_eddsa_sig (&body.purpose, &sig);
GNUNET_assert (NULL != sig_json);
ret = TALER_MINT_reply_json_pack (connection,
MHD_HTTP_OK,
diff --git a/src/util/json.c b/src/util/json.c
index 02591d7bf..38f459200 100644
--- a/src/util/json.c
+++ b/src/util/json.c
@@ -90,8 +90,8 @@ TALER_JSON_from_abs (struct GNUNET_TIME_Absolute stamp)
* @return the JSON reporesentation of the signature with purpose
*/
json_t *
-TALER_JSON_from_sig (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
- const struct GNUNET_CRYPTO_EddsaSignature *signature)
+TALER_JSON_from_eddsa_sig (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+ const struct GNUNET_CRYPTO_EddsaSignature *signature)
{
json_t *root;
json_t *el;
@@ -106,7 +106,37 @@ TALER_JSON_from_sig (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
el = TALER_JSON_from_data (signature,
sizeof (struct GNUNET_CRYPTO_EddsaSignature));
- json_object_set_new (root, "sig", el);
+ json_object_set_new (root, "eddsa-sig", el);
+
+ return root;
+}
+
+
+/**
+ * Convert a signature (with purpose) to a JSON object representation.
+ *
+ * @param purpose purpose of the signature
+ * @param signature the signature
+ * @return the JSON reporesentation of the signature with purpose
+ */
+json_t *
+TALER_JSON_from_ecdsa_sig (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
+ const struct GNUNET_CRYPTO_EcdsaSignature *signature)
+{
+ json_t *root;
+ json_t *el;
+
+ root = json_object ();
+
+ el = json_integer ((json_int_t) ntohl (purpose->size));
+ json_object_set_new (root, "size", el);
+
+ el = json_integer ((json_int_t) ntohl (purpose->purpose));
+ json_object_set_new (root, "purpose", el);
+
+ el = TALER_JSON_from_data (signature,
+ sizeof (struct GNUNET_CRYPTO_EddsaSignature));
+ json_object_set_new (root, "ecdsa-sig", el);
return root;
}
@@ -134,6 +164,20 @@ TALER_JSON_from_data (const void *data, size_t size)
/**
+ * Convert binary hash to a JSON string with the base32crockford
+ * encoding.
+ *
+ * @param hc binary data
+ * @return json string that encodes @a hc
+ */
+json_t *
+TALER_JSON_from_hash (const struct GNUNET_HashCode *hc)
+{
+ return TALER_JSON_from_data (hc, sizeof (struct GNUNET_HashCode));
+}
+
+
+/**
* Parse given JSON object to Amount
*
* @param json the json object representing Amount