Merge branch 'master' of taler.net:/var/git/mint
This commit is contained in:
commit
d6c1340bcd
@ -468,6 +468,23 @@ TALER_link_decrypt_secret2 (const struct TALER_EncryptedLinkSecretP *secret_enc,
|
||||
struct TALER_LinkSecretP *secret);
|
||||
|
||||
|
||||
/**
|
||||
* Given the coin and the transfer private keys, compute the
|
||||
* transfer secret. (Technically, we only need one of the two
|
||||
* private keys, but the caller currently trivially only has
|
||||
* the two private keys, so we derive one of the public keys
|
||||
* internally to this function.)
|
||||
*
|
||||
* @param coin_priv coin key
|
||||
* @param trans_priv transfer private key
|
||||
* @param[out] ts computed transfer secret
|
||||
*/
|
||||
void
|
||||
TALER_link_derive_transfer_secret (const struct TALER_CoinSpendPrivateKeyP *coin_priv,
|
||||
const struct TALER_TransferPrivateKeyP *trans_priv,
|
||||
struct TALER_TransferSecretP *ts);
|
||||
|
||||
|
||||
/**
|
||||
* Encrypt the shared @a secret to generate the encrypted link secret.
|
||||
* Also creates the transfer key.
|
||||
|
@ -181,14 +181,14 @@ struct TALER_MINT_DenomPublicKey
|
||||
struct TALER_Amount fee_deposit;
|
||||
|
||||
/**
|
||||
*The applicable fee to refresh a coin of this denomination
|
||||
*The applicable fee to melt/refresh a coin of this denomination
|
||||
*/
|
||||
struct TALER_Amount fee_refresh;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Information we get from the mint about auditors.
|
||||
* @brief Information we get from the mint about auditors.
|
||||
*/
|
||||
struct TALER_MINT_AuditorInformation
|
||||
{
|
||||
@ -222,9 +222,8 @@ struct TALER_MINT_AuditorInformation
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Information about keys from the mint.
|
||||
* @brief Information about keys from the mint.
|
||||
*/
|
||||
struct TALER_MINT_Keys
|
||||
{
|
||||
@ -396,11 +395,11 @@ typedef void
|
||||
*
|
||||
* @param mint the mint handle; the mint must be ready to operate
|
||||
* @param amount the amount to be deposited
|
||||
* @param wire the merchant’s account details, in a format supported by the mint
|
||||
* @param wire_details the merchant’s account details, in a format supported by the mint
|
||||
* @param h_contract hash of the contact of the merchant with the customer (further details are never disclosed to the mint)
|
||||
* @param coin_pub coin’s public key
|
||||
* @param denom_pub denomination key with which the coin is signed
|
||||
* @param ub_sig mint’s unblinded signature of the coin
|
||||
* @param denom_sig mint’s unblinded signature of the coin
|
||||
* @param timestamp timestamp when the contract was finalized, must match approximately the current time of the mint
|
||||
* @param transaction_id transaction id for the transaction between merchant and customer
|
||||
* @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests)
|
||||
@ -466,7 +465,7 @@ enum TALER_MINT_ReserveTransactionType {
|
||||
|
||||
|
||||
/**
|
||||
* Entry in the reserve's transaction history.
|
||||
* @brief Entry in the reserve's transaction history.
|
||||
*/
|
||||
struct TALER_MINT_ReserveHistory
|
||||
{
|
||||
@ -635,7 +634,7 @@ TALER_MINT_withdraw_sign_cancel (struct TALER_MINT_WithdrawSignHandle *sign);
|
||||
* no money is lost in case of hardware failures, is operation does
|
||||
* not actually initiate the request. Instead, it generates a buffer
|
||||
* which the caller must store before proceeding with the actual call
|
||||
* to #TALER_MINT_refresh_execute() that will generate the request.
|
||||
* to #TALER_MINT_refresh_melt() that will generate the request.
|
||||
*
|
||||
* This function does verify that the given request data is internally
|
||||
* consistent. However, the @a melts_sigs are only verified if @a
|
||||
@ -660,11 +659,11 @@ TALER_MINT_withdraw_sign_cancel (struct TALER_MINT_WithdrawSignHandle *sign);
|
||||
* @param check_sigs verify the validity of the signatures of @a melt_sigs
|
||||
* @param fresh_pks_len length of the @a pks array
|
||||
* @param fresh_pks array of @a pks_len denominations of fresh coins to create
|
||||
* @param[OUT] res_size set to the size of the return value, or 0 on error
|
||||
* @param[out] res_size set to the size of the return value, or 0 on error
|
||||
* @return NULL
|
||||
* if the inputs are invalid (i.e. denomination key not with this mint).
|
||||
* Otherwise, pointer to a buffer of @a res_size to store persistently
|
||||
* before proceeding to #TALER_MINT_refresh_execute().
|
||||
* before proceeding to #TALER_MINT_refresh_melt().
|
||||
* Non-null results should be freed using #GNUNET_free().
|
||||
*/
|
||||
char *
|
||||
@ -727,11 +726,11 @@ typedef void
|
||||
* In this case, neither callback will be called.
|
||||
*/
|
||||
struct TALER_MINT_RefreshMeltHandle *
|
||||
TALER_MINT_refresh_melt_execute (struct TALER_MINT_Handle *mint,
|
||||
size_t refresh_data_length,
|
||||
const char *refresh_data,
|
||||
TALER_MINT_RefreshMeltCallback melt_cb,
|
||||
void *melt_cb_cls);
|
||||
TALER_MINT_refresh_melt (struct TALER_MINT_Handle *mint,
|
||||
size_t refresh_data_length,
|
||||
const char *refresh_data,
|
||||
TALER_MINT_RefreshMeltCallback melt_cb,
|
||||
void *melt_cb_cls);
|
||||
|
||||
|
||||
/**
|
||||
@ -841,6 +840,7 @@ struct TALER_MINT_RefreshLinkHandle;
|
||||
* @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed
|
||||
* @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error
|
||||
* @param sigs array of signature over @a num_coins coins, NULL on error
|
||||
* @param pubs array of public keys for the @a sigs, NULL on error
|
||||
* @param full_response full response from the mint (for logging, in case of errors)
|
||||
*/
|
||||
typedef void
|
||||
@ -849,6 +849,7 @@ typedef void
|
||||
unsigned int num_coins,
|
||||
const struct TALER_CoinSpendPrivateKeyP *coin_privs,
|
||||
const struct TALER_DenominationSignature *sigs,
|
||||
const struct TALER_DenominationPublicKey *pubs,
|
||||
json_t *full_response);
|
||||
|
||||
|
||||
|
@ -388,33 +388,6 @@ struct TALER_MINTDB_RefreshCommitCoin
|
||||
};
|
||||
|
||||
|
||||
GNUNET_NETWORK_STRUCT_BEGIN
|
||||
|
||||
/**
|
||||
* @brief For each (old) coin being melted, we have a `struct
|
||||
* RefreshCommitLinkP` that allows the user to find the shared secret
|
||||
* to decrypt the respective refresh links for the new coins in the
|
||||
* `struct TALER_MINTDB_RefreshCommitCoin`.
|
||||
*/
|
||||
struct TALER_MINTDB_RefreshCommitLinkP
|
||||
{
|
||||
/**
|
||||
* Transfer public key, used to decrypt the @e shared_secret_enc
|
||||
* in combintation with the corresponding private key of the
|
||||
* coin.
|
||||
*/
|
||||
struct TALER_TransferPublicKeyP transfer_pub;
|
||||
|
||||
/**
|
||||
* Encrypted shared secret to decrypt the link.
|
||||
*/
|
||||
struct TALER_EncryptedLinkSecretP shared_secret_enc;
|
||||
};
|
||||
|
||||
GNUNET_NETWORK_STRUCT_END
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Linked list of refresh information linked to a coin.
|
||||
*/
|
||||
@ -566,7 +539,7 @@ struct TALER_MINTDB_MeltCommitment
|
||||
/**
|
||||
* 2D-Array of #TALER_CNC_KAPPA and @e new_oldcoins links.
|
||||
*/
|
||||
struct TALER_MINTDB_RefreshCommitLinkP *commit_links[TALER_CNC_KAPPA];
|
||||
struct TALER_RefreshCommitLinkP *commit_links[TALER_CNC_KAPPA];
|
||||
};
|
||||
|
||||
|
||||
@ -830,11 +803,8 @@ struct TALER_MINTDB_Plugin
|
||||
* @param sesssion database connection
|
||||
* @param deposit deposit to search for
|
||||
* @return #GNUNET_YES if we know this operation,
|
||||
* #GNUNET_NO if this deposit is unknown to us,
|
||||
* #GNUNET_SYSERR on DB error or if same coin(pub), merchant(pub) and
|
||||
* transaction ID are already in DB, but for different
|
||||
* other transaction details (contract, wiring details,
|
||||
* amount, etc.)
|
||||
* #GNUNET_NO if this exact deposit is unknown to us,
|
||||
* #GNUNET_SYSERR on DB error
|
||||
*/
|
||||
int
|
||||
(*have_deposit) (void *cls,
|
||||
@ -1032,7 +1002,7 @@ struct TALER_MINTDB_Plugin
|
||||
const struct GNUNET_HashCode *session_hash,
|
||||
uint16_t cnc_index,
|
||||
uint16_t num_links,
|
||||
const struct TALER_MINTDB_RefreshCommitLinkP *commit_links);
|
||||
const struct TALER_RefreshCommitLinkP *commit_links);
|
||||
|
||||
/**
|
||||
* Obtain the commited (encrypted) refresh link data
|
||||
@ -1054,7 +1024,7 @@ struct TALER_MINTDB_Plugin
|
||||
const struct GNUNET_HashCode *session_hash,
|
||||
uint16_t cnc_index,
|
||||
uint16_t num_links,
|
||||
struct TALER_MINTDB_RefreshCommitLinkP *links);
|
||||
struct TALER_RefreshCommitLinkP *links);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -648,6 +648,31 @@ struct TALER_MintKeyValidityPS
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief For each (old) coin being melted, we have a `struct
|
||||
* RefreshCommitLinkP` that allows the user to find the shared secret
|
||||
* to decrypt the respective refresh links for the new coins in the
|
||||
* `struct TALER_MINTDB_RefreshCommitCoin`.
|
||||
*
|
||||
* Part of the construction of the refresh session's hash and
|
||||
* thus of what is signed there.
|
||||
*/
|
||||
struct TALER_RefreshCommitLinkP
|
||||
{
|
||||
/**
|
||||
* Transfer public key, used to decrypt the @e shared_secret_enc
|
||||
* in combintation with the corresponding private key of the
|
||||
* coin.
|
||||
*/
|
||||
struct TALER_TransferPublicKeyP transfer_pub;
|
||||
|
||||
/**
|
||||
* Encrypted shared secret to decrypt the link.
|
||||
*/
|
||||
struct TALER_EncryptedLinkSecretP shared_secret_enc;
|
||||
};
|
||||
|
||||
|
||||
GNUNET_NETWORK_STRUCT_END
|
||||
|
||||
#endif
|
||||
|
@ -14,6 +14,7 @@ libtalermint_la_LDFLAGS = \
|
||||
-no-undefined
|
||||
|
||||
libtalermint_la_SOURCES = \
|
||||
mint_api_common.c mint_api_common.h \
|
||||
mint_api_context.c mint_api_context.h \
|
||||
mint_api_json.c mint_api_json.h \
|
||||
mint_api_handle.c mint_api_handle.h \
|
||||
|
154
src/mint-lib/mint_api_common.c
Normal file
154
src/mint-lib/mint_api_common.c
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2015 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see
|
||||
<http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file mint-lib/mint_api_common.c
|
||||
* @brief common functions for the mint API
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "mint_api_common.h"
|
||||
#include "mint_api_json.h"
|
||||
#include "mint_api_context.h"
|
||||
#include "mint_api_handle.h"
|
||||
#include "taler_signatures.h"
|
||||
|
||||
|
||||
/**
|
||||
* Verify a coins transaction history as returned by the mint.
|
||||
*
|
||||
* @param currency expected currency for the coin
|
||||
* @param coin_pub public key of the coin
|
||||
* @param history history of the coin in json encoding
|
||||
* @param[out] total how much of the coin has been spent according to @a history
|
||||
* @return #GNUNET_OK if @a history is valid, #GNUNET_SYSERR if not
|
||||
*/
|
||||
int
|
||||
TALER_MINT_verify_coin_history_ (const char *currency,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
json_t *history,
|
||||
struct TALER_Amount *total)
|
||||
{
|
||||
size_t len;
|
||||
size_t off;
|
||||
|
||||
if (NULL == history)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
len = json_array_size (history);
|
||||
if (0 == len)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
TALER_amount_get_zero (currency,
|
||||
total);
|
||||
for (off=0;off<len;off++)
|
||||
{
|
||||
json_t *transaction;
|
||||
struct TALER_Amount amount;
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
|
||||
struct MAJ_Specification spec[] = {
|
||||
MAJ_spec_amount ("amount",
|
||||
&amount),
|
||||
MAJ_spec_eddsa_signed_purpose ("signature",
|
||||
&purpose,
|
||||
&coin_pub->eddsa_pub),
|
||||
MAJ_spec_end
|
||||
};
|
||||
|
||||
transaction = json_array_get (history,
|
||||
off);
|
||||
if (GNUNET_OK !=
|
||||
MAJ_parse_json (transaction,
|
||||
spec))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
switch (ntohl (purpose->purpose))
|
||||
{
|
||||
case TALER_SIGNATURE_WALLET_COIN_DEPOSIT:
|
||||
{
|
||||
const struct TALER_DepositRequestPS *dr;
|
||||
struct TALER_Amount dr_amount;
|
||||
|
||||
if (ntohl (purpose->size) != sizeof (struct TALER_DepositRequestPS))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
MAJ_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
dr = (const struct TALER_DepositRequestPS *) purpose;
|
||||
TALER_amount_ntoh (&dr_amount,
|
||||
&dr->amount_with_fee);
|
||||
if (0 != TALER_amount_cmp (&dr_amount,
|
||||
&amount))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
MAJ_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TALER_SIGNATURE_WALLET_COIN_MELT:
|
||||
{
|
||||
const struct TALER_RefreshMeltCoinAffirmationPS *rm;
|
||||
struct TALER_Amount rm_amount;
|
||||
|
||||
if (ntohl (purpose->size) != sizeof (struct TALER_RefreshMeltCoinAffirmationPS))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
MAJ_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
rm = (const struct TALER_RefreshMeltCoinAffirmationPS *) purpose;
|
||||
TALER_amount_ntoh (&rm_amount,
|
||||
&rm->amount_with_fee);
|
||||
if (0 != TALER_amount_cmp (&rm_amount,
|
||||
&amount))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
MAJ_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* signature not supported, new version on server? */
|
||||
GNUNET_break (0);
|
||||
MAJ_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
TALER_amount_add (total,
|
||||
total,
|
||||
&amount))
|
||||
{
|
||||
/* overflow in history already!? inconceivable! Bad mint! */
|
||||
GNUNET_break_op (0);
|
||||
MAJ_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
MAJ_parse_free (spec);
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/* end of mint_api_common.c */
|
41
src/mint-lib/mint_api_common.h
Normal file
41
src/mint-lib/mint_api_common.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2015 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see
|
||||
<http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file mint-lib/mint_api_common.h
|
||||
* @brief common functions for the mint API
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include <jansson.h>
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include "taler_mint_service.h"
|
||||
|
||||
/**
|
||||
* Verify a coins transaction history as returned by the mint.
|
||||
*
|
||||
* @param currency expected currency for the coin
|
||||
* @param coin_pub public key of the coin
|
||||
* @param history history of the coin in json encoding
|
||||
* @param[out] total how much of the coin has been spent according to @a history
|
||||
* @return #GNUNET_OK if @a history is valid, #GNUNET_SYSERR if not
|
||||
*/
|
||||
int
|
||||
TALER_MINT_verify_coin_history_ (const char *currency,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
json_t *history,
|
||||
struct TALER_Amount *total);
|
||||
|
||||
/* end of mint_api_common.h */
|
@ -90,7 +90,7 @@ MAC_job_cancel (struct MAC_Job *job);
|
||||
|
||||
|
||||
/**
|
||||
* Buffer data structure we use to buffer the HTTP download
|
||||
* @brief Buffer data structure we use to buffer the HTTP download
|
||||
* before giving it to the JSON parser.
|
||||
*/
|
||||
struct MAC_DownloadBuffer
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <microhttpd.h> /* just for HTTP status codes */
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include "taler_mint_service.h"
|
||||
#include "mint_api_common.h"
|
||||
#include "mint_api_json.h"
|
||||
#include "mint_api_context.h"
|
||||
#include "mint_api_handle.h"
|
||||
@ -153,114 +154,19 @@ verify_deposit_signature_forbidden (const struct TALER_MINT_DepositHandle *dh,
|
||||
json_t *json)
|
||||
{
|
||||
json_t *history;
|
||||
size_t len;
|
||||
size_t off;
|
||||
struct TALER_Amount total;
|
||||
|
||||
history = json_object_get (json,
|
||||
"history");
|
||||
if (NULL == history)
|
||||
if (GNUNET_OK !=
|
||||
TALER_MINT_verify_coin_history_ (dh->coin_value.currency,
|
||||
&dh->depconf.coin_pub,
|
||||
history,
|
||||
&total))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
len = json_array_size (history);
|
||||
if (0 == len)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
TALER_amount_get_zero (dh->coin_value.currency,
|
||||
&total);
|
||||
for (off=0;off<len;off++)
|
||||
{
|
||||
json_t *transaction;
|
||||
struct TALER_Amount amount;
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose *purpose;
|
||||
struct MAJ_Specification spec[] = {
|
||||
MAJ_spec_amount ("amount",
|
||||
&amount),
|
||||
MAJ_spec_eddsa_signed_purpose ("signature",
|
||||
&purpose,
|
||||
&dh->depconf.coin_pub.eddsa_pub),
|
||||
MAJ_spec_end
|
||||
};
|
||||
|
||||
transaction = json_array_get (history,
|
||||
off);
|
||||
if (GNUNET_OK !=
|
||||
MAJ_parse_json (transaction,
|
||||
spec))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
switch (ntohl (purpose->purpose))
|
||||
{
|
||||
case TALER_SIGNATURE_WALLET_COIN_DEPOSIT:
|
||||
{
|
||||
const struct TALER_DepositRequestPS *dr;
|
||||
struct TALER_Amount dr_amount;
|
||||
|
||||
if (ntohl (purpose->size) != sizeof (struct TALER_DepositRequestPS))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
MAJ_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
dr = (const struct TALER_DepositRequestPS *) purpose;
|
||||
TALER_amount_ntoh (&dr_amount,
|
||||
&dr->amount_with_fee);
|
||||
if (0 != TALER_amount_cmp (&dr_amount,
|
||||
&amount))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
MAJ_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TALER_SIGNATURE_WALLET_COIN_MELT:
|
||||
{
|
||||
const struct TALER_RefreshMeltCoinAffirmationPS *rm;
|
||||
struct TALER_Amount rm_amount;
|
||||
|
||||
if (ntohl (purpose->size) != sizeof (struct TALER_RefreshMeltCoinAffirmationPS))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
MAJ_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
rm = (const struct TALER_RefreshMeltCoinAffirmationPS *) purpose;
|
||||
TALER_amount_ntoh (&rm_amount,
|
||||
&rm->amount_with_fee);
|
||||
if (0 != TALER_amount_cmp (&rm_amount,
|
||||
&amount))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
MAJ_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* signature not supported, new version on server? */
|
||||
GNUNET_break (0);
|
||||
MAJ_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
TALER_amount_add (&total,
|
||||
&total,
|
||||
&amount))
|
||||
{
|
||||
/* overflow in history already!? inconceivable! Bad mint! */
|
||||
GNUNET_break_op (0);
|
||||
MAJ_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
MAJ_parse_free (spec);
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
TALER_amount_add (&total,
|
||||
&total,
|
||||
@ -452,7 +358,7 @@ verify_signatures (const struct TALER_MINT_DenomPublicKey *dki,
|
||||
*
|
||||
* @param mint the mint handle; the mint must be ready to operate
|
||||
* @param amount the amount to be deposited
|
||||
* @param wire the merchant’s account details, in a format supported by the mint
|
||||
* @param wire_details the merchant’s account details, in a format supported by the mint
|
||||
* @param h_contract hash of the contact of the merchant with the customer (further details are never disclosed to the mint)
|
||||
* @param coin_pub coin’s public key
|
||||
* @param denom_pub denomination key with which the coin is signed
|
||||
|
@ -253,6 +253,37 @@ parse_json (json_t *root,
|
||||
}
|
||||
break;
|
||||
|
||||
case MAJ_CMD_UINT16:
|
||||
{
|
||||
json_int_t val;
|
||||
|
||||
if (! json_is_integer (pos))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return i;
|
||||
}
|
||||
val = json_integer_value (pos);
|
||||
if ( (0 > val) || (val > UINT16_MAX) )
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return i;
|
||||
}
|
||||
*spec[i].details.u16 = (uint16_t) val;
|
||||
}
|
||||
break;
|
||||
|
||||
case MAJ_CMD_JSON_OBJECT:
|
||||
{
|
||||
if (! (json_is_object (pos) || json_is_array (pos)) )
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return i;
|
||||
}
|
||||
json_incref (pos);
|
||||
*spec[i].details.obj = pos;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
GNUNET_break (0);
|
||||
return i;
|
||||
@ -307,6 +338,10 @@ parse_free (struct MAJ_Specification *spec,
|
||||
GNUNET_free (*spec[i].details.eddsa_signature.purpose_p);
|
||||
*spec[i].details.eddsa_signature.purpose_p = NULL;
|
||||
break;
|
||||
case MAJ_CMD_JSON_OBJECT:
|
||||
json_decref (*spec[i].details.obj);
|
||||
*spec[i].details.obj = NULL;
|
||||
break;
|
||||
default:
|
||||
GNUNET_break (0);
|
||||
break;
|
||||
@ -417,6 +452,46 @@ MAJ_spec_amount (const char *name,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 16-bit integer.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param[out] u16 where to store the integer found under @a name
|
||||
*/
|
||||
struct MAJ_Specification
|
||||
MAJ_spec_uint16 (const char *name,
|
||||
uint16_t *u16)
|
||||
{
|
||||
struct MAJ_Specification ret =
|
||||
{
|
||||
.cmd = MAJ_CMD_UINT16,
|
||||
.field = name,
|
||||
.details.u16 = u16
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* JSON object.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param[out] jsonp where to store the JSON found under @a name
|
||||
*/
|
||||
struct MAJ_Specification
|
||||
MAJ_spec_json (const char *name,
|
||||
json_t **jsonp)
|
||||
{
|
||||
struct MAJ_Specification ret =
|
||||
{
|
||||
.cmd = MAJ_CMD_JSON_OBJECT,
|
||||
.field = name,
|
||||
.details.obj = jsonp
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specification for parsing an RSA public key.
|
||||
*
|
||||
|
@ -79,7 +79,17 @@ enum MAJ_Command
|
||||
MAJ_CMD_STRING,
|
||||
|
||||
/**
|
||||
* Parse at current position.
|
||||
* Parse `uint16_t` integer at the current position.
|
||||
*/
|
||||
MAJ_CMD_UINT16,
|
||||
|
||||
/**
|
||||
* Parse JSON object at the current position.
|
||||
*/
|
||||
MAJ_CMD_JSON_OBJECT,
|
||||
|
||||
/**
|
||||
* Parse ??? at current position.
|
||||
*/
|
||||
MAJ_CMD_C
|
||||
|
||||
@ -87,7 +97,7 @@ enum MAJ_Command
|
||||
|
||||
|
||||
/**
|
||||
* Entry in parser specification for #MAJ_parse_json.
|
||||
* @brief Entry in parser specification for #MAJ_parse_json.
|
||||
*/
|
||||
struct MAJ_Specification
|
||||
{
|
||||
@ -181,6 +191,16 @@ struct MAJ_Specification
|
||||
*/
|
||||
const char **strptr;
|
||||
|
||||
/**
|
||||
* Where to store 16-bit integer.
|
||||
*/
|
||||
uint16_t *u16;
|
||||
|
||||
/**
|
||||
* Where to store a JSON object.
|
||||
*/
|
||||
json_t **obj;
|
||||
|
||||
} details;
|
||||
|
||||
};
|
||||
@ -249,13 +269,35 @@ MAJ_spec_string (const char *name,
|
||||
* Absolute time.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param at where to store the absolute time found under @a name
|
||||
* @param[out] at where to store the absolute time found under @a name
|
||||
*/
|
||||
struct MAJ_Specification
|
||||
MAJ_spec_absolute_time (const char *name,
|
||||
struct GNUNET_TIME_Absolute *at);
|
||||
|
||||
|
||||
/**
|
||||
* 16-bit integer.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param[out] u16 where to store the integer found under @a name
|
||||
*/
|
||||
struct MAJ_Specification
|
||||
MAJ_spec_uint16 (const char *name,
|
||||
uint16_t *u16);
|
||||
|
||||
|
||||
/**
|
||||
* JSON object.
|
||||
*
|
||||
* @param name name of the JSON field
|
||||
* @param[out] jsonp where to store the JSON found under @a name
|
||||
*/
|
||||
struct MAJ_Specification
|
||||
MAJ_spec_json (const char *name,
|
||||
json_t **jsonp);
|
||||
|
||||
|
||||
/**
|
||||
* Specification for parsing an amount value.
|
||||
*
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -47,11 +47,6 @@ struct TALER_MINT_RefreshLinkHandle
|
||||
*/
|
||||
char *url;
|
||||
|
||||
/**
|
||||
* JSON encoding of the request to POST.
|
||||
*/
|
||||
char *json_enc;
|
||||
|
||||
/**
|
||||
* Handle for the request.
|
||||
*/
|
||||
@ -72,9 +67,190 @@ struct TALER_MINT_RefreshLinkHandle
|
||||
*/
|
||||
struct MAC_DownloadBuffer db;
|
||||
|
||||
/**
|
||||
* Private key of the coin, required to decode link information.
|
||||
*/
|
||||
struct TALER_CoinSpendPrivateKeyP coin_priv;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse the provided linkage data from the "200 OK" response
|
||||
* for one of the coins.
|
||||
*
|
||||
* @param rlh refresh link handle
|
||||
* @param json json reply with the data for one coin
|
||||
* @param trans_pub our transfer public key
|
||||
* @param secret_enc encrypted key to decrypt link data
|
||||
* @param[out] coin_priv where to return private coin key
|
||||
* @param[out] sig where to return private coin signature
|
||||
* @param[out] pub where to return the public key for the coin
|
||||
* @return #GNUNET_OK on success, #GNUNET_SYSERR on error
|
||||
*/
|
||||
static int
|
||||
parse_refresh_link_coin (const struct TALER_MINT_RefreshLinkHandle *rlh,
|
||||
json_t *json,
|
||||
const struct TALER_TransferPublicKeyP *trans_pub,
|
||||
const struct TALER_EncryptedLinkSecretP *secret_enc,
|
||||
struct TALER_CoinSpendPrivateKeyP *coin_priv,
|
||||
struct TALER_DenominationSignature *sig,
|
||||
struct TALER_DenominationPublicKey *pub)
|
||||
{
|
||||
void *link_enc;
|
||||
size_t link_enc_size;
|
||||
struct GNUNET_CRYPTO_rsa_Signature *bsig;
|
||||
struct MAJ_Specification spec[] = {
|
||||
MAJ_spec_varsize ("link_enc", &link_enc, &link_enc_size),
|
||||
MAJ_spec_rsa_public_key ("denom_pub", &pub->rsa_public_key),
|
||||
MAJ_spec_rsa_signature ("ev_sig", &bsig),
|
||||
MAJ_spec_end
|
||||
};
|
||||
struct TALER_RefreshLinkEncrypted *rle;
|
||||
struct TALER_RefreshLinkDecrypted *rld;
|
||||
struct TALER_LinkSecretP secret;
|
||||
|
||||
/* parse reply */
|
||||
if (GNUNET_OK !=
|
||||
MAJ_parse_json (json,
|
||||
spec))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
/* decode and decrypt link data */
|
||||
rle = TALER_refresh_link_encrypted_decode (link_enc,
|
||||
link_enc_size);
|
||||
if (NULL == rle)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
MAJ_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
TALER_link_decrypt_secret2 (secret_enc,
|
||||
trans_pub,
|
||||
&rlh->coin_priv,
|
||||
&secret))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
MAJ_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
rld = TALER_refresh_decrypt (rle,
|
||||
&secret);
|
||||
if (NULL == rld)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
MAJ_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
/* extract coin and signature */
|
||||
*coin_priv = rld->coin_priv;
|
||||
sig->rsa_signature
|
||||
= GNUNET_CRYPTO_rsa_unblind (bsig,
|
||||
rld->blinding_key.rsa_blinding_key,
|
||||
pub->rsa_public_key);
|
||||
|
||||
/* clean up */
|
||||
GNUNET_free (rld);
|
||||
MAJ_parse_free (spec);
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse the provided linkage data from the "200 OK" response
|
||||
* for one of the coins.
|
||||
*
|
||||
* @param[in,out] rlh refresh link handle (callback may be zero'ed out)
|
||||
* @param json json reply with the data for one coin
|
||||
* @return #GNUNET_OK on success, #GNUNET_SYSERR on error
|
||||
*/
|
||||
static int
|
||||
parse_refresh_link_ok (struct TALER_MINT_RefreshLinkHandle *rlh,
|
||||
json_t *json)
|
||||
{
|
||||
json_t *jsona;
|
||||
struct TALER_TransferPublicKeyP trans_pub;
|
||||
struct TALER_EncryptedLinkSecretP secret_enc;
|
||||
struct MAJ_Specification spec[] = {
|
||||
MAJ_spec_json ("new_coins", &jsona),
|
||||
MAJ_spec_fixed_auto ("trans_pub", &trans_pub),
|
||||
MAJ_spec_fixed_auto ("secret_enc", &secret_enc),
|
||||
MAJ_spec_end
|
||||
};
|
||||
unsigned int num_coins;
|
||||
int ret;
|
||||
|
||||
if (GNUNET_OK !=
|
||||
MAJ_parse_json (json,
|
||||
spec))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (! json_is_array (jsona))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
MAJ_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
/* decode all coins */
|
||||
num_coins = json_array_size (json);
|
||||
{
|
||||
unsigned int i;
|
||||
struct TALER_CoinSpendPrivateKeyP coin_privs[num_coins];
|
||||
struct TALER_DenominationSignature sigs[num_coins];
|
||||
struct TALER_DenominationPublicKey pubs[num_coins];
|
||||
|
||||
for (i=0;i<num_coins;i++)
|
||||
{
|
||||
if (GNUNET_OK !=
|
||||
parse_refresh_link_coin (rlh,
|
||||
json_array_get (json, i),
|
||||
&trans_pub,
|
||||
&secret_enc,
|
||||
&coin_privs[i],
|
||||
&sigs[i],
|
||||
&pubs[i]))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if we really got all, then invoke callback */
|
||||
if (i != num_coins)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
ret = GNUNET_SYSERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
rlh->link_cb (rlh->link_cb_cls,
|
||||
MHD_HTTP_OK,
|
||||
num_coins,
|
||||
coin_privs,
|
||||
sigs,
|
||||
pubs,
|
||||
json);
|
||||
rlh->link_cb = NULL;
|
||||
ret = GNUNET_OK;
|
||||
}
|
||||
|
||||
/* clean up */
|
||||
for (i=0;i<num_coins;i++)
|
||||
if (NULL != sigs[i].rsa_signature)
|
||||
GNUNET_CRYPTO_rsa_signature_free (sigs[i].rsa_signature);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called when we're done processing the
|
||||
* HTTP /refresh/link request.
|
||||
@ -99,8 +275,13 @@ handle_refresh_link_finished (void *cls,
|
||||
case 0:
|
||||
break;
|
||||
case MHD_HTTP_OK:
|
||||
GNUNET_break (0); // FIXME: NOT implemented!
|
||||
// rh->link_cb = NULL; (call with real result, do not call again below)
|
||||
if (GNUNET_OK !=
|
||||
parse_refresh_link_ok (rlh,
|
||||
json))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
response_code = 0;
|
||||
}
|
||||
break;
|
||||
case MHD_HTTP_BAD_REQUEST:
|
||||
/* This should never happen, either us or the mint is buggy
|
||||
@ -126,7 +307,7 @@ handle_refresh_link_finished (void *cls,
|
||||
if (NULL != rlh->link_cb)
|
||||
rlh->link_cb (rlh->link_cb_cls,
|
||||
response_code,
|
||||
0, NULL, NULL,
|
||||
0, NULL, NULL, NULL,
|
||||
json);
|
||||
json_decref (json);
|
||||
TALER_MINT_refresh_link_cancel (rlh);
|
||||
@ -153,10 +334,12 @@ TALER_MINT_refresh_link (struct TALER_MINT_Handle *mint,
|
||||
TALER_MINT_RefreshLinkCallback link_cb,
|
||||
void *link_cb_cls)
|
||||
{
|
||||
json_t *link_obj;
|
||||
struct TALER_MINT_RefreshLinkHandle *rlh;
|
||||
CURL *eh;
|
||||
struct TALER_MINT_Context *ctx;
|
||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||
char *pub_str;
|
||||
char *arg_str;
|
||||
|
||||
if (GNUNET_YES !=
|
||||
MAH_handle_is_ready (mint))
|
||||
@ -164,36 +347,29 @@ TALER_MINT_refresh_link (struct TALER_MINT_Handle *mint,
|
||||
GNUNET_break (0);
|
||||
return NULL;
|
||||
}
|
||||
/* FIXME: totally bogus request building here: */
|
||||
link_obj = json_pack ("{s:o, s:O}", /* f/wire */
|
||||
"4", 42,
|
||||
"6", 62);
|
||||
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
|
||||
&coin_pub.eddsa_pub);
|
||||
pub_str = GNUNET_STRINGS_data_to_string_alloc (&coin_pub,
|
||||
sizeof (struct TALER_CoinSpendPublicKeyP));
|
||||
GNUNET_asprintf (&arg_str,
|
||||
"/refresh/link?coin_pub=%s",
|
||||
pub_str);
|
||||
GNUNET_free (pub_str);
|
||||
|
||||
rlh = GNUNET_new (struct TALER_MINT_RefreshLinkHandle);
|
||||
rlh->mint = mint;
|
||||
rlh->link_cb = link_cb;
|
||||
rlh->link_cb_cls = link_cb_cls;
|
||||
|
||||
rlh->url = MAH_path_to_url (mint, "/refresh/link");
|
||||
rlh->coin_priv = *coin_priv;
|
||||
rlh->url = MAH_path_to_url (mint, arg_str);
|
||||
GNUNET_free (arg_str);
|
||||
|
||||
eh = curl_easy_init ();
|
||||
GNUNET_assert (NULL != (rlh->json_enc =
|
||||
json_dumps (link_obj,
|
||||
JSON_COMPACT)));
|
||||
json_decref (link_obj);
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_URL,
|
||||
rlh->url));
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_POSTFIELDS,
|
||||
rlh->json_enc));
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_POSTFIELDSIZE,
|
||||
strlen (rlh->json_enc)));
|
||||
GNUNET_assert (CURLE_OK ==
|
||||
curl_easy_setopt (eh,
|
||||
CURLOPT_WRITEFUNCTION,
|
||||
@ -228,7 +404,6 @@ TALER_MINT_refresh_link_cancel (struct TALER_MINT_RefreshLinkHandle *rlh)
|
||||
}
|
||||
GNUNET_free_non_null (rlh->db.buf);
|
||||
GNUNET_free (rlh->url);
|
||||
GNUNET_free (rlh->json_enc);
|
||||
GNUNET_free (rlh);
|
||||
}
|
||||
|
||||
|
@ -287,6 +287,7 @@ handle_withdraw_status_finished (void *cls,
|
||||
break;
|
||||
case MHD_HTTP_OK:
|
||||
{
|
||||
/* TODO: move into separate function... */
|
||||
json_t *history;
|
||||
unsigned int len;
|
||||
struct TALER_Amount balance;
|
||||
|
@ -19,6 +19,17 @@ lookahead_provide = 4 weeks 1 day
|
||||
# name begins with "coin_". The rest of the
|
||||
# name is free, but of course following the convention
|
||||
# of "coin_$CURRENCY[_$SUBUNIT]_$VALUE" make sense.
|
||||
[coin_eur_ct_1]
|
||||
value = EUR:0.01
|
||||
duration_overlap = 5 minutes
|
||||
duration_withdraw = 7 days
|
||||
duration_spend = 2 years
|
||||
duration_legal = 3 years
|
||||
fee_withdraw = EUR:0.00
|
||||
fee_deposit = EUR:0.00
|
||||
fee_refresh = EUR:0.01
|
||||
rsa_keysize = 1024
|
||||
|
||||
[coin_eur_ct_10]
|
||||
value = EUR:0.10
|
||||
duration_overlap = 5 minutes
|
||||
@ -27,7 +38,18 @@ duration_spend = 2 years
|
||||
duration_legal = 3 years
|
||||
fee_withdraw = EUR:0.01
|
||||
fee_deposit = EUR:0.01
|
||||
fee_refresh = EUR:0.01
|
||||
fee_refresh = EUR:0.03
|
||||
rsa_keysize = 1024
|
||||
|
||||
[coin_eur_1]
|
||||
value = EUR:1
|
||||
duration_overlap = 5 minutes
|
||||
duration_withdraw = 7 days
|
||||
duration_spend = 2 years
|
||||
duration_legal = 3 years
|
||||
fee_withdraw = EUR:0.01
|
||||
fee_deposit = EUR:0.01
|
||||
fee_refresh = EUR:0.03
|
||||
rsa_keysize = 1024
|
||||
|
||||
[coin_eur_5]
|
||||
@ -38,7 +60,7 @@ duration_spend = 2 years
|
||||
duration_legal = 3 years
|
||||
fee_withdraw = EUR:0.01
|
||||
fee_deposit = EUR:0.01
|
||||
fee_refresh = EUR:0.01
|
||||
fee_refresh = EUR:0.03
|
||||
rsa_keysize = 1024
|
||||
|
||||
[coin_eur_10]
|
||||
@ -49,7 +71,7 @@ duration_spend = 2 years
|
||||
duration_legal = 3 years
|
||||
fee_withdraw = EUR:0.01
|
||||
fee_deposit = EUR:0.01
|
||||
fee_refresh = EUR:0.01
|
||||
fee_refresh = EUR:0.03
|
||||
rsa_keysize = 1024
|
||||
|
||||
[coin_eur_1000]
|
||||
@ -60,5 +82,5 @@ duration_spend = 2 years
|
||||
duration_legal = 3 years
|
||||
fee_withdraw = EUR:0.01
|
||||
fee_deposit = EUR:0.01
|
||||
fee_refresh = EUR:0.01
|
||||
fee_refresh = EUR:0.03
|
||||
rsa_keysize = 2048
|
||||
|
@ -81,7 +81,72 @@ enum OpCode
|
||||
/**
|
||||
* Deposit a coin (pay with it).
|
||||
*/
|
||||
OC_DEPOSIT
|
||||
OC_DEPOSIT,
|
||||
|
||||
/**
|
||||
* Melt a (set of) coins.
|
||||
*/
|
||||
OC_REFRESH_MELT,
|
||||
|
||||
/**
|
||||
* Complete melting session by withdrawing melted coins.
|
||||
*/
|
||||
OC_REFRESH_REVEAL,
|
||||
|
||||
/**
|
||||
* Verify mint's /refresh/link by linking original private key to
|
||||
* results from #OC_REFRESH_REVEAL step.
|
||||
*/
|
||||
OC_REFRESH_LINK
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Structure specifying details about a coin to be melted.
|
||||
* Used in a NULL-terminated array as part of command
|
||||
* specification.
|
||||
*/
|
||||
struct MeltDetails
|
||||
{
|
||||
|
||||
/**
|
||||
* Amount to melt (including fee).
|
||||
*/
|
||||
const char *amount;
|
||||
|
||||
/**
|
||||
* Reference to withdraw_sign operations for coin to
|
||||
* be used for the /refresh/melt operation.
|
||||
*/
|
||||
const char *coin_ref;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Information about a fresh coin generated by the refresh operation.
|
||||
*/
|
||||
struct FreshCoin
|
||||
{
|
||||
|
||||
/**
|
||||
* If @e amount is NULL, this specifies the denomination key to
|
||||
* use. Otherwise, this will be set (by the interpreter) to the
|
||||
* denomination PK matching @e amount.
|
||||
*/
|
||||
const struct TALER_MINT_DenomPublicKey *pk;
|
||||
|
||||
/**
|
||||
* Set (by the interpreter) to the mint's signature over the
|
||||
* coin's public key.
|
||||
*/
|
||||
struct TALER_DenominationSignature sig;
|
||||
|
||||
/**
|
||||
* Set (by the interpreter) to the coin's private key.
|
||||
*/
|
||||
struct TALER_CoinSpendPrivateKeyP coin_priv;
|
||||
|
||||
};
|
||||
|
||||
@ -112,6 +177,9 @@ struct Command
|
||||
union
|
||||
{
|
||||
|
||||
/**
|
||||
* Information for a #OC_ADMIN_ADD_INCOMING command.
|
||||
*/
|
||||
struct
|
||||
{
|
||||
|
||||
@ -145,6 +213,9 @@ struct Command
|
||||
|
||||
} admin_add_incoming;
|
||||
|
||||
/**
|
||||
* Information for a #OC_WITHDRAW_STATUS command.
|
||||
*/
|
||||
struct
|
||||
{
|
||||
|
||||
@ -166,8 +237,12 @@ struct Command
|
||||
|
||||
} withdraw_status;
|
||||
|
||||
/**
|
||||
* Information for a #OC_WITHDRAW_SIGN command.
|
||||
*/
|
||||
struct
|
||||
{
|
||||
|
||||
/**
|
||||
* Which reserve should we withdraw from?
|
||||
*/
|
||||
@ -210,6 +285,9 @@ struct Command
|
||||
|
||||
} withdraw_sign;
|
||||
|
||||
/**
|
||||
* Information for a #OC_DEPOSIT command.
|
||||
*/
|
||||
struct
|
||||
{
|
||||
|
||||
@ -224,6 +302,12 @@ struct Command
|
||||
*/
|
||||
const char *coin_ref;
|
||||
|
||||
/**
|
||||
* If this @e coin_ref refers to an operation that generated
|
||||
* an array of coins, this value determines which coin to use.
|
||||
*/
|
||||
unsigned int coin_idx;
|
||||
|
||||
/**
|
||||
* JSON string describing the merchant's "wire details".
|
||||
*/
|
||||
@ -258,6 +342,103 @@ struct Command
|
||||
|
||||
} deposit;
|
||||
|
||||
/**
|
||||
* Information for a #OC_REFRESH_MELT command.
|
||||
*/
|
||||
struct
|
||||
{
|
||||
|
||||
/**
|
||||
* Information about coins to be melted.
|
||||
*/
|
||||
struct MeltDetails *melted_coins;
|
||||
|
||||
/**
|
||||
* Denominations of the fresh coins to withdraw.
|
||||
*/
|
||||
const char **fresh_amounts;
|
||||
|
||||
/**
|
||||
* Array of the public keys corresponding to
|
||||
* the @e fresh_amounts, set by the interpreter.
|
||||
*/
|
||||
const struct TALER_MINT_DenomPublicKey **fresh_pks;
|
||||
|
||||
/**
|
||||
* Melt handle while operation is running.
|
||||
*/
|
||||
struct TALER_MINT_RefreshMeltHandle *rmh;
|
||||
|
||||
/**
|
||||
* Data used in the refresh operation, set by the interpreter.
|
||||
*/
|
||||
char *refresh_data;
|
||||
|
||||
/**
|
||||
* Number of bytes in @e refresh_data, set by the interpreter.
|
||||
*/
|
||||
size_t refresh_data_length;
|
||||
|
||||
/**
|
||||
* Set by the interpreter (upon completion) to the noreveal
|
||||
* index selected by the mint.
|
||||
*/
|
||||
uint16_t noreveal_index;
|
||||
|
||||
} refresh_melt;
|
||||
|
||||
/**
|
||||
* Information for a #OC_REFRESH_REVEAL command.
|
||||
*/
|
||||
struct
|
||||
{
|
||||
|
||||
/**
|
||||
* Melt operation this is the matching reveal for.
|
||||
*/
|
||||
const char *melt_ref;
|
||||
|
||||
/**
|
||||
* Reveal handle while operation is running.
|
||||
*/
|
||||
struct TALER_MINT_RefreshRevealHandle *rrh;
|
||||
|
||||
/**
|
||||
* Number of fresh coins withdrawn, set by the interpreter.
|
||||
* Length of the @e fresh_coins array.
|
||||
*/
|
||||
unsigned int num_fresh_coins;
|
||||
|
||||
/**
|
||||
* Information about coins withdrawn, set by the interpreter.
|
||||
*/
|
||||
struct FreshCoin *fresh_coins;
|
||||
|
||||
} refresh_reveal;
|
||||
|
||||
/**
|
||||
* Information for a #OC_REFRESH_LINK command.
|
||||
*/
|
||||
struct
|
||||
{
|
||||
|
||||
/**
|
||||
* Reveal operation this is the matching link for.
|
||||
*/
|
||||
const char *reveal_ref;
|
||||
|
||||
/**
|
||||
* Link handle while operation is running.
|
||||
*/
|
||||
struct TALER_MINT_RefreshLinkHandle *rlh;
|
||||
|
||||
/**
|
||||
* Which of the melted coins should be used for the linkage?
|
||||
*/
|
||||
unsigned int coin_idx;
|
||||
|
||||
} refresh_link;
|
||||
|
||||
} details;
|
||||
|
||||
};
|
||||
@ -671,7 +852,182 @@ deposit_cb (void *cls,
|
||||
is->ip++;
|
||||
is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
|
||||
is);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called with the result of the /refresh/melt operation.
|
||||
*
|
||||
* @param cls closure with the interpreter state
|
||||
* @param http_status HTTP response code, never #MHD_HTTP_OK (200) as for successful intermediate response this callback is skipped.
|
||||
* 0 if the mint's reply is bogus (fails to follow the protocol)
|
||||
* @param noreveal_index choice by the mint in the cut-and-choose protocol,
|
||||
* UINT16_MAX on error
|
||||
* @param full_response full response from the mint (for logging, in case of errors)
|
||||
*/
|
||||
static void
|
||||
melt_cb (void *cls,
|
||||
unsigned int http_status,
|
||||
uint16_t noreveal_index,
|
||||
json_t *full_response)
|
||||
{
|
||||
struct InterpreterState *is = cls;
|
||||
struct Command *cmd = &is->commands[is->ip];
|
||||
|
||||
cmd->details.refresh_melt.rmh = NULL;
|
||||
if (cmd->expected_response_code != http_status)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Unexpected response code %u to command %s\n",
|
||||
http_status,
|
||||
cmd->label);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
cmd->details.refresh_melt.noreveal_index = noreveal_index;
|
||||
is->ip++;
|
||||
is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
|
||||
is);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called with the result of the /refresh/reveal operation.
|
||||
*
|
||||
* @param cls closure with the interpreter state
|
||||
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
|
||||
* 0 if the mint's reply is bogus (fails to follow the protocol)
|
||||
* @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed
|
||||
* @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error
|
||||
* @param sigs array of signature over @a num_coins coins, NULL on error
|
||||
* @param full_response full response from the mint (for logging, in case of errors)
|
||||
*/
|
||||
static void
|
||||
reveal_cb (void *cls,
|
||||
unsigned int http_status,
|
||||
unsigned int num_coins,
|
||||
const struct TALER_CoinSpendPrivateKeyP *coin_privs,
|
||||
const struct TALER_DenominationSignature *sigs,
|
||||
json_t *full_response)
|
||||
{
|
||||
struct InterpreterState *is = cls;
|
||||
struct Command *cmd = &is->commands[is->ip];
|
||||
const struct Command *ref;
|
||||
unsigned int i;
|
||||
|
||||
cmd->details.refresh_reveal.rrh = NULL;
|
||||
if (cmd->expected_response_code != http_status)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Unexpected response code %u to command %s\n",
|
||||
http_status,
|
||||
cmd->label);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
ref = find_command (is,
|
||||
cmd->details.refresh_reveal.melt_ref);
|
||||
cmd->details.refresh_reveal.num_fresh_coins = num_coins;
|
||||
switch (http_status)
|
||||
{
|
||||
case MHD_HTTP_OK:
|
||||
cmd->details.refresh_reveal.fresh_coins
|
||||
= GNUNET_new_array (num_coins,
|
||||
struct FreshCoin);
|
||||
for (i=0;i<num_coins;i++)
|
||||
{
|
||||
struct FreshCoin *fc = &cmd->details.refresh_reveal.fresh_coins[i];
|
||||
|
||||
fc->pk = ref->details.refresh_melt.fresh_pks[i];
|
||||
fc->coin_priv = coin_privs[i];
|
||||
fc->sig.rsa_signature
|
||||
= GNUNET_CRYPTO_rsa_signature_dup (sigs[i].rsa_signature);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
is->ip++;
|
||||
is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
|
||||
is);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called with the result of a /refresh/link operation.
|
||||
*
|
||||
* @param cls closure with the interpreter state
|
||||
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
|
||||
* 0 if the mint's reply is bogus (fails to follow the protocol)
|
||||
* @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed
|
||||
* @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error
|
||||
* @param sigs array of signature over @a num_coins coins, NULL on error
|
||||
* @param pubs array of public keys for the @a sigs, NULL on error
|
||||
* @param full_response full response from the mint (for logging, in case of errors)
|
||||
*/
|
||||
static void
|
||||
link_cb (void *cls,
|
||||
unsigned int http_status,
|
||||
unsigned int num_coins,
|
||||
const struct TALER_CoinSpendPrivateKeyP *coin_privs,
|
||||
const struct TALER_DenominationSignature *sigs,
|
||||
const struct TALER_DenominationPublicKey *pubs,
|
||||
json_t *full_response)
|
||||
{
|
||||
struct InterpreterState *is = cls;
|
||||
struct Command *cmd = &is->commands[is->ip];
|
||||
const struct Command *ref;
|
||||
unsigned int i;
|
||||
|
||||
cmd->details.refresh_link.rlh = NULL;
|
||||
if (cmd->expected_response_code != http_status)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Unexpected response code %u to command %s\n",
|
||||
http_status,
|
||||
cmd->label);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
ref = find_command (is,
|
||||
cmd->details.refresh_link.reveal_ref);
|
||||
switch (http_status)
|
||||
{
|
||||
case MHD_HTTP_OK:
|
||||
/* check that number of coins returned matches */
|
||||
if (num_coins != ref->details.refresh_reveal.num_fresh_coins)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
/* check that the coins match */
|
||||
for (i=0;i<num_coins;i++)
|
||||
{
|
||||
const struct FreshCoin *fc;
|
||||
|
||||
fc = &ref->details.refresh_reveal.fresh_coins[i];
|
||||
if ( (0 != memcmp (&coin_privs[i],
|
||||
&fc->coin_priv,
|
||||
sizeof (struct TALER_CoinSpendPrivateKeyP))) ||
|
||||
(0 != GNUNET_CRYPTO_rsa_signature_cmp (fc->sig.rsa_signature,
|
||||
sigs[i].rsa_signature)) ||
|
||||
(0 != GNUNET_CRYPTO_rsa_public_key_cmp (fc->pk->key.rsa_public_key,
|
||||
pubs[i].rsa_public_key)) )
|
||||
{
|
||||
GNUNET_break (0);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
is->ip++;
|
||||
is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
|
||||
is);
|
||||
}
|
||||
|
||||
|
||||
@ -904,6 +1260,9 @@ interpreter_run (void *cls,
|
||||
case OC_DEPOSIT:
|
||||
{
|
||||
struct GNUNET_HashCode h_contract;
|
||||
const struct TALER_CoinSpendPrivateKeyP *coin_priv;
|
||||
const struct TALER_MINT_DenomPublicKey *coin_pk;
|
||||
const struct TALER_DenominationSignature *coin_pk_sig;
|
||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||
struct TALER_CoinSpendSignatureP coin_sig;
|
||||
struct GNUNET_TIME_Absolute refund_deadline;
|
||||
@ -916,7 +1275,30 @@ interpreter_run (void *cls,
|
||||
ref = find_command (is,
|
||||
cmd->details.deposit.coin_ref);
|
||||
GNUNET_assert (NULL != ref);
|
||||
GNUNET_assert (OC_WITHDRAW_SIGN == ref->oc);
|
||||
switch (ref->oc)
|
||||
{
|
||||
case OC_WITHDRAW_SIGN:
|
||||
coin_priv = &ref->details.withdraw_sign.coin_priv;
|
||||
coin_pk = ref->details.withdraw_sign.pk;
|
||||
coin_pk_sig = &ref->details.withdraw_sign.sig;
|
||||
break;
|
||||
case OC_REFRESH_REVEAL:
|
||||
{
|
||||
const struct FreshCoin *fc;
|
||||
unsigned int idx;
|
||||
|
||||
idx = cmd->details.deposit.coin_idx;
|
||||
GNUNET_assert (idx < ref->details.refresh_reveal.num_fresh_coins);
|
||||
fc = &ref->details.refresh_reveal.fresh_coins[idx];
|
||||
|
||||
coin_priv = &fc->coin_priv;
|
||||
coin_pk = fc->pk;
|
||||
coin_pk_sig = &fc->sig;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
GNUNET_assert (0);
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
TALER_string_to_amount (cmd->details.deposit.amount,
|
||||
&amount))
|
||||
@ -943,7 +1325,8 @@ interpreter_run (void *cls,
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&ref->details.withdraw_sign.coin_priv.eddsa_priv,
|
||||
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
|
||||
&coin_pub.eddsa_pub);
|
||||
|
||||
if (0 != cmd->details.deposit.refund_deadline.rel_value_us)
|
||||
@ -975,11 +1358,11 @@ interpreter_run (void *cls,
|
||||
TALER_amount_hton (&dr.amount_with_fee,
|
||||
&amount);
|
||||
TALER_amount_hton (&dr.deposit_fee,
|
||||
&ref->details.withdraw_sign.pk->fee_deposit);
|
||||
&coin_pk->fee_deposit);
|
||||
dr.merchant = merchant_pub;
|
||||
dr.coin_pub = coin_pub;
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
GNUNET_CRYPTO_eddsa_sign (&ref->details.withdraw_sign.coin_priv.eddsa_priv,
|
||||
GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv,
|
||||
&dr.purpose,
|
||||
&coin_sig.eddsa_signature));
|
||||
|
||||
@ -990,8 +1373,8 @@ interpreter_run (void *cls,
|
||||
wire,
|
||||
&h_contract,
|
||||
&coin_pub,
|
||||
&ref->details.withdraw_sign.sig,
|
||||
&ref->details.withdraw_sign.pk->key,
|
||||
coin_pk_sig,
|
||||
&coin_pk->key,
|
||||
timestamp,
|
||||
cmd->details.deposit.transaction_id,
|
||||
&merchant_pub,
|
||||
@ -1009,6 +1392,157 @@ interpreter_run (void *cls,
|
||||
trigger_context_task ();
|
||||
return;
|
||||
}
|
||||
case OC_REFRESH_MELT:
|
||||
{
|
||||
unsigned int num_melted_coins;
|
||||
unsigned int num_fresh_coins;
|
||||
|
||||
cmd->details.refresh_melt.noreveal_index = UINT16_MAX;
|
||||
for (num_melted_coins=0;
|
||||
NULL != cmd->details.refresh_melt.melted_coins[num_melted_coins].amount;
|
||||
num_melted_coins++) ;
|
||||
for (num_fresh_coins=0;
|
||||
NULL != cmd->details.refresh_melt.fresh_amounts[num_fresh_coins];
|
||||
num_fresh_coins++) ;
|
||||
|
||||
cmd->details.refresh_melt.fresh_pks
|
||||
= GNUNET_new_array (num_fresh_coins,
|
||||
const struct TALER_MINT_DenomPublicKey *);
|
||||
{
|
||||
struct TALER_CoinSpendPrivateKeyP melt_privs[num_melted_coins];
|
||||
struct TALER_Amount melt_amounts[num_melted_coins];
|
||||
struct TALER_DenominationSignature melt_sigs[num_melted_coins];
|
||||
struct TALER_MINT_DenomPublicKey melt_pks[num_melted_coins];
|
||||
struct TALER_MINT_DenomPublicKey fresh_pks[num_fresh_coins];
|
||||
unsigned int i;
|
||||
|
||||
for (i=0;i<num_melted_coins;i++)
|
||||
{
|
||||
const struct MeltDetails *md = &cmd->details.refresh_melt.melted_coins[i];
|
||||
ref = find_command (is,
|
||||
md->coin_ref);
|
||||
GNUNET_assert (NULL != ref);
|
||||
GNUNET_assert (OC_WITHDRAW_SIGN == ref->oc);
|
||||
|
||||
melt_privs[i] = ref->details.withdraw_sign.coin_priv;
|
||||
if (GNUNET_OK !=
|
||||
TALER_string_to_amount (md->amount,
|
||||
&melt_amounts[i]))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to parse amount `%s' at %u\n",
|
||||
md->amount,
|
||||
is->ip);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
melt_sigs[i] = ref->details.withdraw_sign.sig;
|
||||
melt_pks[i] = *ref->details.withdraw_sign.pk;
|
||||
}
|
||||
for (i=0;i<num_fresh_coins;i++)
|
||||
{
|
||||
if (GNUNET_OK !=
|
||||
TALER_string_to_amount (cmd->details.refresh_melt.fresh_amounts[i],
|
||||
&amount))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to parse amount `%s' at %u\n",
|
||||
cmd->details.withdraw_sign.amount,
|
||||
is->ip);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
cmd->details.refresh_melt.fresh_pks[i]
|
||||
= find_pk (is->keys,
|
||||
&amount);
|
||||
fresh_pks[i] = *cmd->details.refresh_melt.fresh_pks[i];
|
||||
}
|
||||
cmd->details.refresh_melt.refresh_data
|
||||
= TALER_MINT_refresh_prepare (num_melted_coins,
|
||||
melt_privs,
|
||||
melt_amounts,
|
||||
melt_sigs,
|
||||
melt_pks,
|
||||
GNUNET_YES,
|
||||
num_fresh_coins,
|
||||
fresh_pks,
|
||||
&cmd->details.refresh_melt.refresh_data_length);
|
||||
if (NULL == cmd->details.refresh_melt.refresh_data)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
cmd->details.refresh_melt.rmh
|
||||
= TALER_MINT_refresh_melt (mint,
|
||||
cmd->details.refresh_melt.refresh_data_length,
|
||||
cmd->details.refresh_melt.refresh_data,
|
||||
&melt_cb,
|
||||
is);
|
||||
if (NULL == cmd->details.refresh_melt.rmh)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
trigger_context_task ();
|
||||
return;
|
||||
case OC_REFRESH_REVEAL:
|
||||
ref = find_command (is,
|
||||
cmd->details.refresh_reveal.melt_ref);
|
||||
cmd->details.refresh_reveal.rrh
|
||||
= TALER_MINT_refresh_reveal (mint,
|
||||
ref->details.refresh_melt.refresh_data_length,
|
||||
ref->details.refresh_melt.refresh_data,
|
||||
ref->details.refresh_melt.noreveal_index,
|
||||
&reveal_cb,
|
||||
is);
|
||||
if (NULL == cmd->details.refresh_reveal.rrh)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
trigger_context_task ();
|
||||
return;
|
||||
case OC_REFRESH_LINK:
|
||||
/* find reveal command */
|
||||
ref = find_command (is,
|
||||
cmd->details.refresh_link.reveal_ref);
|
||||
/* find melt command */
|
||||
ref = find_command (is,
|
||||
ref->details.refresh_reveal.melt_ref);
|
||||
/* find withdraw_sign command */
|
||||
{
|
||||
unsigned int idx;
|
||||
const struct MeltDetails *md;
|
||||
unsigned int num_melted_coins;
|
||||
|
||||
for (num_melted_coins=0;
|
||||
NULL != ref->details.refresh_melt.melted_coins[num_melted_coins].amount;
|
||||
num_melted_coins++) ;
|
||||
idx = cmd->details.refresh_link.coin_idx;
|
||||
GNUNET_assert (idx < num_melted_coins);
|
||||
md = &ref->details.refresh_melt.melted_coins[idx];
|
||||
ref = find_command (is,
|
||||
md->coin_ref);
|
||||
}
|
||||
/* finally, use private key from withdraw sign command */
|
||||
cmd->details.refresh_link.rlh
|
||||
= TALER_MINT_refresh_link (mint,
|
||||
&ref->details.withdraw_sign.coin_priv,
|
||||
&link_cb,
|
||||
is);
|
||||
if (NULL == cmd->details.refresh_link.rlh)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
fail (is);
|
||||
return;
|
||||
}
|
||||
trigger_context_task ();
|
||||
return;
|
||||
default:
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Unknown instruction %d at %u (%s)\n",
|
||||
@ -1100,6 +1634,55 @@ do_shutdown (void *cls,
|
||||
cmd->details.deposit.dh = NULL;
|
||||
}
|
||||
break;
|
||||
case OC_REFRESH_MELT:
|
||||
if (NULL != cmd->details.refresh_melt.rmh)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"Command %u (%s) did not complete\n",
|
||||
i,
|
||||
cmd->label);
|
||||
TALER_MINT_refresh_melt_cancel (cmd->details.refresh_melt.rmh);
|
||||
cmd->details.refresh_melt.rmh = NULL;
|
||||
}
|
||||
GNUNET_free_non_null (cmd->details.refresh_melt.fresh_pks);
|
||||
cmd->details.refresh_melt.fresh_pks = NULL;
|
||||
GNUNET_free_non_null (cmd->details.refresh_melt.refresh_data);
|
||||
cmd->details.refresh_melt.refresh_data = NULL;
|
||||
cmd->details.refresh_melt.refresh_data_length = 0;
|
||||
break;
|
||||
case OC_REFRESH_REVEAL:
|
||||
if (NULL != cmd->details.refresh_reveal.rrh)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"Command %u (%s) did not complete\n",
|
||||
i,
|
||||
cmd->label);
|
||||
TALER_MINT_refresh_reveal_cancel (cmd->details.refresh_reveal.rrh);
|
||||
cmd->details.refresh_reveal.rrh = NULL;
|
||||
}
|
||||
{
|
||||
unsigned int j;
|
||||
struct FreshCoin *fresh_coins;
|
||||
|
||||
fresh_coins = cmd->details.refresh_reveal.fresh_coins;
|
||||
for (j=0;j<cmd->details.refresh_reveal.num_fresh_coins;j++)
|
||||
GNUNET_CRYPTO_rsa_signature_free (fresh_coins[j].sig.rsa_signature);
|
||||
}
|
||||
GNUNET_free_non_null (cmd->details.refresh_reveal.fresh_coins);
|
||||
cmd->details.refresh_reveal.fresh_coins = NULL;
|
||||
cmd->details.refresh_reveal.num_fresh_coins = 0;
|
||||
break;
|
||||
case OC_REFRESH_LINK:
|
||||
if (NULL != cmd->details.refresh_link.rlh)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"Command %u (%s) did not complete\n",
|
||||
i,
|
||||
cmd->label);
|
||||
TALER_MINT_refresh_link_cancel (cmd->details.refresh_link.rlh);
|
||||
cmd->details.refresh_link.rlh = NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Unknown instruction %d at %u (%s)\n",
|
||||
@ -1236,6 +1819,34 @@ run (void *cls,
|
||||
const struct GNUNET_SCHEDULER_TaskContext *tc)
|
||||
{
|
||||
struct InterpreterState *is;
|
||||
static struct MeltDetails melt_coins_1[] = {
|
||||
{ .amount = "EUR:4",
|
||||
.coin_ref = "refresh-withdraw-coin-1" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
static const char *melt_fresh_amounts_1[] = {
|
||||
"EUR:1",
|
||||
"EUR:1",
|
||||
"EUR:1",
|
||||
"EUR:0.1",
|
||||
"EUR:0.1",
|
||||
"EUR:0.1",
|
||||
"EUR:0.1",
|
||||
"EUR:0.1",
|
||||
"EUR:0.1",
|
||||
"EUR:0.1",
|
||||
"EUR:0.1",
|
||||
"EUR:0.01",
|
||||
"EUR:0.01",
|
||||
"EUR:0.01",
|
||||
"EUR:0.01",
|
||||
"EUR:0.01",
|
||||
"EUR:0.01",
|
||||
/* with 0.01 withdraw fees (except for 1ct coins),
|
||||
this totals up to exactly EUR:3.97, and with
|
||||
the 0.03 refresh fee, to EUR:4.0*/
|
||||
NULL
|
||||
};
|
||||
static struct Command commands[] =
|
||||
{
|
||||
/* Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config */
|
||||
@ -1273,6 +1884,7 @@ run (void *cls,
|
||||
.expected_response_code = MHD_HTTP_PAYMENT_REQUIRED,
|
||||
.details.withdraw_sign.reserve_reference = "create-reserve-1",
|
||||
.details.withdraw_sign.amount = "EUR:5" },
|
||||
|
||||
/* Try to double-spend the 5 EUR coin with different wire details */
|
||||
{ .oc = OC_DEPOSIT,
|
||||
.label = "deposit-double-1",
|
||||
@ -1303,6 +1915,87 @@ run (void *cls,
|
||||
.details.deposit.contract = "{ \"items\"={ \"name\":\"ice cream\", \"value\":2 } }",
|
||||
.details.deposit.transaction_id = 1 },
|
||||
|
||||
/* ***************** /refresh testing ******************** */
|
||||
|
||||
/* Fill reserve with EUR:5.01, as withdraw fee is 1 ct */
|
||||
{ .oc = OC_ADMIN_ADD_INCOMING,
|
||||
.label = "refresh-create-reserve-1",
|
||||
.expected_response_code = MHD_HTTP_OK,
|
||||
.details.admin_add_incoming.wire = "{ \"type\":\"TEST\", \"bank\":\"source bank\", \"account\":424 }",
|
||||
.details.admin_add_incoming.amount = "EUR:5.01" },
|
||||
/* Withdraw a 5 EUR coin, at fee of 1 ct */
|
||||
{ .oc = OC_WITHDRAW_SIGN,
|
||||
.label = "refresh-withdraw-coin-1",
|
||||
.expected_response_code = MHD_HTTP_OK,
|
||||
.details.withdraw_sign.reserve_reference = "refresh-create-reserve-1",
|
||||
.details.withdraw_sign.amount = "EUR:5" },
|
||||
/* Try to partially spend (deposit) 1 EUR of the 5 EUR coin (in full)
|
||||
(merchant would receive EUR:0.99 due to 1 ct deposit fee) */
|
||||
{ .oc = OC_DEPOSIT,
|
||||
.label = "refresh-deposit-partial",
|
||||
.expected_response_code = MHD_HTTP_OK,
|
||||
.details.deposit.amount = "EUR:1",
|
||||
.details.deposit.coin_ref = "refresh-withdraw-coin-1",
|
||||
.details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }",
|
||||
.details.deposit.contract = "{ \"items\"={ \"name\":\"ice cream\", \"value\"EUR:1 } }",
|
||||
.details.deposit.transaction_id = 42421 },
|
||||
|
||||
/* Melt the rest of the coin's value (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */
|
||||
|
||||
{ .oc = OC_REFRESH_MELT,
|
||||
.label = "refresh-melt-1",
|
||||
.expected_response_code = MHD_HTTP_OK,
|
||||
.details.refresh_melt.melted_coins = melt_coins_1,
|
||||
.details.refresh_melt.fresh_amounts = melt_fresh_amounts_1 },
|
||||
|
||||
#if TEST_REFRESH
|
||||
|
||||
/* Complete (successful) melt operation, and withdraw the coins */
|
||||
{ .oc = OC_REFRESH_REVEAL,
|
||||
.label = "refresh-reveal-1",
|
||||
.expected_response_code = MHD_HTTP_OK,
|
||||
.details.refresh_reveal.melt_ref = "refresh-melt-1" },
|
||||
|
||||
|
||||
/* Test that /refresh/link works */
|
||||
{ .oc = OC_REFRESH_LINK,
|
||||
.label = "refresh-link-1",
|
||||
.expected_response_code = MHD_HTTP_OK,
|
||||
.details.refresh_link.reveal_ref = "refresh-reveal-1" },
|
||||
|
||||
/* Test successfully spending coins from the refresh operation:
|
||||
first EUR:1 */
|
||||
{ .oc = OC_DEPOSIT,
|
||||
.label = "refresh-deposit-refreshed-1",
|
||||
.expected_response_code = MHD_HTTP_OK,
|
||||
.details.deposit.amount = "EUR:1",
|
||||
.details.deposit.coin_ref = "refresh-reveal-1a",
|
||||
.details.deposit.coin_idx = 0,
|
||||
.details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }",
|
||||
.details.deposit.contract = "{ \"items\"={ \"name\":\"ice cream\", \"value\":3 } }",
|
||||
.details.deposit.transaction_id = 2 },
|
||||
/* Test successfully spending coins from the refresh operation:
|
||||
finally EUR:0.1 */
|
||||
{ .oc = OC_DEPOSIT,
|
||||
.label = "refresh-deposit-refreshed-1b",
|
||||
.expected_response_code = MHD_HTTP_OK,
|
||||
.details.deposit.amount = "EUR:0.1",
|
||||
.details.deposit.coin_ref = "refresh-reveal-1b",
|
||||
.details.deposit.coin_idx = 4,
|
||||
.details.deposit.wire_details = "{ \"type\":\"TEST\", \"bank\":\"dest bank\", \"account\":42 }",
|
||||
.details.deposit.contract = "{ \"items\"={ \"name\":\"ice cream\", \"value\":3 } }",
|
||||
.details.deposit.transaction_id = 2 },
|
||||
|
||||
/* Test running a failing melt operation (same operation again must fail) */
|
||||
{ .oc = OC_REFRESH_MELT,
|
||||
.label = "refresh-melt-failing",
|
||||
.expected_response_code = MHD_HTTP_FORBIDDEN,
|
||||
.details.refresh_melt.melted_coins = melt_coins_1,
|
||||
.details.refresh_melt.fresh_amounts = melt_fresh_amounts_1 },
|
||||
|
||||
/* *************** end of /refresh testing ************** */
|
||||
#endif
|
||||
|
||||
{ .oc = OC_END }
|
||||
};
|
||||
|
||||
@ -1359,7 +2052,14 @@ main (int argc,
|
||||
"-d", "test-mint-home",
|
||||
NULL);
|
||||
/* give child time to start and bind against the socket */
|
||||
sleep (2);
|
||||
fprintf (stderr, "Waiting for taler-mint-httpd to be ready");
|
||||
do
|
||||
{
|
||||
fprintf (stderr, ".");
|
||||
sleep (1);
|
||||
}
|
||||
while (0 != system ("wget -q -t 1 http://localhost:8081/agpl -o /dev/null -O /dev/null"));
|
||||
fprintf (stderr, "\n");
|
||||
result = GNUNET_SYSERR;
|
||||
GNUNET_SCHEDULER_run (&run, NULL);
|
||||
GNUNET_OS_process_kill (mintd,
|
||||
|
@ -550,7 +550,9 @@ refresh_accept_melts (struct MHD_Connection *connection,
|
||||
GNUNET_break (0);
|
||||
TMH_plugin->free_coin_transaction_list (TMH_plugin->cls,
|
||||
tl);
|
||||
return TMH_RESPONSE_reply_internal_db_error (connection);
|
||||
return (MHD_YES ==
|
||||
TMH_RESPONSE_reply_internal_db_error (connection))
|
||||
? GNUNET_NO : GNUNET_SYSERR;
|
||||
}
|
||||
/* Refuse to refresh when the coin's value is insufficient
|
||||
for the cost of all transactions. */
|
||||
@ -580,6 +582,7 @@ refresh_accept_melts (struct MHD_Connection *connection,
|
||||
melt.coin_sig = coin_details->melt_sig;
|
||||
melt.session_hash = *session_hash;
|
||||
melt.amount_with_fee = coin_details->melt_amount_with_fee;
|
||||
melt.melt_fee = coin_details->melt_fee;
|
||||
if (GNUNET_OK !=
|
||||
TMH_plugin->insert_refresh_melt (TMH_plugin->cls,
|
||||
session,
|
||||
@ -587,7 +590,9 @@ refresh_accept_melts (struct MHD_Connection *connection,
|
||||
&melt))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
return (MHD_YES ==
|
||||
TMH_RESPONSE_reply_internal_db_error (connection))
|
||||
? GNUNET_NO : GNUNET_SYSERR;
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
@ -623,7 +628,7 @@ TMH_DB_execute_refresh_melt (struct MHD_Connection *connection,
|
||||
unsigned int coin_count,
|
||||
const struct TMH_DB_MeltDetails *coin_melt_details,
|
||||
struct TALER_MINTDB_RefreshCommitCoin *const* commit_coin,
|
||||
struct TALER_MINTDB_RefreshCommitLinkP *const* commit_link)
|
||||
struct TALER_RefreshCommitLinkP *const* commit_link)
|
||||
{
|
||||
struct TMH_KS_StateHandle *key_state;
|
||||
struct TALER_MINTDB_RefreshSession refresh_session;
|
||||
@ -839,11 +844,11 @@ check_commitment (struct MHD_Connection *connection,
|
||||
unsigned int j;
|
||||
struct TALER_LinkSecretP last_shared_secret;
|
||||
int secret_initialized = GNUNET_NO;
|
||||
struct TALER_MINTDB_RefreshCommitLinkP *commit_links;
|
||||
struct TALER_RefreshCommitLinkP *commit_links;
|
||||
struct TALER_MINTDB_RefreshCommitCoin *commit_coins;
|
||||
|
||||
commit_links = GNUNET_malloc (num_oldcoins *
|
||||
sizeof (struct TALER_MINTDB_RefreshCommitLinkP));
|
||||
sizeof (struct TALER_RefreshCommitLinkP));
|
||||
if (GNUNET_OK !=
|
||||
TMH_plugin->get_refresh_commit_links (TMH_plugin->cls,
|
||||
session,
|
||||
|
@ -99,6 +99,12 @@ struct TMH_DB_MeltDetails
|
||||
* to the melt is this value minus the fee for melting the coin.
|
||||
*/
|
||||
struct TALER_Amount melt_amount_with_fee;
|
||||
|
||||
/**
|
||||
* What fee is earned by the mint? Set delayed during
|
||||
* #verify_coin_public_info().
|
||||
*/
|
||||
struct TALER_Amount melt_fee;
|
||||
};
|
||||
|
||||
|
||||
@ -130,7 +136,7 @@ TMH_DB_execute_refresh_melt (struct MHD_Connection *connection,
|
||||
unsigned int coin_count,
|
||||
const struct TMH_DB_MeltDetails *coin_melt_details,
|
||||
struct TALER_MINTDB_RefreshCommitCoin *const* commit_coin,
|
||||
struct TALER_MINTDB_RefreshCommitLinkP *const* commit_link);
|
||||
struct TALER_RefreshCommitLinkP *const* commit_link);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -490,6 +490,7 @@ TMH_PARSE_navigate_json (struct MHD_Connection *connection,
|
||||
fname);
|
||||
if (NULL == root)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
ret = (MHD_YES ==
|
||||
TMH_RESPONSE_reply_json_pack (connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
@ -513,6 +514,7 @@ TMH_PARSE_navigate_json (struct MHD_Connection *connection,
|
||||
fnum);
|
||||
if (NULL == root)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
ret = (MHD_YES ==
|
||||
TMH_RESPONSE_reply_json_pack (connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
@ -535,6 +537,7 @@ TMH_PARSE_navigate_json (struct MHD_Connection *connection,
|
||||
str = json_string_value (root);
|
||||
if (NULL == str)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
ret = (MHD_YES ==
|
||||
TMH_RESPONSE_reply_json_pack (connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
@ -548,6 +551,7 @@ TMH_PARSE_navigate_json (struct MHD_Connection *connection,
|
||||
where, len);
|
||||
if (GNUNET_OK != res)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
ret = (MHD_YES ==
|
||||
TMH_RESPONSE_reply_json_pack (connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
@ -571,6 +575,7 @@ TMH_PARSE_navigate_json (struct MHD_Connection *connection,
|
||||
str = json_string_value (root);
|
||||
if (NULL == str)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
ret = (MHD_YES ==
|
||||
TMH_RESPONSE_reply_internal_error (connection,
|
||||
"json_string_value() failed"))
|
||||
@ -587,6 +592,7 @@ TMH_PARSE_navigate_json (struct MHD_Connection *connection,
|
||||
*len);
|
||||
if (GNUNET_OK != res)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_free (*where);
|
||||
*where = NULL;
|
||||
*len = 0;
|
||||
@ -613,6 +619,7 @@ TMH_PARSE_navigate_json (struct MHD_Connection *connection,
|
||||
( (-1 != typ) &&
|
||||
(json_typeof (root) != typ)) )
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
*r_json = NULL;
|
||||
ret = (MHD_YES ==
|
||||
TMH_RESPONSE_reply_json_pack (connection,
|
||||
@ -637,6 +644,7 @@ TMH_PARSE_navigate_json (struct MHD_Connection *connection,
|
||||
|
||||
if (json_typeof (root) != JSON_INTEGER)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
ret = (MHD_YES ==
|
||||
TMH_RESPONSE_reply_json_pack (connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
@ -666,6 +674,7 @@ TMH_PARSE_navigate_json (struct MHD_Connection *connection,
|
||||
str = json_string_value (root);
|
||||
if (NULL == str)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
ret = (MHD_YES ==
|
||||
TMH_RESPONSE_reply_json_pack (connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
@ -683,6 +692,7 @@ TMH_PARSE_navigate_json (struct MHD_Connection *connection,
|
||||
len);
|
||||
if (GNUNET_OK != res)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_free (buf);
|
||||
ret = (MHD_YES ==
|
||||
TMH_RESPONSE_reply_json_pack (connection,
|
||||
@ -698,6 +708,7 @@ TMH_PARSE_navigate_json (struct MHD_Connection *connection,
|
||||
GNUNET_free (buf);
|
||||
if (NULL == where->rsa_public_key)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
ret = (MHD_YES ==
|
||||
TMH_RESPONSE_reply_json_pack (connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
@ -724,6 +735,7 @@ TMH_PARSE_navigate_json (struct MHD_Connection *connection,
|
||||
str = json_string_value (root);
|
||||
if (NULL == str)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
ret = (MHD_YES ==
|
||||
TMH_RESPONSE_reply_json_pack (connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
@ -741,6 +753,7 @@ TMH_PARSE_navigate_json (struct MHD_Connection *connection,
|
||||
len);
|
||||
if (GNUNET_OK != res)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_free (buf);
|
||||
ret = (MHD_YES ==
|
||||
TMH_RESPONSE_reply_json_pack (connection,
|
||||
@ -756,6 +769,7 @@ TMH_PARSE_navigate_json (struct MHD_Connection *connection,
|
||||
GNUNET_free (buf);
|
||||
if (NULL == where->rsa_signature)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
ret = (MHD_YES ==
|
||||
TMH_RESPONSE_reply_json_pack (connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
@ -777,6 +791,7 @@ TMH_PARSE_navigate_json (struct MHD_Connection *connection,
|
||||
TALER_json_to_amount ((json_t *) root,
|
||||
where))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
if (MHD_YES !=
|
||||
TMH_RESPONSE_reply_json_pack (connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
@ -789,6 +804,7 @@ TMH_PARSE_navigate_json (struct MHD_Connection *connection,
|
||||
if (0 != strcmp (where->currency,
|
||||
TMH_mint_currency_string))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
if (MHD_YES !=
|
||||
TMH_RESPONSE_reply_json_pack (connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
@ -815,6 +831,7 @@ TMH_PARSE_navigate_json (struct MHD_Connection *connection,
|
||||
TALER_json_to_abs ((json_t *) root,
|
||||
where))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
if (MHD_YES !=
|
||||
TMH_RESPONSE_reply_json_pack (connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
|
@ -57,7 +57,7 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
|
||||
const struct TMH_DB_MeltDetails *coin_melt_details,
|
||||
const struct GNUNET_HashCode *session_hash,
|
||||
struct TALER_MINTDB_RefreshCommitCoin *const* commit_coin,
|
||||
struct TALER_MINTDB_RefreshCommitLinkP *const* commit_link)
|
||||
struct TALER_RefreshCommitLinkP *const* commit_link)
|
||||
{
|
||||
unsigned int i;
|
||||
struct TMH_KS_StateHandle *key_state;
|
||||
@ -92,6 +92,7 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
|
||||
&cost,
|
||||
&total_cost)) )
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
TMH_KS_release (key_state);
|
||||
return TMH_RESPONSE_reply_internal_error (connection,
|
||||
"cost calculation failure");
|
||||
@ -115,6 +116,7 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
|
||||
&coin_melt_details->melt_amount_with_fee,
|
||||
&fee_melt))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
TMH_KS_release (key_state);
|
||||
return TMH_RESPONSE_reply_external_error (connection,
|
||||
"Melt contribution below melting fee");
|
||||
@ -124,6 +126,7 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
|
||||
&melt,
|
||||
&total_melt))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
TMH_KS_release (key_state);
|
||||
return TMH_RESPONSE_reply_internal_error (connection,
|
||||
"balance calculation failure");
|
||||
@ -134,6 +137,7 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
|
||||
TALER_amount_cmp (&total_cost,
|
||||
&total_melt))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
/* We require total value of coins being melted and
|
||||
total value of coins being generated to match! */
|
||||
return TMH_RESPONSE_reply_json_pack (connection,
|
||||
@ -185,13 +189,17 @@ get_coin_public_info (struct MHD_Connection *connection,
|
||||
coin_info,
|
||||
spec);
|
||||
if (GNUNET_OK != ret)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return ret;
|
||||
}
|
||||
/* check mint signature on the coin */
|
||||
r_melt_detail->coin_info.denom_sig = sig;
|
||||
r_melt_detail->coin_info.denom_pub = pk;
|
||||
if (GNUNET_OK !=
|
||||
TALER_test_coin_valid (&r_melt_detail->coin_info))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
TMH_PARSE_release_data (spec);
|
||||
r_melt_detail->coin_info.denom_sig.rsa_signature = NULL;
|
||||
r_melt_detail->coin_info.denom_pub.rsa_public_key = NULL;
|
||||
@ -202,21 +210,21 @@ get_coin_public_info (struct MHD_Connection *connection,
|
||||
}
|
||||
r_melt_detail->melt_sig = melt_sig;
|
||||
r_melt_detail->melt_amount_with_fee = amount;
|
||||
TMH_PARSE_release_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
|
||||
* the given @a session_hash 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 session_hash hash over refresh session the coin is melted into
|
||||
* @param melt_detail details about the coin's melting permission (if valid)
|
||||
* @param[in,out] melt_detail details about the coin's melting permission,
|
||||
* the `melt_fee` is updated
|
||||
* @return #GNUNET_YES if coin public info in JSON was valid
|
||||
* #GNUNET_NO JSON was invalid, response was generated
|
||||
* #GNUNET_SYSERR on internal error
|
||||
@ -224,7 +232,7 @@ get_coin_public_info (struct MHD_Connection *connection,
|
||||
static int
|
||||
verify_coin_public_info (struct MHD_Connection *connection,
|
||||
const struct GNUNET_HashCode *session_hash,
|
||||
const struct TMH_DB_MeltDetails *melt_detail)
|
||||
struct TMH_DB_MeltDetails *melt_detail)
|
||||
{
|
||||
struct TALER_RefreshMeltCoinAffirmationPS body;
|
||||
struct TMH_KS_StateHandle *key_state;
|
||||
@ -246,17 +254,20 @@ verify_coin_public_info (struct MHD_Connection *connection,
|
||||
valid for issuing! (#3634) */
|
||||
TALER_amount_ntoh (&fee_refresh,
|
||||
&dki->issue.properties.fee_refresh);
|
||||
melt_detail->melt_fee = fee_refresh;
|
||||
body.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS));
|
||||
body.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT);
|
||||
body.session_hash = *session_hash;
|
||||
|
||||
TALER_amount_hton (&body.amount_with_fee,
|
||||
&melt_detail->melt_amount_with_fee);
|
||||
TALER_amount_hton (&body.melt_fee,
|
||||
&fee_refresh);
|
||||
body.coin_pub = melt_detail->coin_info.coin_pub;
|
||||
if (TALER_amount_cmp (&fee_refresh,
|
||||
&melt_detail->melt_amount_with_fee) < 0)
|
||||
&melt_detail->melt_amount_with_fee) > 0)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
TMH_KS_release (key_state);
|
||||
return (MHD_YES ==
|
||||
TMH_RESPONSE_reply_external_error (connection,
|
||||
@ -271,6 +282,7 @@ verify_coin_public_info (struct MHD_Connection *connection,
|
||||
&melt_detail->melt_sig.eddsa_signature,
|
||||
&melt_detail->coin_info.coin_pub.eddsa_pub))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
if (MHD_YES !=
|
||||
TMH_RESPONSE_reply_signature_invalid (connection,
|
||||
"confirm_sig"))
|
||||
@ -318,7 +330,7 @@ free_commit_coins (struct TALER_MINTDB_RefreshCommitCoin **commit_coin,
|
||||
* @param num_old_coins size of 2nd dimension
|
||||
*/
|
||||
static void
|
||||
free_commit_links (struct TALER_MINTDB_RefreshCommitLinkP **commit_link,
|
||||
free_commit_links (struct TALER_RefreshCommitLinkP **commit_link,
|
||||
unsigned int kappa,
|
||||
unsigned int num_old_coins)
|
||||
{
|
||||
@ -361,7 +373,6 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
|
||||
unsigned int num_newcoins,
|
||||
const json_t *coin_evs,
|
||||
const json_t *link_encs)
|
||||
|
||||
{
|
||||
int res;
|
||||
unsigned int i;
|
||||
@ -373,7 +384,7 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
|
||||
struct GNUNET_HashCode session_hash;
|
||||
struct GNUNET_HashContext *hash_context;
|
||||
struct TALER_MINTDB_RefreshCommitCoin *commit_coin[TALER_CNC_KAPPA];
|
||||
struct TALER_MINTDB_RefreshCommitLinkP *commit_link[TALER_CNC_KAPPA];
|
||||
struct TALER_RefreshCommitLinkP *commit_link[TALER_CNC_KAPPA];
|
||||
|
||||
/* For the signature check, we hash most of the inputs together
|
||||
(except for the signatures on the coins). */
|
||||
@ -407,8 +418,8 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
|
||||
}
|
||||
|
||||
coin_count = json_array_size (melt_coins);
|
||||
coin_melt_details = GNUNET_malloc (coin_count *
|
||||
sizeof (struct TMH_DB_MeltDetails));
|
||||
coin_melt_details = GNUNET_new_array (coin_count,
|
||||
struct TMH_DB_MeltDetails);
|
||||
for (i=0;i<coin_count;i++)
|
||||
{
|
||||
/* decode JSON data on coin to melt */
|
||||
@ -419,6 +430,7 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
|
||||
&coin_melt_details[i]);
|
||||
if (GNUNET_OK != res)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
for (j=0;j<i;j++)
|
||||
{
|
||||
GNUNET_CRYPTO_rsa_public_key_free (coin_melt_details[j].coin_info.denom_pub.rsa_public_key);
|
||||
@ -438,6 +450,7 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
|
||||
&coin_melt_details[j].coin_info.coin_pub,
|
||||
sizeof (struct TALER_CoinSpendPublicKeyP)))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
for (j=0;j<i;j++)
|
||||
{
|
||||
GNUNET_CRYPTO_rsa_public_key_free (coin_melt_details[j].coin_info.denom_pub.rsa_public_key);
|
||||
@ -459,7 +472,6 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
|
||||
GNUNET_CRYPTO_hash_context_read (hash_context,
|
||||
&melt_amount,
|
||||
sizeof (struct TALER_AmountNBO));
|
||||
|
||||
}
|
||||
|
||||
/* parse JSON arrays into 2d binary arrays and hash everything
|
||||
@ -486,6 +498,7 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
|
||||
|
||||
if (GNUNET_OK != res)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_CRYPTO_hash_context_abort (hash_context);
|
||||
free_commit_coins (commit_coin,
|
||||
TALER_CNC_KAPPA,
|
||||
@ -504,6 +517,7 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
|
||||
&link_enc_size);
|
||||
if (GNUNET_OK != res)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_CRYPTO_hash_context_abort (hash_context);
|
||||
free_commit_coins (commit_coin,
|
||||
TALER_CNC_KAPPA,
|
||||
@ -524,10 +538,10 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
|
||||
for (i = 0; i < TALER_CNC_KAPPA; i++)
|
||||
{
|
||||
commit_link[i] = GNUNET_malloc (num_oldcoins *
|
||||
sizeof (struct TALER_MINTDB_RefreshCommitLinkP));
|
||||
sizeof (struct TALER_RefreshCommitLinkP));
|
||||
for (j = 0; j < num_oldcoins; j++)
|
||||
{
|
||||
struct TALER_MINTDB_RefreshCommitLinkP *rcl = &commit_link[i][j];
|
||||
struct TALER_RefreshCommitLinkP *rcl = &commit_link[i][j];
|
||||
|
||||
res = TMH_PARSE_navigate_json (connection,
|
||||
transfer_pubs,
|
||||
@ -539,6 +553,7 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
|
||||
|
||||
if (GNUNET_OK != res)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_break (GNUNET_SYSERR != res);
|
||||
GNUNET_CRYPTO_hash_context_abort (hash_context);
|
||||
free_commit_coins (commit_coin,
|
||||
@ -559,6 +574,7 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
|
||||
|
||||
if (GNUNET_OK != res)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_break (GNUNET_SYSERR != res);
|
||||
GNUNET_CRYPTO_hash_context_abort (hash_context);
|
||||
free_commit_coins (commit_coin,
|
||||
@ -572,7 +588,7 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
|
||||
|
||||
GNUNET_CRYPTO_hash_context_read (hash_context,
|
||||
rcl,
|
||||
sizeof (struct TALER_MINTDB_RefreshCommitLinkP));
|
||||
sizeof (struct TALER_RefreshCommitLinkP));
|
||||
}
|
||||
|
||||
}
|
||||
@ -587,6 +603,7 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
|
||||
&coin_melt_details[i]);
|
||||
if (GNUNET_OK != res)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
res = (GNUNET_NO == res) ? MHD_YES : MHD_NO;
|
||||
goto cleanup;
|
||||
}
|
||||
@ -694,12 +711,14 @@ TMH_REFRESH_handler_refresh_melt (struct TMH_RequestHandler *rh,
|
||||
return TMH_RESPONSE_reply_arg_invalid (connection,
|
||||
"transfer_pubs");
|
||||
}
|
||||
res = TMH_PARSE_navigate_json (connection, coin_evs,
|
||||
res = TMH_PARSE_navigate_json (connection,
|
||||
coin_evs,
|
||||
TMH_PARSE_JNC_INDEX, (int) 0,
|
||||
TMH_PARSE_JNC_RET_DATA,
|
||||
TMH_PARSE_JNC_RET_TYPED_JSON,
|
||||
JSON_ARRAY, &coin_detail);
|
||||
if (GNUNET_OK != res)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
TMH_PARSE_release_data (spec);
|
||||
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
|
||||
}
|
||||
@ -707,10 +726,11 @@ TMH_REFRESH_handler_refresh_melt (struct TMH_RequestHandler *rh,
|
||||
res = TMH_PARSE_navigate_json (connection,
|
||||
transfer_pubs,
|
||||
TMH_PARSE_JNC_INDEX, (int) 0,
|
||||
TMH_PARSE_JNC_RET_DATA,
|
||||
TMH_PARSE_JNC_RET_TYPED_JSON,
|
||||
JSON_ARRAY, &coin_detail);
|
||||
if (GNUNET_OK != res)
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
TMH_PARSE_release_data (spec);
|
||||
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
|
||||
}
|
||||
|
@ -695,7 +695,7 @@ TMH_RESPONSE_reply_withdraw_sign_success (struct MHD_Connection *connection,
|
||||
* @param coin_pub public key of the coin
|
||||
* @param coin_value original value of the coin
|
||||
* @param tl transaction history for the coin
|
||||
* @param requested how much this coin was supposed to contribute
|
||||
* @param requested how much this coin was supposed to contribute, including fee
|
||||
* @param residual remaining value of the coin (after subtracting @a tl)
|
||||
* @return a MHD result code
|
||||
*/
|
||||
@ -713,13 +713,19 @@ TMH_RESPONSE_reply_refresh_melt_insufficient_funds (struct MHD_Connection *conne
|
||||
return TMH_RESPONSE_reply_json_pack (connection,
|
||||
MHD_HTTP_NOT_FOUND,
|
||||
"{s:s, s:o, s:o, s:o, s:o, s:o}",
|
||||
"error", "insufficient funds",
|
||||
"coin-pub", TALER_json_from_data (coin_pub,
|
||||
sizeof (struct TALER_CoinSpendPublicKeyP)),
|
||||
"original-value", TALER_json_from_amount (&coin_value),
|
||||
"residual-value", TALER_json_from_amount (&residual),
|
||||
"requested-value", TALER_json_from_amount (&requested),
|
||||
"history", history);
|
||||
"error",
|
||||
"insufficient funds",
|
||||
"coin_pub",
|
||||
TALER_json_from_data (coin_pub,
|
||||
sizeof (struct TALER_CoinSpendPublicKeyP)),
|
||||
"original_value",
|
||||
TALER_json_from_amount (&coin_value),
|
||||
"residual_value",
|
||||
TALER_json_from_amount (&residual),
|
||||
"requested_value",
|
||||
TALER_json_from_amount (&requested),
|
||||
"history",
|
||||
history);
|
||||
}
|
||||
|
||||
|
||||
@ -894,7 +900,7 @@ TMH_RESPONSE_reply_refresh_reveal_missmatch (struct MHD_Connection *connection,
|
||||
info_link_k = json_array ();
|
||||
for (i=0;i<mc->num_newcoins;i++)
|
||||
{
|
||||
const struct TALER_MINTDB_RefreshCommitLinkP *cl;
|
||||
const struct TALER_RefreshCommitLinkP *cl;
|
||||
json_t *cl_json;
|
||||
|
||||
cl = &mc->commit_links[k][i];
|
||||
|
@ -350,7 +350,7 @@ TMH_RESPONSE_reply_refresh_reveal_missmatch (struct MHD_Connection *connection,
|
||||
|
||||
|
||||
/**
|
||||
* Information for each session a coin was melted into.
|
||||
* @brief Information for each session a coin was melted into.
|
||||
*/
|
||||
struct TMH_RESPONSE_LinkSessionInfo
|
||||
{
|
||||
|
@ -166,7 +166,7 @@ static int
|
||||
postgres_drop_temporary (void *cls,
|
||||
struct TALER_MINTDB_Session *session)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Dropping temporary tables\n");
|
||||
SQLEXEC_ (session->conn,
|
||||
"DROP SCHEMA " TALER_TEMP_SCHEMA_NAME " CASCADE;");
|
||||
@ -176,6 +176,40 @@ postgres_drop_temporary (void *cls,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called by libpq whenever it wants to log something.
|
||||
* We already log whenever we care, so this function does nothing
|
||||
* and merely exists to silence the libpq logging.
|
||||
*
|
||||
* @param arg NULL
|
||||
* @param res information about some libpq event
|
||||
*/
|
||||
static void
|
||||
pq_notice_receiver_cb (void *arg,
|
||||
const PGresult *res)
|
||||
{
|
||||
/* do nothing, intentionally */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called by libpq whenever it wants to log something.
|
||||
* We log those using the Taler logger.
|
||||
*
|
||||
* @param arg NULL
|
||||
* @param message information about some libpq event
|
||||
*/
|
||||
static void
|
||||
pq_notice_processor_cb (void *arg,
|
||||
const char *message)
|
||||
{
|
||||
GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
|
||||
"pq",
|
||||
"%s",
|
||||
message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the necessary tables if they are not present
|
||||
*
|
||||
@ -198,6 +232,12 @@ postgres_create_tables (void *cls,
|
||||
PQfinish (conn);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
PQsetNoticeReceiver (conn,
|
||||
&pq_notice_receiver_cb,
|
||||
NULL);
|
||||
PQsetNoticeProcessor (conn,
|
||||
&pq_notice_processor_cb,
|
||||
NULL);
|
||||
if ( (GNUNET_YES == temporary) &&
|
||||
(GNUNET_SYSERR == set_temporary_schema (conn)))
|
||||
{
|
||||
@ -939,6 +979,12 @@ postgres_get_session (void *cls,
|
||||
GNUNET_break (0);
|
||||
return NULL;
|
||||
}
|
||||
PQsetNoticeReceiver (db_conn,
|
||||
&pq_notice_receiver_cb,
|
||||
NULL);
|
||||
PQsetNoticeProcessor (db_conn,
|
||||
&pq_notice_processor_cb,
|
||||
NULL);
|
||||
if ( (GNUNET_YES == temporary) &&
|
||||
(GNUNET_SYSERR == set_temporary_schema(db_conn)) )
|
||||
{
|
||||
@ -1751,11 +1797,8 @@ postgres_get_reserve_history (void *cls,
|
||||
* @param session database connection
|
||||
* @param deposit deposit to search for
|
||||
* @return #GNUNET_YES if we know this operation,
|
||||
* #GNUNET_NO if this deposit is unknown to us
|
||||
* #GNUNET_SYSERR on DB error or if same coin(pub), merchant(pub) and
|
||||
* transaction ID are already in DB, but for different
|
||||
* other transaction details (contract, wiring details,
|
||||
* amount, etc.)
|
||||
* #GNUNET_NO if this exact deposit is unknown to us
|
||||
* #GNUNET_SYSERR on DB error
|
||||
*/
|
||||
static int
|
||||
postgres_have_deposit (void *cls,
|
||||
@ -1823,13 +1866,12 @@ postgres_have_deposit (void *cls,
|
||||
&deposit2.h_wire,
|
||||
sizeof (struct GNUNET_HashCode))) )
|
||||
{
|
||||
/* Inconsistencies detected! Bug in merchant! (We might want to
|
||||
/* Inconsistencies detected! Does not match! (We might want to
|
||||
expand the API with a 'get_deposit' function to return the
|
||||
original transaction details to be used for an error message
|
||||
in the future!) #3838 */
|
||||
GNUNET_break_op (0);
|
||||
PQclear (result);
|
||||
return GNUNET_SYSERR;
|
||||
return GNUNET_NO;
|
||||
}
|
||||
}
|
||||
PQclear (result);
|
||||
@ -2598,7 +2640,7 @@ postgres_insert_refresh_commit_links (void *cls,
|
||||
const struct GNUNET_HashCode *session_hash,
|
||||
uint16_t cnc_index,
|
||||
uint16_t num_links,
|
||||
const struct TALER_MINTDB_RefreshCommitLinkP *links)
|
||||
const struct TALER_RefreshCommitLinkP *links)
|
||||
{
|
||||
// FIXME: check logic! links is array!
|
||||
struct TALER_PQ_QueryParam params[] = {
|
||||
@ -2651,7 +2693,7 @@ postgres_get_refresh_commit_links (void *cls,
|
||||
const struct GNUNET_HashCode *session_hash,
|
||||
uint16_t cnc_index,
|
||||
uint16_t num_links,
|
||||
struct TALER_MINTDB_RefreshCommitLinkP *links)
|
||||
struct TALER_RefreshCommitLinkP *links)
|
||||
{
|
||||
// FIXME: check logic: was written for a single link!
|
||||
struct TALER_PQ_QueryParam params[] = {
|
||||
@ -2759,7 +2801,7 @@ postgres_get_melt_commitment (void *cls,
|
||||
goto cleanup;
|
||||
mc->commit_links[cnc_index]
|
||||
= GNUNET_malloc (mc->num_oldcoins *
|
||||
sizeof (struct TALER_MINTDB_RefreshCommitLinkP));
|
||||
sizeof (struct TALER_RefreshCommitLinkP));
|
||||
if (GNUNET_OK !=
|
||||
postgres_get_refresh_commit_links (cls,
|
||||
session,
|
||||
|
@ -162,6 +162,34 @@ TALER_transfer_decrypt (const struct TALER_EncryptedLinkSecretP *secret_enc,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Given the coin and the transfer private keys, compute the
|
||||
* transfer secret. (Technically, we only need one of the two
|
||||
* private keys, but the caller currently trivially only has
|
||||
* the two private keys, so we derive one of the public keys
|
||||
* internally to this function.)
|
||||
*
|
||||
* @param coin_priv coin key
|
||||
* @param trans_priv transfer private key
|
||||
* @param[out] ts computed transfer secret
|
||||
*/
|
||||
void
|
||||
TALER_link_derive_transfer_secret (const struct TALER_CoinSpendPrivateKeyP *coin_priv,
|
||||
const struct TALER_TransferPrivateKeyP *trans_priv,
|
||||
struct TALER_TransferSecretP *ts)
|
||||
{
|
||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
|
||||
&coin_pub.eddsa_pub);
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
GNUNET_CRYPTO_ecdh_eddsa (&trans_priv->ecdhe_priv,
|
||||
&coin_pub.eddsa_pub,
|
||||
&ts->key));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Use the @a trans_sec (from ECDHE) to encrypt the @a secret
|
||||
* to obtain the @a secret_enc.
|
||||
|
Loading…
Reference in New Issue
Block a user