fix major bug with SQL statement missing ORDER BY freshcoin_index resulting in possible link failures (but usually lucky with old DB schema)

This commit is contained in:
Christian Grothoff 2021-01-10 00:54:12 +01:00
parent 02ecf68a3d
commit ca66a1d1af
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
10 changed files with 174 additions and 74 deletions

View File

@ -83,8 +83,8 @@ handle_link_data (void *cls,
obj = json_pack ("{s:o, s:o, s:o}", obj = json_pack ("{s:o, s:o, s:o}",
"denom_pub", "denom_pub",
GNUNET_JSON_from_rsa_public_key GNUNET_JSON_from_rsa_public_key (
(pos->denom_pub.rsa_public_key), pos->denom_pub.rsa_public_key),
"ev_sig", "ev_sig",
GNUNET_JSON_from_rsa_signature GNUNET_JSON_from_rsa_signature
(pos->ev_sig.rsa_signature), (pos->ev_sig.rsa_signature),

View File

@ -349,7 +349,7 @@ refreshes_reveal_transaction (void *cls,
else else
{ {
/* Reconstruct coin envelopes from transfer private key */ /* Reconstruct coin envelopes from transfer private key */
struct TALER_TransferPrivateKeyP *tpriv const struct TALER_TransferPrivateKeyP *tpriv
= &rctx->transfer_privs[i - off]; = &rctx->transfer_privs[i - off];
struct TALER_TransferSecretP ts; struct TALER_TransferSecretP ts;
@ -695,32 +695,22 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,
if (GNUNET_OK != res) if (GNUNET_OK != res)
return (GNUNET_NO == res) ? MHD_YES : MHD_NO; return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
/* Check link_sigs[i] signature */ /* Check link_sigs[i] signature */
if (GNUNET_OK !=
TALER_wallet_link_verify (
&dk_h[i],
&rctx->gamma_tp,
rcds[i].coin_ev,
rcds[i].coin_ev_size,
&melt.session.coin.coin_pub,
&link_sigs[i]))
{ {
struct TALER_LinkDataPS ldp = { GNUNET_break_op (0);
.purpose.size = htonl (sizeof (ldp)), ret = TALER_MHD_reply_with_error (
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_LINK), connection,
.h_denom_pub = dk_h[i], MHD_HTTP_FORBIDDEN,
.old_coin_pub = melt.session.coin.coin_pub, TALER_EC_EXCHANGE_REFRESHES_REVEAL_LINK_SIGNATURE_INVALID,
.transfer_pub = rctx->gamma_tp NULL);
}; goto cleanup;
GNUNET_CRYPTO_hash (rcds[i].coin_ev,
rcds[i].coin_ev_size,
&ldp.coin_envelope_hash);
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (
TALER_SIGNATURE_WALLET_COIN_LINK,
&ldp,
&link_sigs[i].eddsa_signature,
&melt.session.coin.coin_pub.eddsa_pub))
{
GNUNET_break_op (0);
ret = TALER_MHD_reply_with_error (connection,
MHD_HTTP_FORBIDDEN,
TALER_EC_EXCHANGE_REFRESHES_REVEAL_LINK_SIGNATURE_INVALID,
NULL);
goto cleanup;
}
} }
} }

View File

@ -280,7 +280,6 @@ COMMENT ON COLUMN refunds.deposit_serial_id
IS 'Identifies ONLY the merchant_pub, h_contract_terms and known_coin_id. Multiple deposits may match a refund, this only identifies one of them.'; IS 'Identifies ONLY the merchant_pub, h_contract_terms and known_coin_id. Multiple deposits may match a refund, this only identifies one of them.';
-- Create additional tables... -- Create additional tables...
CREATE TABLE IF NOT EXISTS auditors CREATE TABLE IF NOT EXISTS auditors

View File

@ -794,7 +794,7 @@ postgres_get_session (void *cls)
",h_coin_ev" ",h_coin_ev"
",ev_sig" ",ev_sig"
") SELECT rcx.melt_serial_id, $2, $3, " ") SELECT rcx.melt_serial_id, $2, $3, "
" denominations_serial, $5, $6, $7 " " denominations_serial, $5, $6, $7"
" FROM denominations" " FROM denominations"
" CROSS JOIN rcx" " CROSS JOIN rcx"
" WHERE denom_pub_hash=$4;", " WHERE denom_pub_hash=$4;",
@ -1108,7 +1108,7 @@ postgres_get_session (void *cls)
" (SELECT known_coin_id " " (SELECT known_coin_id "
" FROM known_coins" " FROM known_coins"
" WHERE coin_pub=$1)" " WHERE coin_pub=$1)"
" ORDER BY tp.transfer_pub", " ORDER BY tp.transfer_pub, rrc.freshcoin_index ASC",
1), 1),
/* Used in #postgres_lookup_wire_transfer */ /* Used in #postgres_lookup_wire_transfer */
GNUNET_PQ_make_prepare ("lookup_transactions", GNUNET_PQ_make_prepare ("lookup_transactions",
@ -2323,6 +2323,11 @@ postgres_preflight (void *cls,
}; };
(void) cls; (void) cls;
if (NULL == session)
{
GNUNET_break (0);
return;
}
if (NULL == session->transaction_name) if (NULL == session->transaction_name)
return; /* all good */ return; /* all good */
if (GNUNET_OK == if (GNUNET_OK ==

View File

@ -1050,6 +1050,47 @@ TALER_CRYPTO_helper_esign_disconnect (
struct TALER_CRYPTO_ExchangeSignHelper *esh); struct TALER_CRYPTO_ExchangeSignHelper *esh);
/* ********************* wallet signing ************************** */
/**
* Sign link data.
*
* @param h_denom_pub hash of the denomiantion public key of the new coin
* @param transfer_pub transfer public key
* @param coin_ev coin envelope
* @param coin_ev_size number of bytes in @a coin_ev
* @param old_coin_priv private key to sign with
* @param[out] coin_sig resulting signature
*/
void
TALER_wallet_link_sign (const struct GNUNET_HashCode *h_denom_pub,
const struct TALER_TransferPublicKeyP *transfer_pub,
const void *coin_ev,
size_t coin_ev_size,
const struct TALER_CoinSpendPrivateKeyP *old_coin_priv,
struct TALER_CoinSpendSignatureP *coin_sig);
/**
* Verify link signature.
*
* @param h_denom_pub hash of the denomiantion public key of the new coin
* @param transfer_pub transfer public key
* @param coin_ev coin envelope
* @param coin_ev_size number of bytes in @a coin_ev
* @param old_coin_priv private key to sign with
* @param coin_sig resulting signature
* @return #GNUNET_OK if the signature is valid
*/
enum GNUNET_GenericReturnValue
TALER_wallet_link_verify (
const struct GNUNET_HashCode *h_denom_pub,
const struct TALER_TransferPublicKeyP *transfer_pub,
const void *coin_ev,
size_t coin_ev_size,
const struct TALER_CoinSpendPublicKeyP *old_coin_pub,
const struct TALER_CoinSpendSignatureP *coin_sig);
/* ********************* offline signing ************************** */ /* ********************* offline signing ************************** */

View File

@ -1274,6 +1274,7 @@ struct TALER_EXCHANGEDB_LinkList
* link data, of type #TALER_SIGNATURE_WALLET_COIN_LINK * link data, of type #TALER_SIGNATURE_WALLET_COIN_LINK
*/ */
struct TALER_CoinSpendSignatureP orig_coin_link_sig; struct TALER_CoinSpendSignatureP orig_coin_link_sig;
}; };

