implementing #3632: generate proof of insufficient funds by converting transaction history to JSON

This commit is contained in:
Christian Grothoff 2015-03-09 12:29:41 +01:00
parent 7b0ae9c1d0
commit 579f465c9b
8 changed files with 228 additions and 72 deletions

View File

@ -60,10 +60,22 @@ 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,
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);
/**
* Convert binary data to a JSON string
* with the base32crockford encoding.
@ -76,6 +88,17 @@ json_t *
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
*
@ -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_ */

View File

@ -266,7 +266,83 @@ struct RefreshMeltResponseSignatureBody
};
/**
* Message signed by a coin to indicate that the coin should
* be melted.
*/
struct RefreshMeltSignatureBody
{
/**
* Purpose is #TALER_SIGNATURE_REFRESH_MELT.
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/**
* 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;
};
/**
* Message signed during melting committing the client to the
* hashed inputs.
*/
struct RefreshCommitSignatureBody
{
/**
* Purpose is #TALER_SIGNATURE_REFRESH_COMMIT.
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/**
* Session state the client commits itself to.
*/
struct GNUNET_HashCode commit_hash;
};
/**
* Message signed by the mint, committing it to a particular
* index to not be revealed during the refresh.
*/
struct RefreshCommitResponseSignatureBody
{
/**
* Purpose is #TALER_SIGNATURE_REFRESH_MELT_RESPONSE.
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/**
* Index that the client will not have to reveal.
*/
uint16_t noreveal_index GNUNET_PACKED;
};
/**
* Message signed by the client requesting the final
* result of the melting operation.
*/
struct RefreshMeltConfirmSignRequestBody
{
/**
* Purpose is #TALER_SIGNATURE_REFRESH_MELT_CONFIRM.
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/**
* FIXME.
*/
struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
};
/**
@ -303,45 +379,6 @@ struct TALER_MINT_DenomKeyIssue
};
/**
* FIXME
*/
struct RefreshMeltSignatureBody
{
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct GNUNET_HashCode melt_hash;
};
/**
* FIXME
*/
struct RefreshCommitSignatureBody
{
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct GNUNET_HashCode commit_hash;
};
/**
* FIXME
*/
struct RefreshCommitResponseSignatureBody
{
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
uint16_t noreveal_index;
};
/**
* FIXME
*/
struct RefreshMeltConfirmSignRequestBody
{
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
};
GNUNET_NETWORK_STRUCT_END

View File

@ -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.
@ -544,8 +540,15 @@ 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;

View File

@ -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],

View File

@ -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,

View File

@ -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,

View File

@ -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;
case TALER_MINT_DB_TT_REFRESH_MELT:
/* FIXME: add operation details to json reply */
break;
case TALER_MINT_DB_TT_LOCK:
/* FIXME: add operation details to json reply */
{
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:
{
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:
{
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,

View File

@ -90,7 +90,7 @@ 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,
TALER_JSON_from_eddsa_sig (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
const struct GNUNET_CRYPTO_EddsaSignature *signature)
{
json_t *root;
@ -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;
}
@ -133,6 +163,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
*