separate DB logic for /refresh/reveal from parsing logic
This commit is contained in:
parent
c9a819a5ef
commit
9c56c91c1f
@ -794,8 +794,6 @@ TALER_MINT_db_execute_refresh_commit (struct MHD_Connection *connection,
|
|||||||
return MHD_NO;
|
return MHD_NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (GNUNET_OK != TALER_MINT_DB_commit (db_conn))
|
if (GNUNET_OK != TALER_MINT_DB_commit (db_conn))
|
||||||
{
|
{
|
||||||
// FIXME: return 'internal error'?
|
// FIXME: return 'internal error'?
|
||||||
@ -804,7 +802,346 @@ TALER_MINT_db_execute_refresh_commit (struct MHD_Connection *connection,
|
|||||||
}
|
}
|
||||||
|
|
||||||
return TALER_MINT_reply_refresh_commit_success (connection, &refresh_session);
|
return TALER_MINT_reply_refresh_commit_success (connection, &refresh_session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send response for "/refresh/reveal".
|
||||||
|
*
|
||||||
|
* @param connection the MHD connection
|
||||||
|
* @param db_conn the connection to the mint's db
|
||||||
|
* @param refresh_session_pub the refresh session's public key
|
||||||
|
* @return a MHD result code
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
helper_refresh_reveal_send_response (struct MHD_Connection *connection,
|
||||||
|
PGconn *db_conn,
|
||||||
|
const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
int newcoin_index;
|
||||||
|
struct RefreshSession refresh_session;
|
||||||
|
struct TALER_RSA_Signature *sigs;
|
||||||
|
|
||||||
|
res = TALER_MINT_DB_get_refresh_session (db_conn,
|
||||||
|
refresh_session_pub,
|
||||||
|
&refresh_session);
|
||||||
|
if (GNUNET_OK != res)
|
||||||
|
{
|
||||||
|
// FIXME: return 'internal error'
|
||||||
|
GNUNET_break (0);
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
GNUNET_assert (0 != refresh_session.reveal_ok);
|
||||||
|
sigs = GNUNET_malloc (refresh_session.num_newcoins *
|
||||||
|
sizeof (struct TALER_RSA_Signature));
|
||||||
|
for (newcoin_index = 0; newcoin_index < refresh_session.num_newcoins; newcoin_index++)
|
||||||
|
{
|
||||||
|
res = TALER_MINT_DB_get_refresh_collectable (db_conn,
|
||||||
|
newcoin_index,
|
||||||
|
refresh_session_pub,
|
||||||
|
&sigs[newcoin_index]);
|
||||||
|
if (GNUNET_OK != res)
|
||||||
|
{
|
||||||
|
// FIXME: return 'internal error'
|
||||||
|
GNUNET_break (0);
|
||||||
|
GNUNET_free (sigs);
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res = TALER_MINT_reply_refresh_reveal_success (connection,
|
||||||
|
refresh_session.num_newcoins,
|
||||||
|
sigs);
|
||||||
|
GNUNET_free (sigs);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a /refresh/reveal.
|
||||||
|
*
|
||||||
|
* @param connection the MHD connection to handle
|
||||||
|
* @param refresh_session_pub public key of the refresh session
|
||||||
|
* @param kappa size of x-dimension of @transfer_privs array plus one (!)
|
||||||
|
* @param num_oldcoins size of y-dimension of @transfer_privs array
|
||||||
|
* @param transfer_pubs array with the revealed transfer keys
|
||||||
|
* @return MHD result code
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection,
|
||||||
|
const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
|
||||||
|
unsigned int kappa,
|
||||||
|
unsigned int num_oldcoins,
|
||||||
|
struct GNUNET_CRYPTO_EcdsaPrivateKey *const*transfer_privs)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
PGconn *db_conn;
|
||||||
|
struct RefreshSession refresh_session;
|
||||||
|
struct MintKeyState *key_state;
|
||||||
|
unsigned int i;
|
||||||
|
unsigned int j;
|
||||||
|
unsigned int off;
|
||||||
|
|
||||||
|
if (NULL == (db_conn = TALER_MINT_DB_get_connection ()))
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
// FIXME: return 'internal error'?
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send response immediately if we already know the session,
|
||||||
|
* and the session commited already.
|
||||||
|
* Do _not_ care about fields other than session_pub in this case. */
|
||||||
|
|
||||||
|
res = TALER_MINT_DB_get_refresh_session (db_conn,
|
||||||
|
refresh_session_pub,
|
||||||
|
&refresh_session);
|
||||||
|
if (GNUNET_YES == res && 0 != refresh_session.reveal_ok)
|
||||||
|
return helper_refresh_reveal_send_response (connection,
|
||||||
|
db_conn,
|
||||||
|
refresh_session_pub);
|
||||||
|
if (GNUNET_SYSERR == res)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
// FIXME: return 'internal error'?
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the transfer private keys match their commitments.
|
||||||
|
* Then derive the shared secret for each kappa, and check that they match. */
|
||||||
|
|
||||||
|
off = 0;
|
||||||
|
for (i = 0; i < refresh_session.kappa - 1; i++)
|
||||||
|
{
|
||||||
|
struct GNUNET_HashCode last_shared_secret;
|
||||||
|
int secret_initialized = GNUNET_NO;
|
||||||
|
|
||||||
|
if (i == refresh_session.noreveal_index)
|
||||||
|
off = 1;
|
||||||
|
|
||||||
|
for (j = 0; j < refresh_session.num_oldcoins; j++)
|
||||||
|
{
|
||||||
|
struct RefreshCommitLink commit_link;
|
||||||
|
struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub;
|
||||||
|
struct GNUNET_HashCode transfer_secret;
|
||||||
|
struct GNUNET_HashCode shared_secret;
|
||||||
|
|
||||||
|
res = TALER_MINT_DB_get_refresh_commit_link (db_conn,
|
||||||
|
refresh_session_pub,
|
||||||
|
i + off, j,
|
||||||
|
&commit_link);
|
||||||
|
if (GNUNET_OK != res)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
// FIXME: return 'internal error'?
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = TALER_MINT_DB_get_refresh_melt (db_conn, refresh_session_pub, j, &coin_pub);
|
||||||
|
if (GNUNET_OK != res)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
// FIXME: return 'internal error'?
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We're converting key types here, which is not very nice
|
||||||
|
* but necessary and harmless (keys will be thrown away later). */
|
||||||
|
if (GNUNET_OK != GNUNET_CRYPTO_ecc_ecdh ((struct GNUNET_CRYPTO_EcdhePrivateKey *) &transfer_privs[i+off][j],
|
||||||
|
(struct GNUNET_CRYPTO_EcdhePublicKey *) &coin_pub,
|
||||||
|
&transfer_secret))
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
// FIXME: return 'internal error'?
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 >= TALER_refresh_decrypt (commit_link.shared_secret_enc, TALER_REFRESH_SHARED_SECRET_LENGTH,
|
||||||
|
&transfer_secret, &shared_secret))
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decryption failed\n");
|
||||||
|
// FIXME: return 'internal error'?
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GNUNET_NO == secret_initialized)
|
||||||
|
{
|
||||||
|
secret_initialized = GNUNET_YES;
|
||||||
|
last_shared_secret = shared_secret;
|
||||||
|
}
|
||||||
|
else if (0 != memcmp (&shared_secret, &last_shared_secret, sizeof (struct GNUNET_HashCode)))
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "shared secrets do not match\n");
|
||||||
|
// FIXME: return error code!
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
struct GNUNET_CRYPTO_EcdsaPublicKey transfer_pub_check;
|
||||||
|
GNUNET_CRYPTO_ecdsa_key_get_public (&transfer_privs[i+off][j], &transfer_pub_check);
|
||||||
|
if (0 != memcmp (&transfer_pub_check, &commit_link.transfer_pub, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "transfer keys do not match\n");
|
||||||
|
// FIXME: return error code!
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the commitments for all new coins were correct */
|
||||||
|
|
||||||
|
for (j = 0; j < refresh_session.num_newcoins; j++)
|
||||||
|
{
|
||||||
|
struct RefreshCommitCoin commit_coin;
|
||||||
|
struct LinkData link_data;
|
||||||
|
struct TALER_RSA_BlindedSignaturePurpose *coin_ev_check;
|
||||||
|
struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub;
|
||||||
|
struct TALER_RSA_BlindingKey *bkey;
|
||||||
|
struct TALER_RSA_PublicKeyBinaryEncoded denom_pub;
|
||||||
|
|
||||||
|
bkey = NULL;
|
||||||
|
res = TALER_MINT_DB_get_refresh_commit_coin (db_conn,
|
||||||
|
refresh_session_pub,
|
||||||
|
i+off, j,
|
||||||
|
&commit_coin);
|
||||||
|
if (GNUNET_OK != res)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
// FIXME: return error code!
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (0 >= TALER_refresh_decrypt (commit_coin.link_enc, sizeof (struct LinkData),
|
||||||
|
&last_shared_secret, &link_data))
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decryption failed\n");
|
||||||
|
// FIXME: return error code!
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
GNUNET_CRYPTO_ecdsa_key_get_public (&link_data.coin_priv, &coin_pub);
|
||||||
|
if (NULL == (bkey = TALER_RSA_blinding_key_decode (&link_data.bkey_enc)))
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid blinding key\n");
|
||||||
|
// FIXME: return error code!
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
res = TALER_MINT_DB_get_refresh_order (db_conn, j, refresh_session_pub, &denom_pub);
|
||||||
|
if (GNUNET_OK != res)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
// FIXME: return error code!
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
if (NULL == (coin_ev_check =
|
||||||
|
TALER_RSA_message_blind (&coin_pub,
|
||||||
|
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
|
||||||
|
bkey,
|
||||||
|
&denom_pub)))
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "blind failed\n");
|
||||||
|
// FIXME: return error code!
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != memcmp (&coin_ev_check,
|
||||||
|
&commit_coin.coin_ev,
|
||||||
|
sizeof (struct TALER_RSA_BlindedSignaturePurpose)))
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "blind envelope does not match for kappa=%d, old=%d\n",
|
||||||
|
(int) (i+off), (int) j);
|
||||||
|
// FIXME: return error code!
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (GNUNET_OK != TALER_MINT_DB_transaction (db_conn))
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
// FIXME: return error code!
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j < refresh_session.num_newcoins; j++)
|
||||||
|
{
|
||||||
|
struct RefreshCommitCoin commit_coin;
|
||||||
|
struct TALER_RSA_PublicKeyBinaryEncoded denom_pub;
|
||||||
|
struct TALER_MINT_DenomKeyIssuePriv *dki;
|
||||||
|
struct TALER_RSA_Signature ev_sig;
|
||||||
|
|
||||||
|
res = TALER_MINT_DB_get_refresh_commit_coin (db_conn,
|
||||||
|
refresh_session_pub,
|
||||||
|
refresh_session.noreveal_index % refresh_session.kappa,
|
||||||
|
j,
|
||||||
|
&commit_coin);
|
||||||
|
if (GNUNET_OK != res)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
// FIXME: return error code!
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
res = TALER_MINT_DB_get_refresh_order (db_conn, j, refresh_session_pub, &denom_pub);
|
||||||
|
if (GNUNET_OK != res)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
// FIXME: return error code!
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
key_state = TALER_MINT_key_state_acquire ();
|
||||||
|
dki = TALER_MINT_get_denom_key (key_state, &denom_pub);
|
||||||
|
TALER_MINT_key_state_release (key_state);
|
||||||
|
if (NULL == dki)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
// FIXME: return error code!
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
if (GNUNET_OK !=
|
||||||
|
TALER_RSA_sign (dki->denom_priv,
|
||||||
|
&commit_coin.coin_ev,
|
||||||
|
sizeof (struct TALER_RSA_BlindedSignaturePurpose),
|
||||||
|
&ev_sig))
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
// FIXME: return error code!
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = TALER_MINT_DB_insert_refresh_collectable (db_conn,
|
||||||
|
j,
|
||||||
|
refresh_session_pub,
|
||||||
|
&ev_sig);
|
||||||
|
if (GNUNET_OK != res)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
// FIXME: return error code!
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* mark that reveal was successful */
|
||||||
|
|
||||||
|
res = TALER_MINT_DB_set_reveal_ok (db_conn, refresh_session_pub);
|
||||||
|
if (GNUNET_OK != res)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
// FIXME: return error code!
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GNUNET_OK != TALER_MINT_DB_commit (db_conn))
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return helper_refresh_reveal_send_response (connection, db_conn, refresh_session_pub);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -110,6 +110,23 @@ TALER_MINT_db_execute_refresh_commit (struct MHD_Connection *connection,
|
|||||||
struct RefreshCommitLink *const* commit_link);
|
struct RefreshCommitLink *const* commit_link);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a /refresh/reveal.
|
||||||
|
*
|
||||||
|
* @param connection the MHD connection to handle
|
||||||
|
* @param refresh_session_pub public key of the refresh session
|
||||||
|
* @param kappa size of x-dimension of @transfer_privs array plus one (!)
|
||||||
|
* @param num_oldcoins size of y-dimension of @transfer_privs array
|
||||||
|
* @param transfer_pubs array with the revealed transfer keys
|
||||||
|
* @return MHD result code
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection,
|
||||||
|
const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
|
||||||
|
unsigned int kappa,
|
||||||
|
unsigned int num_oldcoins,
|
||||||
|
struct GNUNET_CRYPTO_EcdsaPrivateKey *const*transfer_privs);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute a /refresh/link.
|
* Execute a /refresh/link.
|
||||||
|
@ -483,6 +483,7 @@ TALER_MINT_handler_refresh_commit (struct RequestHandler *rh,
|
|||||||
return MHD_NO;
|
return MHD_NO;
|
||||||
}
|
}
|
||||||
res = GNUNET_MINT_parse_navigate_json (connection, root,
|
res = GNUNET_MINT_parse_navigate_json (connection, root,
|
||||||
|
JNAV_FIELD, "coin_evs",
|
||||||
JNAV_INDEX, (int) 0,
|
JNAV_INDEX, (int) 0,
|
||||||
JNAV_RET_DATA,
|
JNAV_RET_DATA,
|
||||||
JSON_ARRAY, &coin_detail);
|
JSON_ARRAY, &coin_detail);
|
||||||
@ -502,6 +503,7 @@ TALER_MINT_handler_refresh_commit (struct RequestHandler *rh,
|
|||||||
return MHD_NO;
|
return MHD_NO;
|
||||||
}
|
}
|
||||||
res = GNUNET_MINT_parse_navigate_json (connection, root,
|
res = GNUNET_MINT_parse_navigate_json (connection, root,
|
||||||
|
JNAV_FIELD, "transfer_pubs",
|
||||||
JNAV_INDEX, (int) 0,
|
JNAV_INDEX, (int) 0,
|
||||||
JNAV_RET_DATA,
|
JNAV_RET_DATA,
|
||||||
JSON_ARRAY, &coin_detail);
|
JSON_ARRAY, &coin_detail);
|
||||||
@ -652,59 +654,6 @@ TALER_MINT_handler_refresh_commit (struct RequestHandler *rh,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send response for "/refresh/reveal".
|
|
||||||
*
|
|
||||||
* @param connection the MHD connection
|
|
||||||
* @param db_conn the connection to the mint's db
|
|
||||||
* @param refresh_session_pub the refresh session's public key
|
|
||||||
* @return a MHD result code
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
helper_refresh_reveal_send_response (struct MHD_Connection *connection,
|
|
||||||
PGconn *db_conn,
|
|
||||||
struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
int newcoin_index;
|
|
||||||
struct RefreshSession refresh_session;
|
|
||||||
struct TALER_RSA_Signature *sigs;
|
|
||||||
|
|
||||||
res = TALER_MINT_DB_get_refresh_session (db_conn,
|
|
||||||
refresh_session_pub,
|
|
||||||
&refresh_session);
|
|
||||||
if (GNUNET_OK != res)
|
|
||||||
{
|
|
||||||
// FIXME: return 'internal error'
|
|
||||||
GNUNET_break (0);
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
GNUNET_assert (0 != refresh_session.reveal_ok);
|
|
||||||
sigs = GNUNET_malloc (refresh_session.num_newcoins *
|
|
||||||
sizeof (struct TALER_RSA_Signature));
|
|
||||||
for (newcoin_index = 0; newcoin_index < refresh_session.num_newcoins; newcoin_index++)
|
|
||||||
{
|
|
||||||
res = TALER_MINT_DB_get_refresh_collectable (db_conn,
|
|
||||||
newcoin_index,
|
|
||||||
refresh_session_pub,
|
|
||||||
&sigs[newcoin_index]);
|
|
||||||
if (GNUNET_OK != res)
|
|
||||||
{
|
|
||||||
// FIXME: return 'internal error'
|
|
||||||
GNUNET_break (0);
|
|
||||||
GNUNET_free (sigs);
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res = TALER_MINT_reply_refresh_reveal_success (connection,
|
|
||||||
refresh_session.num_newcoins,
|
|
||||||
sigs);
|
|
||||||
GNUNET_free (sigs);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a "/refresh/reveal" request
|
* Handle a "/refresh/reveal" request
|
||||||
*
|
*
|
||||||
@ -724,12 +673,14 @@ TALER_MINT_handler_refresh_reveal (struct RequestHandler *rh,
|
|||||||
{
|
{
|
||||||
struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub;
|
struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub;
|
||||||
int res;
|
int res;
|
||||||
PGconn *db_conn;
|
unsigned int kappa;
|
||||||
struct RefreshSession refresh_session;
|
unsigned int num_oldcoins;
|
||||||
struct MintKeyState *key_state;
|
json_t *transfer_p;
|
||||||
int i;
|
json_t *reveal_detail;
|
||||||
int j;
|
unsigned int i;
|
||||||
|
unsigned int j;
|
||||||
json_t *root;
|
json_t *root;
|
||||||
|
struct GNUNET_CRYPTO_EcdsaPrivateKey **transfer_privs;
|
||||||
|
|
||||||
res = TALER_MINT_parse_post_json (connection,
|
res = TALER_MINT_parse_post_json (connection,
|
||||||
connection_cls,
|
connection_cls,
|
||||||
@ -753,279 +704,60 @@ TALER_MINT_handler_refresh_reveal (struct RequestHandler *rh,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Determine dimensionality of the request (kappa and #old coins) */
|
||||||
if (NULL == (db_conn = TALER_MINT_DB_get_connection ()))
|
res = GNUNET_MINT_parse_navigate_json (connection, root,
|
||||||
{
|
JNAV_FIELD, "transfer_privs",
|
||||||
GNUNET_break (0);
|
JNAV_RET_TYPED_JSON, JSON_ARRAY, &transfer_p);
|
||||||
// FIXME: return 'internal error'?
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send response immediately if we already know the session,
|
|
||||||
* and the session commited already.
|
|
||||||
* Do _not_ care about fields other than session_pub in this case. */
|
|
||||||
|
|
||||||
res = TALER_MINT_DB_get_refresh_session (db_conn,
|
|
||||||
&refresh_session_pub,
|
|
||||||
&refresh_session);
|
|
||||||
if (GNUNET_YES == res && 0 != refresh_session.reveal_ok)
|
|
||||||
return helper_refresh_reveal_send_response (connection,
|
|
||||||
db_conn,
|
|
||||||
&refresh_session_pub);
|
|
||||||
if (GNUNET_SYSERR == res)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
// FIXME: return 'internal error'?
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check that the transfer private keys match their commitments.
|
|
||||||
* Then derive the shared secret for each kappa, and check that they match. */
|
|
||||||
|
|
||||||
for (i = 0; i < refresh_session.kappa; i++)
|
|
||||||
{
|
|
||||||
struct GNUNET_HashCode last_shared_secret;
|
|
||||||
int secret_initialized = GNUNET_NO;
|
|
||||||
|
|
||||||
if (i == (refresh_session.noreveal_index % refresh_session.kappa))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (j = 0; j < refresh_session.num_oldcoins; j++)
|
|
||||||
{
|
|
||||||
struct GNUNET_CRYPTO_EcdsaPrivateKey transfer_priv;
|
|
||||||
struct RefreshCommitLink commit_link;
|
|
||||||
struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub;
|
|
||||||
struct GNUNET_HashCode transfer_secret;
|
|
||||||
struct GNUNET_HashCode shared_secret;
|
|
||||||
|
|
||||||
res = GNUNET_MINT_parse_navigate_json (connection, root,
|
|
||||||
JNAV_FIELD, "transfer_privs",
|
|
||||||
JNAV_INDEX, (int) i,
|
|
||||||
JNAV_INDEX, (int) j,
|
|
||||||
JNAV_RET_DATA,
|
|
||||||
&transfer_priv,
|
|
||||||
sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
|
|
||||||
|
|
||||||
if (GNUNET_OK != res)
|
|
||||||
{
|
|
||||||
GNUNET_break (GNUNET_SYSERR != res);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = TALER_MINT_DB_get_refresh_commit_link (db_conn,
|
|
||||||
&refresh_session_pub,
|
|
||||||
i, j,
|
|
||||||
&commit_link);
|
|
||||||
if (GNUNET_OK != res)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
// FIXME: return 'internal error'?
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = TALER_MINT_DB_get_refresh_melt (db_conn, &refresh_session_pub, j, &coin_pub);
|
|
||||||
if (GNUNET_OK != res)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
// FIXME: return 'internal error'?
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We're converting key types here, which is not very nice
|
|
||||||
* but necessary and harmless (keys will be thrown away later). */
|
|
||||||
if (GNUNET_OK != GNUNET_CRYPTO_ecc_ecdh ((struct GNUNET_CRYPTO_EcdhePrivateKey *) &transfer_priv,
|
|
||||||
(struct GNUNET_CRYPTO_EcdhePublicKey *) &coin_pub,
|
|
||||||
&transfer_secret))
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
// FIXME: return 'internal error'?
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 >= TALER_refresh_decrypt (commit_link.shared_secret_enc, TALER_REFRESH_SHARED_SECRET_LENGTH,
|
|
||||||
&transfer_secret, &shared_secret))
|
|
||||||
{
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decryption failed\n");
|
|
||||||
// FIXME: return 'internal error'?
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GNUNET_NO == secret_initialized)
|
|
||||||
{
|
|
||||||
secret_initialized = GNUNET_YES;
|
|
||||||
last_shared_secret = shared_secret;
|
|
||||||
}
|
|
||||||
else if (0 != memcmp (&shared_secret, &last_shared_secret, sizeof (struct GNUNET_HashCode)))
|
|
||||||
{
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "shared secrets do not match\n");
|
|
||||||
// FIXME: return error code!
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
struct GNUNET_CRYPTO_EcdsaPublicKey transfer_pub_check;
|
|
||||||
GNUNET_CRYPTO_ecdsa_key_get_public (&transfer_priv, &transfer_pub_check);
|
|
||||||
if (0 != memcmp (&transfer_pub_check, &commit_link.transfer_pub, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
|
|
||||||
{
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "transfer keys do not match\n");
|
|
||||||
// FIXME: return error code!
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check that the commitments for all new coins were correct */
|
|
||||||
|
|
||||||
for (j = 0; j < refresh_session.num_newcoins; j++)
|
|
||||||
{
|
|
||||||
struct RefreshCommitCoin commit_coin;
|
|
||||||
struct LinkData link_data;
|
|
||||||
struct TALER_RSA_BlindedSignaturePurpose *coin_ev_check;
|
|
||||||
struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub;
|
|
||||||
struct TALER_RSA_BlindingKey *bkey;
|
|
||||||
struct TALER_RSA_PublicKeyBinaryEncoded denom_pub;
|
|
||||||
|
|
||||||
bkey = NULL;
|
|
||||||
res = TALER_MINT_DB_get_refresh_commit_coin (db_conn,
|
|
||||||
&refresh_session_pub,
|
|
||||||
i, j,
|
|
||||||
&commit_coin);
|
|
||||||
if (GNUNET_OK != res)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
// FIXME: return error code!
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (0 >= TALER_refresh_decrypt (commit_coin.link_enc, sizeof (struct LinkData),
|
|
||||||
&last_shared_secret, &link_data))
|
|
||||||
{
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decryption failed\n");
|
|
||||||
// FIXME: return error code!
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
GNUNET_CRYPTO_ecdsa_key_get_public (&link_data.coin_priv, &coin_pub);
|
|
||||||
if (NULL == (bkey = TALER_RSA_blinding_key_decode (&link_data.bkey_enc)))
|
|
||||||
{
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid blinding key\n");
|
|
||||||
// FIXME: return error code!
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
res = TALER_MINT_DB_get_refresh_order (db_conn, j, &refresh_session_pub, &denom_pub);
|
|
||||||
if (GNUNET_OK != res)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
// FIXME: return error code!
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
if (NULL == (coin_ev_check =
|
|
||||||
TALER_RSA_message_blind (&coin_pub,
|
|
||||||
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
|
|
||||||
bkey,
|
|
||||||
&denom_pub)))
|
|
||||||
{
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "blind failed\n");
|
|
||||||
// FIXME: return error code!
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 != memcmp (&coin_ev_check,
|
|
||||||
&commit_coin.coin_ev,
|
|
||||||
sizeof (struct TALER_RSA_BlindedSignaturePurpose)))
|
|
||||||
{
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "blind envelope does not match for kappa=%d, old=%d\n",
|
|
||||||
(int) i, (int) j);
|
|
||||||
// FIXME: return error code!
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (GNUNET_OK != TALER_MINT_DB_transaction (db_conn))
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
// FIXME: return error code!
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (j = 0; j < refresh_session.num_newcoins; j++)
|
|
||||||
{
|
|
||||||
struct RefreshCommitCoin commit_coin;
|
|
||||||
struct TALER_RSA_PublicKeyBinaryEncoded denom_pub;
|
|
||||||
struct TALER_MINT_DenomKeyIssuePriv *dki;
|
|
||||||
struct TALER_RSA_Signature ev_sig;
|
|
||||||
|
|
||||||
res = TALER_MINT_DB_get_refresh_commit_coin (db_conn,
|
|
||||||
&refresh_session_pub,
|
|
||||||
refresh_session.noreveal_index % refresh_session.kappa,
|
|
||||||
j,
|
|
||||||
&commit_coin);
|
|
||||||
if (GNUNET_OK != res)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
// FIXME: return error code!
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
res = TALER_MINT_DB_get_refresh_order (db_conn, j, &refresh_session_pub, &denom_pub);
|
|
||||||
if (GNUNET_OK != res)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
// FIXME: return error code!
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
key_state = TALER_MINT_key_state_acquire ();
|
|
||||||
dki = TALER_MINT_get_denom_key (key_state, &denom_pub);
|
|
||||||
TALER_MINT_key_state_release (key_state);
|
|
||||||
if (NULL == dki)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
// FIXME: return error code!
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
if (GNUNET_OK !=
|
|
||||||
TALER_RSA_sign (dki->denom_priv,
|
|
||||||
&commit_coin.coin_ev,
|
|
||||||
sizeof (struct TALER_RSA_BlindedSignaturePurpose),
|
|
||||||
&ev_sig))
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
// FIXME: return error code!
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = TALER_MINT_DB_insert_refresh_collectable (db_conn,
|
|
||||||
j,
|
|
||||||
&refresh_session_pub,
|
|
||||||
&ev_sig);
|
|
||||||
if (GNUNET_OK != res)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
// FIXME: return error code!
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* mark that reveal was successful */
|
|
||||||
|
|
||||||
res = TALER_MINT_DB_set_reveal_ok (db_conn, &refresh_session_pub);
|
|
||||||
if (GNUNET_OK != res)
|
if (GNUNET_OK != res)
|
||||||
|
return res;
|
||||||
|
kappa = json_array_size (transfer_p) + 1; /* 1 row is missing */
|
||||||
|
if (3 > kappa)
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break_op (0);
|
||||||
// FIXME: return error code!
|
// FIXME: generate error message
|
||||||
return MHD_NO;
|
return MHD_NO;
|
||||||
}
|
}
|
||||||
|
res = GNUNET_MINT_parse_navigate_json (connection, root,
|
||||||
|
JNAV_FIELD, "transfer_privs",
|
||||||
|
JNAV_INDEX, 0,
|
||||||
|
JNAV_RET_TYPED_JSON, JSON_ARRAY, &reveal_detail);
|
||||||
|
if (GNUNET_OK != res)
|
||||||
|
return res;
|
||||||
|
num_oldcoins = json_array_size (reveal_detail);
|
||||||
|
|
||||||
if (GNUNET_OK != TALER_MINT_DB_commit (db_conn))
|
|
||||||
|
transfer_privs = GNUNET_malloc ((kappa - 1) *
|
||||||
|
sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey *));
|
||||||
|
for (i = 0; i < kappa - 1; i++)
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
transfer_privs[i] = GNUNET_malloc (num_oldcoins *
|
||||||
return MHD_NO;
|
sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
|
||||||
|
for (j = 0; j < num_oldcoins; j++)
|
||||||
|
{
|
||||||
|
res = GNUNET_MINT_parse_navigate_json (connection, root,
|
||||||
|
JNAV_FIELD, "transfer_privs",
|
||||||
|
JNAV_INDEX, (int) i,
|
||||||
|
JNAV_INDEX, (int) j,
|
||||||
|
JNAV_RET_DATA,
|
||||||
|
&transfer_privs[i][j],
|
||||||
|
sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
|
||||||
|
if (GNUNET_OK != res)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
// FIXME: return 'internal error'?
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return helper_refresh_reveal_send_response (connection, db_conn, &refresh_session_pub);
|
|
||||||
|
res = TALER_MINT_db_execute_refresh_reveal (connection,
|
||||||
|
&refresh_session_pub,
|
||||||
|
kappa,
|
||||||
|
num_oldcoins,
|
||||||
|
transfer_privs);
|
||||||
|
// FIXME: free memory
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user