View File

@ -75,7 +75,7 @@ struct TALER_EXCHANGE_LinkHandle
* *
* @param lh link handle * @param lh link handle
* @param json json reply with the data for one coin * @param json json reply with the data for one coin
* @param coin_num number of the coin to decode * @param coin_num number of the coin
* @param trans_pub our transfer public key * @param trans_pub our transfer public key
* @param[out] coin_priv where to return private coin key * @param[out] coin_priv where to return private coin key
* @param[out] sig where to return private coin signature * @param[out] sig where to return private coin signature
@ -85,7 +85,7 @@ struct TALER_EXCHANGE_LinkHandle
static int static int
parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh, parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,
const json_t *json, const json_t *json,
unsigned int coin_num, uint32_t coin_num,
const struct TALER_TransferPublicKeyP *trans_pub, const struct TALER_TransferPublicKeyP *trans_pub,
struct TALER_CoinSpendPrivateKeyP *coin_priv, struct TALER_CoinSpendPrivateKeyP *coin_priv,
struct TALER_DenominationSignature *sig, struct TALER_DenominationSignature *sig,
@ -112,7 +112,6 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,
GNUNET_break_op (0); GNUNET_break_op (0);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
TALER_link_recover_transfer_secret (trans_pub, TALER_link_recover_transfer_secret (trans_pub,
&lh->coin_priv, &lh->coin_priv,
&secret); &secret);
@ -130,14 +129,10 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,
{ {
struct TALER_PlanchetDetail pd; struct TALER_PlanchetDetail pd;
struct GNUNET_HashCode c_hash; struct GNUNET_HashCode c_hash;
struct TALER_LinkDataPS ldp = { struct TALER_CoinSpendPublicKeyP old_coin_pub;
.purpose.size = htonl (sizeof (ldp)),
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_LINK),
.transfer_pub = *trans_pub
};
GNUNET_CRYPTO_eddsa_key_get_public (&lh->coin_priv.eddsa_priv, GNUNET_CRYPTO_eddsa_key_get_public (&lh->coin_priv.eddsa_priv,
&ldp.old_coin_pub.eddsa_pub); &old_coin_pub.eddsa_pub);
pub->rsa_public_key = rpub; pub->rsa_public_key = rpub;
if (GNUNET_OK != if (GNUNET_OK !=
TALER_planchet_prepare (pub, TALER_planchet_prepare (pub,
@ -149,22 +144,20 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
ldp.h_denom_pub = pd.denom_pub_hash;
GNUNET_CRYPTO_hash (pd.coin_ev,
pd.coin_ev_size,
&ldp.coin_envelope_hash);
GNUNET_free (pd.coin_ev);
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_LINK, TALER_wallet_link_verify (&pd.denom_pub_hash,
&ldp, trans_pub,
&link_sig.eddsa_signature, pd.coin_ev,
&ldp.old_coin_pub.eddsa_pub)) pd.coin_ev_size,
&old_coin_pub,
&link_sig))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_free (pd.coin_ev);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
GNUNET_free (pd.coin_ev);
} }
/* clean up */ /* clean up */
@ -457,11 +450,11 @@ TALER_EXCHANGE_link (struct TALER_EXCHANGE_Handle *exchange,
char pub_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2]; char pub_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2];
char *end; char *end;
end = GNUNET_STRINGS_data_to_string (&coin_pub, end = GNUNET_STRINGS_data_to_string (
sizeof (struct &coin_pub,
TALER_CoinSpendPublicKeyP), sizeof (struct TALER_CoinSpendPublicKeyP),
pub_str, pub_str,
sizeof (pub_str)); sizeof (pub_str));
*end = '\0'; *end = '\0';
GNUNET_snprintf (arg_str, GNUNET_snprintf (arg_str,
sizeof (arg_str), sizeof (arg_str),

View File

@ -391,30 +391,20 @@ TALER_EXCHANGE_refreshes_reveal (
json_array_append_new (coin_evs, json_array_append_new (coin_evs,
GNUNET_JSON_from_data (pd.coin_ev, GNUNET_JSON_from_data (pd.coin_ev,
pd.coin_ev_size))); pd.coin_ev_size)));
/* compute link signature */
{ {
struct TALER_CoinSpendSignatureP link_sig; struct TALER_CoinSpendSignatureP link_sig;
struct TALER_LinkDataPS ldp;
ldp.purpose.size = htonl (sizeof (ldp)); TALER_wallet_link_sign (&denom_hash,
ldp.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_LINK); &transfer_pub,
ldp.h_denom_pub = denom_hash; pd.coin_ev,
GNUNET_CRYPTO_eddsa_key_get_public (&md->melted_coin.coin_priv.eddsa_priv, pd.coin_ev_size,
&ldp.old_coin_pub.eddsa_pub); &md->melted_coin.coin_priv,
ldp.transfer_pub = transfer_pub; &link_sig);
GNUNET_CRYPTO_hash (pd.coin_ev,
pd.coin_ev_size,
&ldp.coin_envelope_hash);
GNUNET_CRYPTO_eddsa_sign (&md->melted_coin.coin_priv.eddsa_priv,
&ldp,
&link_sig.eddsa_signature);
GNUNET_assert (0 == GNUNET_assert (0 ==
json_array_append_new (link_sigs, json_array_append_new (
GNUNET_JSON_from_data_auto ( link_sigs,
&link_sig))); GNUNET_JSON_from_data_auto (&link_sig)));
} }
GNUNET_free (pd.coin_ev); GNUNET_free (pd.coin_ev);
} }

View File

@ -76,6 +76,7 @@ libtalerutil_la_SOURCES = \
taler_error_codes.c \ taler_error_codes.c \
url.c \ url.c \
util.c \ util.c \
wallet_signatures.c \
yna.c \ yna.c \
os_installation.c os_installation.c

View File

@ -0,0 +1,80 @@
/*
This file is part of TALER
Copyright (C) 2020 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file secmod_signatures.c
* @brief Utility functions for Taler security module signatures
* @author Christian Grothoff
*/
#include "platform.h"
#include "taler_util.h"
#include "taler_signatures.h"
void
TALER_wallet_link_sign (const struct GNUNET_HashCode *h_denom_pub,
const struct TALER_TransferPublicKeyP *transfer_pub,
const void *coin_ev,
size_t coin_ev_size,
const struct TALER_CoinSpendPrivateKeyP *old_coin_priv,
struct TALER_CoinSpendSignatureP *coin_sig)
{
struct TALER_LinkDataPS ldp = {
.purpose.size = htonl (sizeof (ldp)),
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_LINK),
.h_denom_pub = *h_denom_pub,
.transfer_pub = *transfer_pub
};
GNUNET_CRYPTO_hash (coin_ev,
coin_ev_size,
&ldp.coin_envelope_hash);
GNUNET_CRYPTO_eddsa_key_get_public (&old_coin_priv->eddsa_priv,
&ldp.old_coin_pub.eddsa_pub);
GNUNET_CRYPTO_eddsa_sign (&old_coin_priv->eddsa_priv,
&ldp,
&coin_sig->eddsa_signature);
}
enum GNUNET_GenericReturnValue
TALER_wallet_link_verify (
const struct GNUNET_HashCode *h_denom_pub,
const struct TALER_TransferPublicKeyP *transfer_pub,
const void *coin_ev,
size_t coin_ev_size,
const struct TALER_CoinSpendPublicKeyP *old_coin_pub,
const struct TALER_CoinSpendSignatureP *coin_sig)
{
struct TALER_LinkDataPS ldp = {
.purpose.size = htonl (sizeof (ldp)),
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_LINK),
.h_denom_pub = *h_denom_pub,
.old_coin_pub = *old_coin_pub,
.transfer_pub = *transfer_pub
};
GNUNET_CRYPTO_hash (coin_ev,
coin_ev_size,
&ldp.coin_envelope_hash);
return
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_LINK,
&ldp,
&coin_sig->eddsa_signature,
&old_coin_pub->eddsa_pub);
}
/* end of wallet_signatures.c */