aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-03-24 18:27:24 +0100
committerChristian Grothoff <christian@grothoff.org>2015-03-24 18:27:24 +0100
commita3ac2587cfee3c8b6e058d4086eea8f5f297e5af (patch)
tree61e4e8881d2c7d0952a44f75f08582b852789169 /src
parentec05a64e3e6346ea91b79244a0a69b06afd22562 (diff)
parent324bf3f980542cb9f209ee7edc6f142c5c34e5a2 (diff)
Merge branch 'master' of git.taler.net:/var/git/mint
Diffstat (limited to 'src')
-rw-r--r--src/include/taler_amount_lib.h121
-rw-r--r--src/include/taler_crypto_lib.h305
-rw-r--r--src/include/taler_json_lib.h22
-rw-r--r--src/include/taler_mint_service.h22
-rw-r--r--src/include/taler_signatures.h239
-rw-r--r--src/include/taler_util.h26
-rw-r--r--src/lib/mint_api.c85
-rw-r--r--src/mint/Makefile.am25
-rw-r--r--src/mint/key_io.c255
-rw-r--r--src/mint/key_io.h109
-rw-r--r--src/mint/mint_db.h974
-rw-r--r--src/mint/plugin.c118
-rw-r--r--src/mint/plugin.h50
-rw-r--r--src/mint/plugin_mintdb_common.c118
-rw-r--r--src/mint/plugin_mintdb_postgres.c (renamed from src/mint/mint_db.c)1088
-rw-r--r--src/mint/taler-mint-dbinit.c76
-rw-r--r--src/mint/taler-mint-httpd.c16
-rw-r--r--src/mint/taler-mint-httpd.h7
-rw-r--r--src/mint/taler-mint-httpd_db.c881
-rw-r--r--src/mint/taler-mint-httpd_db.h45
-rw-r--r--src/mint/taler-mint-httpd_deposit.c28
-rw-r--r--src/mint/taler-mint-httpd_keys.c74
-rw-r--r--src/mint/taler-mint-httpd_keys.h51
-rw-r--r--src/mint/taler-mint-httpd_keystate.c530
-rw-r--r--src/mint/taler-mint-httpd_keystate.h77
-rw-r--r--src/mint/taler-mint-httpd_parsing.c51
-rw-r--r--src/mint/taler-mint-httpd_parsing.h16
-rw-r--r--src/mint/taler-mint-httpd_refresh.c428
-rw-r--r--src/mint/taler-mint-httpd_responses.c151
-rw-r--r--src/mint/taler-mint-httpd_responses.h10
-rw-r--r--src/mint/taler-mint-httpd_withdraw.c27
-rw-r--r--src/mint/taler-mint-keycheck.c181
-rw-r--r--src/mint/taler-mint-keyup.c861
-rw-r--r--src/mint/taler-mint-reservemod.c204
-rw-r--r--src/mint/taler_mintdb_plugin.h1024
-rw-r--r--src/mint/test_mint_common.c25
-rw-r--r--src/mint/test_mint_db.c254
-rw-r--r--src/mint/test_mint_deposits.c102
-rw-r--r--src/pq/db_pq.c17
-rw-r--r--src/pq/db_pq.h4
-rw-r--r--src/util/Makefile.am3
-rw-r--r--src/util/amount.c492
-rw-r--r--src/util/crypto.c16
-rw-r--r--src/util/json.c65
-rw-r--r--src/util/os_installation.c701
-rw-r--r--src/util/util.c28
46 files changed, 6372 insertions, 3630 deletions
diff --git a/src/include/taler_amount_lib.h b/src/include/taler_amount_lib.h
index 8bea0256c..e64ff4d92 100644
--- a/src/include/taler_amount_lib.h
+++ b/src/include/taler_amount_lib.h
@@ -25,10 +25,27 @@
/**
* Number of characters (plus 1 for 0-termination) we use to
* represent currency names (i.e. EUR, USD, etc.). We use
- * 8 for alignment (!).
+ * 4 for alignment as 3 characters are typical and we need a
+ * 0-terminator. So do not change this.
*/
#define TALER_CURRENCY_LEN 4
+/**
+ * The "fraction" value in a `struct TALER_Amount` represents which
+ * fraction of the "main" value?
+ *
+ * Note that we need sub-cent precision here as transaction fees might
+ * be that low, and as we want to support microdonations.
+ */
+#define TALER_AMOUNT_FRAC_BASE 1000000
+
+/**
+ * How many digits behind the comma are required to represent the
+ * fractional value in human readable decimal format? Must match
+ * lg(#TALER_AMOUNT_FRAC_BASE).
+ */
+#define TALER_AMOUNT_FRAC_LEN 6
+
GNUNET_NETWORK_STRUCT_BEGIN
@@ -41,12 +58,12 @@ struct TALER_AmountNBO
/**
* Value in the main currency, in NBO.
*/
- uint32_t value;
+ uint64_t value GNUNET_PACKED;
/**
* Additinal fractional value, in NBO.
*/
- uint32_t fraction;
+ uint32_t fraction GNUNET_PACKED;
/**
* Type of the currency being represented.
@@ -65,7 +82,7 @@ struct TALER_Amount
/**
* Value (numerator of fraction)
*/
- uint32_t value;
+ uint64_t value;
/**
* Fraction (denominator of fraction)
@@ -73,7 +90,8 @@ struct TALER_Amount
uint32_t fraction;
/**
- * Currency string, left adjusted and padded with zeros.
+ * Currency string, left adjusted and padded with zeros. All zeros
+ * for "invalid" values.
*/
char currency[TALER_CURRENCY_LEN];
};
@@ -93,81 +111,122 @@ TALER_string_to_amount (const char *str,
/**
+ * Get the value of "zero" in a particular currency.
+ *
+ * @param cur currency description
+ * @param denom denomination to write the result to
+ * @return #GNUNET_OK if @a cur is a valid currency specification,
+ * #GNUNET_SYSERR if it is invalid.
+ */
+int
+TALER_amount_get_zero (const char *cur,
+ struct TALER_Amount *denom);
+
+
+/**
* Convert amount from host to network representation.
*
+ * @param res where to store amount in network representation
* @param d amount in host representation
- * @return amount in network representation
*/
-struct TALER_AmountNBO
-TALER_amount_hton (const struct TALER_Amount d);
+void
+TALER_amount_hton (struct TALER_AmountNBO *res,
+ const struct TALER_Amount *d);
/**
* Convert amount from network to host representation.
*
+ * @param res where to store amount in host representation
* @param d amount in network representation
- * @return amount in host representation
*/
-struct TALER_Amount
-TALER_amount_ntoh (const struct TALER_AmountNBO dn);
+void
+TALER_amount_ntoh (struct TALER_Amount *res,
+ const struct TALER_AmountNBO *dn);
/**
- * Compare the value/fraction of two amounts. Does not compare the currency,
- * i.e. comparing amounts with the same value and fraction but different
- * currency would return 0.
+ * Compare the value/fraction of two amounts. Does not compare the currency.
+ * Comparing amounts of different currencies will cause the program to abort().
+ * If unsure, check with #TALER_amount_cmp_currency() first to be sure that
+ * the currencies of the two amounts are identical.
*
* @param a1 first amount
* @param a2 second amount
* @return result of the comparison
*/
int
-TALER_amount_cmp (struct TALER_Amount a1,
- struct TALER_Amount a2);
+TALER_amount_cmp (const struct TALER_Amount *a1,
+ const struct TALER_Amount *a2);
+
+
+/**
+ * Test if @a a1 and @a a2 are the same currency.
+ *
+ * @param a1 amount to test
+ * @param a2 amount to test
+ * @return #GNUNET_YES if @a a1 and @a a2 are the same currency
+ * #GNUNET_NO if the currencies are different
+ * #GNUNET_SYSERR if either amount is invalid
+ */
+int
+TALER_amount_cmp_currency (const struct TALER_Amount *a1,
+ const struct TALER_Amount *a2);
/**
* Perform saturating subtraction of amounts.
*
+ * @param diff where to store (@a a1 - @a a2), or invalid if @a a2 > @a a1
* @param a1 amount to subtract from
* @param a2 amount to subtract
- * @return (a1-a2) or 0 if a2>=a1
+ * @return #GNUNET_OK if the subtraction worked,
+ * #GNUNET_NO if @a a1 = @a a2
+ * #GNUNET_SYSERR if @a a2 > @a a1 or currencies are incompatible;
+ * @a diff is set to invalid
*/
-struct TALER_Amount
-TALER_amount_subtract (struct TALER_Amount a1,
- struct TALER_Amount a2);
+int
+TALER_amount_subtract (struct TALER_Amount *diff,
+ const struct TALER_Amount *a1,
+ const struct TALER_Amount *a2);
/**
- * Perform saturating addition of amounts
+ * Perform addition of amounts.
*
+ * @param sum where to store @a a1 + @a a2, set to "invalid" on overflow
* @param a1 first amount to add
* @param a2 second amount to add
- * @return sum of a1 and a2
+ * @return #GNUNET_OK if the addition worked,
+ * #GNUNET_SYSERR on overflow
*/
-struct TALER_Amount
-TALER_amount_add (struct TALER_Amount a1,
- struct TALER_Amount a2);
+int
+TALER_amount_add (struct TALER_Amount *sum,
+ const struct TALER_Amount *a1,
+ const struct TALER_Amount *a2);
/**
* Normalize the given amount.
*
- * @param amout amount to normalize
- * @return normalized amount
+ * @param amount amount to normalize
+ * @return #GNUNET_OK if normalization worked
+ * #GNUNET_NO if value was already normalized
+ * #GNUNET_SYSERR if value was invalid or could not be normalized
*/
-struct TALER_Amount
-TALER_amount_normalize (struct TALER_Amount amount);
+int
+TALER_amount_normalize (struct TALER_Amount *amount);
/**
* Convert amount to string.
*
* @param amount amount to convert to string
- * @return freshly allocated string representation
+ * @return freshly allocated string representation,
+ * NULL if the @a amount was invalid
*/
char *
-TALER_amount_to_string (struct TALER_Amount amount);
+TALER_amount_to_string (const struct TALER_Amount *amount);
#endif
diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h
index db663612c..3156e63ed 100644
--- a/src/include/taler_crypto_lib.h
+++ b/src/include/taler_crypto_lib.h
@@ -27,6 +27,263 @@
/* ****************** Coin crypto primitives ************* */
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Type of public keys for Taler reserves.
+ */
+struct TALER_ReservePublicKey
+{
+ /**
+ * Taler uses EdDSA for reserves.
+ */
+ struct GNUNET_CRYPTO_EddsaPublicKey eddsa_pub;
+};
+
+
+/**
+ * Type of private keys for Taler reserves.
+ */
+struct TALER_ReservePrivateKey
+{
+ /**
+ * Taler uses EdDSA for reserves.
+ */
+ struct GNUNET_CRYPTO_EddsaPrivateKey eddsa_priv;
+};
+
+
+/**
+ * Type of signatures used with Taler reserves.
+ */
+struct TALER_ReserveSignature
+{
+ /**
+ * Taler uses EdDSA for reserves.
+ */
+ struct GNUNET_CRYPTO_EddsaSignature eddsa_signature;
+};
+
+
+/**
+ * Type of public keys to for merchant authorizations.
+ * Merchants can issue refunds using the corresponding
+ * private key.
+ */
+struct TALER_MerchantPublicKey
+{
+ /**
+ * Taler uses EdDSA for merchants.
+ */
+ struct GNUNET_CRYPTO_EddsaPublicKey eddsa_pub;
+};
+
+
+/**
+ * Type of private keys for merchant authorizations.
+ * Merchants can issue refunds using the corresponding
+ * private key.
+ */
+struct TALER_MerchantPrivateKey
+{
+ /**
+ * Taler uses EdDSA for merchants.
+ */
+ struct GNUNET_CRYPTO_EddsaPrivateKey eddsa_priv;
+};
+
+
+/**
+ * Type of transfer public keys used during refresh
+ * operations.
+ */
+struct TALER_TransferPublicKey
+{
+ /**
+ * Taler uses ECDSA for transfer keys.
+ * FIXME: should this not be ECDHE?
+ */
+ struct GNUNET_CRYPTO_EcdsaPublicKey ecdsa_pub;
+};
+
+
+/**
+ * Type of transfer public keys used during refresh
+ * operations.
+ */
+struct TALER_TransferPrivateKey
+{
+ /**
+ * Taler uses ECDSA for melting session keys.
+ * FIXME: should this not be ECDHE?
+ */
+ struct GNUNET_CRYPTO_EcdsaPrivateKey ecdsa_priv;
+};
+
+
+/**
+ * Type of online public keys used by the mint to sign
+ * messages.
+ */
+struct TALER_MintPublicKey
+{
+ /**
+ * Taler uses EdDSA for online mint message signing.
+ */
+ struct GNUNET_CRYPTO_EddsaPublicKey eddsa_pub;
+};
+
+
+/**
+ * Type of online public keys used by the mint to
+ * sign messages.
+ */
+struct TALER_MintPrivateKey
+{
+ /**
+ * Taler uses EdDSA for online signatures sessions.
+ */
+ struct GNUNET_CRYPTO_EddsaPrivateKey eddsa_priv;
+};
+
+
+/**
+ * Type of signatures used by the mint to sign messages online.
+ */
+struct TALER_MintSignature
+{
+ /**
+ * Taler uses EdDSA for online signatures sessions.
+ */
+ struct GNUNET_CRYPTO_EddsaSignature eddsa_signature;
+};
+
+
+/**
+ * Type of the offline master public key used by the mint.
+ */
+struct TALER_MasterPublicKey
+{
+ /**
+ * Taler uses EdDSA for the long-term offline master key.
+ */
+ struct GNUNET_CRYPTO_EddsaPublicKey eddsa_pub;
+};
+
+
+/**
+ * Type of the offline master public keys used by the mint.
+ */
+struct TALER_MasterPrivateKey
+{
+ /**
+ * Taler uses EdDSA for the long-term offline master key.
+ */
+ struct GNUNET_CRYPTO_EddsaPrivateKey eddsa_priv;
+};
+
+
+/**
+ * Type of signatures by the offline master public key used by the mint.
+ */
+struct TALER_MasterSignature
+{
+ /**
+ * Taler uses EdDSA for the long-term offline master key.
+ */
+ struct GNUNET_CRYPTO_EddsaSignature eddsa_signature;
+};
+
+
+
+/**
+ * Type of public keys for Taler coins.
+ */
+struct TALER_CoinSpendPublicKey
+{
+ /**
+ * Taler uses ECDSA for coins.
+ */
+ struct GNUNET_CRYPTO_EcdsaPublicKey ecdsa_pub;
+};
+
+
+/**
+ * Type of private keys for Taler coins.
+ */
+struct TALER_CoinSpendPrivateKey
+{
+ /**
+ * Taler uses ECDSA for coins.
+ */
+ struct GNUNET_CRYPTO_EcdsaPrivateKey ecdsa_priv;
+};
+
+
+/**
+ * Type of signatures made with Taler coins.
+ */
+struct TALER_CoinSpendSignature
+{
+ /**
+ * Taler uses ECDSA for coins.
+ */
+ struct GNUNET_CRYPTO_EcdsaSignature ecdsa_signature;
+};
+
+
+GNUNET_NETWORK_STRUCT_END
+
+
+
+/**
+ * Type of blinding keys for Taler.
+ */
+struct TALER_DenominationBlindingKey
+{
+ /**
+ * Taler uses RSA for blinding.
+ */
+ struct GNUNET_CRYPTO_rsa_BlindingKey *rsa_blinding_key;
+};
+
+
+/**
+ * Type of (unblinded) coin signatures for Taler.
+ */
+struct TALER_DenominationSignature
+{
+ /**
+ * Taler uses RSA for blinding.
+ */
+ struct GNUNET_CRYPTO_rsa_Signature *rsa_signature;
+};
+
+
+/**
+ * Type of public signing keys for verifying blindly signed coins.
+ */
+struct TALER_DenominationPublicKey
+{
+ /**
+ * Taler uses RSA for signing coins.
+ */
+ struct GNUNET_CRYPTO_rsa_PublicKey *rsa_public_key;
+};
+
+
+/**
+ * Type of private signing keys for blind signing of coins.
+ */
+struct TALER_DenominationPrivateKey
+{
+ /**
+ * Taler uses RSA for signing coins.
+ */
+ struct GNUNET_CRYPTO_rsa_PrivateKey *rsa_private_key;
+};
+
+
/**
* Public information about a coin (including the public key
* of the coin, the denomination key and the signature with
@@ -37,19 +294,19 @@ struct TALER_CoinPublicInfo
/**
* The coin's public key.
*/
- struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub;
+ struct TALER_CoinSpendPublicKey coin_pub;
/**
* Public key representing the denomination of the coin
* that is being deposited.
*/
- struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub;
+ struct TALER_DenominationPublicKey denom_pub;
/**
* (Unblinded) signature over @e coin_pub with @e denom_pub,
* which demonstrates that the coin is valid.
*/
- struct GNUNET_CRYPTO_rsa_Signature *denom_sig;
+ struct TALER_DenominationSignature denom_sig;
};
@@ -68,6 +325,9 @@ TALER_test_coin_valid (const struct TALER_CoinPublicInfo *coin_public_info);
/* ****************** Refresh crypto primitives ************* */
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
/**
* Secret used to decrypt the key to decrypt link secrets.
*/
@@ -107,45 +367,48 @@ struct TALER_EncryptedLinkSecret
/**
- * Representation of an encrypted refresh link.
+ * Representation of an refresh link in cleartext.
*/
-struct TALER_RefreshLinkEncrypted
+struct TALER_RefreshLinkDecrypted
{
/**
- * Encrypted blinding key with @e blinding_key_enc_size bytes,
- * must be allocated at the end of this struct.
- */
- const char *blinding_key_enc;
-
- /**
- * Number of bytes in @e blinding_key_enc.
+ * Private key of the coin.
*/
- size_t blinding_key_enc_size;
+ struct TALER_CoinSpendPrivateKey coin_priv;
/**
- * Encrypted private key of the coin.
+ * Blinding key.
*/
- char coin_priv_enc[sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)];
+ struct TALER_DenominationBlindingKey blinding_key;
};
+GNUNET_NETWORK_STRUCT_END
+
+
/**
- * Representation of an refresh link in cleartext.
+ * Representation of an encrypted refresh link.
*/
-struct TALER_RefreshLinkDecrypted
+struct TALER_RefreshLinkEncrypted
{
/**
- * Private key of the coin.
+ * Encrypted blinding key with @e blinding_key_enc_size bytes,
+ * must be allocated at the end of this struct.
+ */
+ const char *blinding_key_enc;
+
+ /**
+ * Number of bytes in @e blinding_key_enc.
*/
- struct GNUNET_CRYPTO_EcdsaPrivateKey coin_priv;
+ size_t blinding_key_enc_size;
/**
- * Blinding key with @e blinding_key_enc_size bytes.
+ * Encrypted private key of the coin.
*/
- struct GNUNET_CRYPTO_rsa_BlindingKey *blinding_key;
+ char coin_priv_enc[sizeof (struct TALER_CoinSpendPrivateKey)];
};
diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h
index ffa440d56..c5515966f 100644
--- a/src/include/taler_json_lib.h
+++ b/src/include/taler_json_lib.h
@@ -39,7 +39,7 @@
* @return a json object describing the amount
*/
json_t *
-TALER_JSON_from_amount (struct TALER_Amount amount);
+TALER_JSON_from_amount (const struct TALER_Amount *amount);
/**
@@ -77,6 +77,26 @@ TALER_JSON_from_ecdsa_sig (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpo
/**
+ * Convert RSA public key to JSON.
+ *
+ * @param pk public key to convert
+ * @return corresponding JSON encoding
+ */
+json_t *
+TALER_JSON_from_rsa_public_key (struct GNUNET_CRYPTO_rsa_PublicKey *pk);
+
+
+/**
+ * Convert RSA signature to JSON.
+ *
+ * @param sig signature to convert
+ * @return corresponding JSON encoding
+ */
+json_t *
+TALER_JSON_from_rsa_signature (struct GNUNET_CRYPTO_rsa_Signature *sig);
+
+
+/**
* Convert binary data to a JSON string
* with the base32crockford encoding.
*
diff --git a/src/include/taler_mint_service.h b/src/include/taler_mint_service.h
index f300a5cfb..30aaad38e 100644
--- a/src/include/taler_mint_service.h
+++ b/src/include/taler_mint_service.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2014, 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 Affero General Public License as published by the Free Software
@@ -42,7 +42,7 @@ struct TALER_MINT_SigningPublicKey
/**
* The signing public key
*/
- struct GNUNET_CRYPTO_EddsaPublicKey key;
+ struct TALER_MintPublicKey key;
/**
* Validity start time
@@ -64,7 +64,7 @@ struct TALER_MINT_DenomPublicKey
/**
* The public key
*/
- struct GNUNET_CRYPTO_rsa_PublicKey *key;
+ struct TALER_DenominationPublicKey key;
/**
* Timestamp indicating when the denomination key becomes valid
@@ -132,7 +132,7 @@ TALER_MINT_cleanup (struct TALER_MINT_Context *ctx);
* @param hostname the hostname of the mint
* @param port the point where the mint's HTTP service is running. If port is
* given as 0, ports 80 or 443 are chosen depending on @a url.
- * @param mint_key the public key of the mint. This is used to verify the
+ * @param master_key the public master key of the mint. This is used to verify the
* responses of the mint.
* @return the mint handle; NULL upon error
*/
@@ -140,7 +140,7 @@ struct TALER_MINT_Handle *
TALER_MINT_connect (struct TALER_MINT_Context *ctx,
const char *hostname,
uint16_t port,
- struct GNUNET_CRYPTO_EddsaPublicKey *mint_key);
+ const struct TALER_MasterPublicKey *master_key);
/**
* Disconnect from the mint
@@ -282,15 +282,15 @@ struct TALER_MINT_DepositHandle *
TALER_MINT_deposit_submit_json_ (struct TALER_MINT_Handle *mint,
TALER_MINT_DepositResultCallback *cb,
void *cls,
- struct GNUNET_CRYPTO_EddsaPublicKey *coin_pub,
- struct TALER_BLIND_SigningPublicKey *denom_pub,
+ const struct TALER_CoinPublicKey *coin_pub,
+ const struct TALER_BLIND_SigningPublicKey *denom_pub,
struct TALER_BLIND_Signature *ubsig,
uint64_t transaction_id,
struct TALER_Amount *amount,
- struct GNUNET_CRYPTO_EddsaPublicKey *merchant_pub,
- struct GNUNET_HashCode *h_contract,
- struct GNUNET_HashCode *h_wire,
- struct GNUNET_CRYPTO_EddsaSignature *csig,
+ const struct TALER_MerchantPublicKey *merchant_pub,
+ const struct GNUNET_HashCode *h_contract,
+ const struct GNUNET_HashCode *h_wire,
+ const struct TALER_CoinSignature *csig,
json_t *wire_obj);
#endif
diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h
index b1b578236..007a309f3 100644
--- a/src/include/taler_signatures.h
+++ b/src/include/taler_signatures.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2014, 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
@@ -28,10 +28,20 @@
#ifndef TALER_SIGNATURES_H
#define TALER_SIGNATURES_H
-#include <gnunet/gnunet_util_lib.h>
#include "taler_util.h"
/**
+ * Cut-and-choose size for refreshing. Client looses the gamble (of
+ * unaccountable transfers) with probability 1/KAPPA. Refresh cost
+ * increases linearly with KAPPA, and 3 is sufficient up to a
+ * income/sales tax of 66% of total transaction value. As there is
+ * no good reason to change this security parameter, we declare it
+ * fixed and part of the protocol.
+ */
+#define KAPPA 3
+
+
+/**
* Purpose for signing public keys signed
* by the mint master key.
*/
@@ -62,28 +72,21 @@
#define TALER_SIGNATURE_REFRESH_MELT_COIN 5
/**
- * Signature where the refresh session confirms
- * the commits.
- */
-#define TALER_SIGNATURE_REFRESH_MELT_SESSION 6
-
-/**
* Signature where the mint (current signing key)
* confirms the no-reveal index for cut-and-choose and
* the validity of the melted coins.
*/
-#define TALER_SIGNATURE_REFRESH_MELT_RESPONSE 7
+#define TALER_SIGNATURE_REFRESH_MELT_RESPONSE 6
/**
- * Signature where coins confirm that they want
- * to be melted into a certain session.
+ * Signature where the Mint confirms a deposit request.
*/
-#define TALER_SIGNATURE_REFRESH_MELT_CONFIRM 9
+#define TALER_SIGNATURE_MINT_DEPOSIT 7
/**
- * Signature where the Mint confirms a deposit request.
+ * Signature where the Mint confirms the full /keys response set.
*/
-#define TALER_SIGNATURE_MINT_DEPOSIT 10
+#define TALER_SIGNATURE_KEYS_SET 8
/***********************/
@@ -129,7 +132,16 @@ struct TALER_WithdrawRequest
* Reserve public key (which reserve to withdraw from). This is
* the public key which must match the signature.
*/
- struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
+ struct TALER_ReservePublicKey reserve_pub;
+
+ /**
+ * Value of the coin being minted (matching the denomination key)
+ * plus the transaction fee. We include this in what is being
+ * signed so that we can verify a reserve's remaining total balance
+ * without needing to access the respective denomination key
+ * information each time.
+ */
+ struct TALER_AmountNBO amount_with_fee;
/**
* Hash of the denomination public key for the coin that is withdrawn.
@@ -171,14 +183,16 @@ struct TALER_DepositRequest
uint64_t transaction_id GNUNET_PACKED;
/**
- * Amount to be deposited.
+ * Amount to be deposited, including fee.
*/
- struct TALER_AmountNBO amount;
+ struct TALER_AmountNBO amount_with_fee;
+ /* FIXME: we should probably also include the value of
+ the depositing fee here as well! */
/**
* The coin's public key.
*/
- struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub;
+ struct TALER_CoinSpendPublicKey coin_pub;
};
@@ -211,19 +225,22 @@ struct TALER_DepositConfirmation
uint64_t transaction_id GNUNET_PACKED;
/**
- * Amount to be deposited.
+ * Amount to be deposited, including fee.
*/
- struct TALER_AmountNBO amount;
+ struct TALER_AmountNBO amount_with_fee;
+
+ /* FIXME: we should probably also include the value of
+ the depositing fee here as well! */
/**
* The coin's public key.
*/
- struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub;
+ struct TALER_CoinSpendPublicKey coin_pub;
/**
* The Merchant's public key.
*/
- struct GNUNET_CRYPTO_EddsaPublicKey merchant;
+ struct TALER_MerchantPublicKey merchant;
};
@@ -240,51 +257,27 @@ struct RefreshMeltCoinSignature
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/**
- * Which melting operation should the coin become a part of.
- */
- struct GNUNET_HashCode melt_hash;
-
- /**
- * How much of the value of the coin should be melted?
- * This amount includes the fees, so the final amount contributed
- * to the melt is this value minus the fee for melting the coin.
- */
- struct TALER_AmountNBO amount;
-
- /**
- * The coin's public key.
- */
- struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub;
-};
-
-
-/**
- * Message signed by a coin to indicate that the coin should
- * be melted.
- */
-struct RefreshMeltSessionSignature
-{
- /**
- * Purpose is #TALER_SIGNATURE_REFRESH_MELT_SESSION
+ * Which melting session should the coin become a part of.
*/
- struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct GNUNET_HashCode session_hash;
/**
- * Which melting operation should the coin become a part of.
+ * How much of the value of the coin should be melted? This amount
+ * includes the fees, so the final amount contributed to the melt is
+ * this value minus the fee for melting the coin. We include the
+ * fee in what is being signed so that we can verify a reserve's
+ * remaining total balance without needing to access the respective
+ * denomination key information each time.
*/
- struct GNUNET_HashCode melt_hash;
+ struct TALER_AmountNBO amount_with_fee;
- /**
- * Public key of the refresh session for which
- * @e melt_client_signature must be a valid signature.
- */
- struct GNUNET_CRYPTO_EddsaPublicKey session_key;
+ /* FIXME: we should probably also include the value of
+ the melting fee here as well! */
/**
- * What is the total value of the coins created during the
- * refresh, excluding fees?
+ * The coin's public key.
*/
- struct TALER_AmountNBO amount;
+ struct TALER_CoinSpendPublicKey coin_pub;
};
@@ -314,57 +307,147 @@ struct RefreshMeltResponseSignatureBody
/**
- * Message signed by the client requesting the final
- * result of the melting operation.
+ * Information about a signing key of the mint. Signing keys are used
+ * to sign mint messages other than coins, i.e. to confirm that a
+ * deposit was successful or that a refresh was accepted.
*/
-struct RefreshMeltConfirmSignRequestBody
+struct TALER_MINT_SignKeyIssue
{
/**
- * Purpose is #TALER_SIGNATURE_REFRESH_MELT_CONFIRM.
+ * Signature over the signing key (by the master key of the mint).
+ */
+ struct TALER_MasterSignature signature;
+
+ /**
+ * Purpose is #TALER_SIGNATURE_MASTER_SIGNKEY.
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/**
- * FIXME.
+ * Master public key of the mint corresponding to @e signature.
+ * This is the long-term offline master key of the mint.
+ */
+ struct TALER_MasterPublicKey master_pub;
+
+ /**
+ * When does this signing key begin to be valid?
*/
- struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
+ struct GNUNET_TIME_AbsoluteNBO start;
+
+ /**
+ * When does this signing key expire? Note: This is
+ * currently when the Mint will definitively stop using it.
+ * This does not mean that all signatures with tkey key are
+ * afterwards invalid.
+ */
+ struct GNUNET_TIME_AbsoluteNBO expire;
+
+ /**
+ * The public online signing key that the mint will use
+ * between @e start and @e expire.
+ */
+ struct TALER_MintPublicKey signkey_pub;
};
/**
- * FIXME
+ * Signature made by the mint over the full set of keys, used
+ * to detect cheating mints that give out different sets to
+ * different users.
*/
-struct TALER_MINT_SignKeyIssue
+struct TALER_MINT_KeySetSignature
{
- struct GNUNET_CRYPTO_EddsaSignature signature;
+
+ /**
+ * Purpose is #TALER_SIGNATURE_KEYS_SET
+ */
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_CRYPTO_EddsaPublicKey master_pub;
- struct GNUNET_TIME_AbsoluteNBO start;
- struct GNUNET_TIME_AbsoluteNBO expire;
- struct GNUNET_CRYPTO_EddsaPublicKey signkey_pub;
+
+ /**
+ * Time of the key set issue.
+ */
+ struct GNUNET_TIME_AbsoluteNBO list_issue_date;
+
+ /**
+ * Hash over the "inner" JSON with the key set.
+ */
+ struct GNUNET_HashCode hc;
};
/**
- * FIXME
+ * Information about a denomination key. Denomination keys
+ * are used to sign coins of a certain value into existence.
*/
struct TALER_MINT_DenomKeyIssue
{
- struct GNUNET_CRYPTO_EddsaSignature signature;
+ /**
+ * Signature over this struct to affirm the validity
+ * of the key.
+ */
+ struct TALER_MasterSignature signature;
+
+ /**
+ * Purpose is #TALER_SIGNATURE_MASTER_DENOM.
+ */
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
- struct GNUNET_CRYPTO_EddsaPublicKey master;
+
+ /**
+ * The long-term offline master key of the mint that was
+ * used to create @e signature.
+ */
+ struct TALER_MasterPublicKey master;
+
+ /**
+ * Start time of the validity period for this key.
+ */
struct GNUNET_TIME_AbsoluteNBO start;
+
+ /**
+ * The mint will sign fresh coins between @e start and
+ * this time.
+ */
struct GNUNET_TIME_AbsoluteNBO expire_withdraw;
+
+ /**
+ * Coins signed with the denomination key must be spent or refreshed
+ * between @e start and this expiration time. After this time, the
+ * mint will refuse transactions involving this key as it will
+ * "drop" the table with double-spending information (shortly after)
+ * this time. Note that wallets should refresh coins significantly
+ * before this time to be on the safe side.
+ */
struct GNUNET_TIME_AbsoluteNBO expire_spend;
- // FIXME: does not work like this:
- struct GNUNET_CRYPTO_rsa_PublicKey * denom_pub;
+
+ /**
+ * The value of the coins signed with this denomination key.
+ */
struct TALER_AmountNBO value;
+
+ /**
+ * The fee the mint charges when a coin of this type is withdrawn.
+ * (can be zero).
+ */
struct TALER_AmountNBO fee_withdraw;
+
+ /**
+ * The fee the mint charges when a coin of this type is deposited.
+ * (can be zero).
+ */
struct TALER_AmountNBO fee_deposit;
+
+ /**
+ * The fee the mint charges when a coin of this type is refreshed.
+ * (can be zero).
+ */
struct TALER_AmountNBO fee_refresh;
-};
+ /**
+ * Hash code of the denomination public key.
+ */
+ struct GNUNET_HashCode denom_hash;
+};
GNUNET_NETWORK_STRUCT_END
diff --git a/src/include/taler_util.h b/src/include/taler_util.h
index 74feb037a..e46583989 100644
--- a/src/include/taler_util.h
+++ b/src/include/taler_util.h
@@ -84,5 +84,31 @@ struct GNUNET_CONFIGURATION_Handle *
TALER_config_load (const char *base_dir);
+/**
+ * Obtain denomination amount from configuration file.
+ *
+ * @param section section of the configuration to access
+ * @param option option of the configuration to access
+ * @param denom[OUT] set to the amount found in configuration
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+int
+TALER_config_get_denom (struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *section,
+ const char *option,
+ struct TALER_Amount *denom);
+
+
+/**
+ * Get the path to a specific Taler installation directory or, with
+ * #GNUNET_OS_IPK_SELF_PREFIX, the current running apps installation
+ * directory.
+ *
+ * @param dirkind what kind of directory is desired?
+ * @return a pointer to the dir path (to be freed by the caller)
+ */
+char *
+TALER_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind);
+
#endif
diff --git a/src/lib/mint_api.c b/src/lib/mint_api.c
index 3edb722bf..305fc95d9 100644
--- a/src/lib/mint_api.c
+++ b/src/lib/mint_api.c
@@ -179,9 +179,11 @@ struct TALER_MINT_KeysGetHandle
char *url;
TALER_MINT_KeysGetCallback cb;
- void *cls;
+
+ void *cb_cls;
TALER_MINT_ContinuationCallback cont_cb;
+
void *cont_cls;
};
@@ -202,7 +204,8 @@ struct TALER_MINT_DepositHandle
char *url;
TALER_MINT_DepositResultCallback cb;
- void *cls;
+
+ void *cb_cls;
char *json_enc;
@@ -219,7 +222,8 @@ struct TALER_MINT_DepositHandle
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
*/
static int
-parse_timestamp (struct GNUNET_TIME_Absolute *abs, const char *tstamp_enc)
+parse_timestamp (struct GNUNET_TIME_Absolute *abs,
+ const char *tstamp_enc)
{
unsigned long tstamp;
@@ -242,7 +246,7 @@ parse_timestamp (struct GNUNET_TIME_Absolute *abs, const char *tstamp_enc)
static int
parse_json_signkey (struct TALER_MINT_SigningPublicKey **_sign_key,
json_t *sign_key_obj,
- struct GNUNET_CRYPTO_EddsaPublicKey *master_key)
+ struct TALER_MasterPublicKey *master_key)
{
json_t *valid_from_obj;
json_t *valid_until_obj;
@@ -281,7 +285,7 @@ parse_json_signkey (struct TALER_MINT_SigningPublicKey **_sign_key,
EXITIF (GNUNET_SYSERR ==
GNUNET_CRYPTO_eddsa_public_key_from_string (key_enc,
52,
- &sign_key_issue.signkey_pub));
+ &sign_key_issue.signkey_pub.eddsa_pub));
sign_key_issue.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNKEY);
sign_key_issue.purpose.size =
htonl (sizeof (sign_key_issue)
@@ -293,7 +297,7 @@ parse_json_signkey (struct TALER_MINT_SigningPublicKey **_sign_key,
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SIGNKEY,
&sign_key_issue.purpose,
&sig,
- master_key));
+ &master_key->eddsa_pub));
sign_key = GNUNET_new (struct TALER_MINT_SigningPublicKey);
sign_key->valid_from = valid_from;
sign_key->valid_until = valid_until;
@@ -332,10 +336,12 @@ parse_json_amount (json_t *amount_obj, struct TALER_Amount *amt)
return GNUNET_SYSERR;
}
+
+/* FIXME: avoid useless ** for _denom_key! */
static int
parse_json_denomkey (struct TALER_MINT_DenomPublicKey **_denom_key,
json_t *denom_key_obj,
- struct GNUNET_CRYPTO_EddsaPublicKey *master_key)
+ struct TALER_MasterPublicKey *master_key)
{
json_t *obj;
const char *sig_enc;
@@ -354,6 +360,7 @@ parse_json_denomkey (struct TALER_MINT_DenomPublicKey **_denom_key,
struct TALER_Amount fee_deposit;
struct TALER_Amount fee_refresh;
struct TALER_MINT_DenomKeyIssue denom_key_issue;
+ struct GNUNET_CRYPTO_rsa_PublicKey *pk;
struct GNUNET_CRYPTO_EddsaSignature sig;
EXITIF (JSON_OBJECT != json_typeof (denom_key_obj));
@@ -387,10 +394,12 @@ parse_json_denomkey (struct TALER_MINT_DenomPublicKey **_denom_key,
GNUNET_STRINGS_string_to_data (key_enc, strlen (key_enc),
buf,
buf_size));
- denom_key_issue.denom_pub = GNUNET_CRYPTO_rsa_public_key_decode (buf, buf_size);
+ pk = GNUNET_CRYPTO_rsa_public_key_decode (buf, buf_size);
GNUNET_free (buf);
- EXITIF (NULL == denom_key_issue.denom_pub);
+ EXITIF (NULL == pk);
+ GNUNET_CRYPTO_rsa_public_key_hash (pk,
+ &denom_key_issue.denom_hash);
EXITIF (NULL == (obj = json_object_get (denom_key_obj, "value")));
EXITIF (GNUNET_SYSERR == parse_json_amount (obj, &value));
EXITIF (NULL == (obj = json_object_get (denom_key_obj, "fee_withdraw")));
@@ -407,17 +416,21 @@ parse_json_denomkey (struct TALER_MINT_DenomPublicKey **_denom_key,
denom_key_issue.start = GNUNET_TIME_absolute_hton (valid_from);
denom_key_issue.expire_withdraw = GNUNET_TIME_absolute_hton (withdraw_valid_until);
denom_key_issue.expire_spend = GNUNET_TIME_absolute_hton (deposit_valid_until);
- denom_key_issue.value = TALER_amount_hton (value);
- denom_key_issue.fee_withdraw = TALER_amount_hton (fee_withdraw);
- denom_key_issue.fee_deposit = TALER_amount_hton (fee_deposit);
- denom_key_issue.fee_refresh = TALER_amount_hton (fee_refresh);
+ TALER_amount_hton (&denom_key_issue.value,
+ &value);
+ TALER_amount_hton (&denom_key_issue.fee_withdraw,
+ &fee_withdraw);
+ TALER_amount_hton (&denom_key_issue.fee_deposit,
+ &fee_deposit);
+ TALER_amount_hton (&denom_key_issue.fee_refresh,
+ &fee_refresh);
EXITIF (GNUNET_SYSERR ==
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOM,
&denom_key_issue.purpose,
&sig,
- master_key));
+ &master_key->eddsa_pub));
denom_key = GNUNET_new (struct TALER_MINT_DenomPublicKey);
- denom_key->key = denom_key_issue.denom_pub;
+ denom_key->key.rsa_public_key = pk;
denom_key->valid_from = valid_from;
denom_key->withdraw_valid_until = withdraw_valid_until;
denom_key->deposit_valid_until = deposit_valid_until;
@@ -442,7 +455,7 @@ parse_response_keys_get (const char *in, size_t size,
{
json_t *resp_obj;
struct TALER_MINT_DenomPublicKey **denom_keys;
- struct GNUNET_CRYPTO_EddsaPublicKey master_key;
+ struct TALER_MasterPublicKey master_key;
struct GNUNET_TIME_Absolute list_issue_date;
struct TALER_MINT_SigningPublicKey **sign_keys;
unsigned int n_denom_keys;
@@ -478,7 +491,7 @@ parse_response_keys_get (const char *in, size_t size,
EXITIF (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_public_key_from_string (master_key_enc,
52,
- &master_key));
+ &master_key.eddsa_pub));
}
{
/* parse the issue date of the response */
@@ -655,7 +668,8 @@ request_failed (struct TALER_MINT_Handle *mint, long resp_code)
{
struct TALER_MINT_DepositHandle *dh = mint->req.deposit;
TALER_MINT_DepositResultCallback cb = dh->cb;
- void *cls = dh->cls;
+ void *cls = dh->cb_cls;
+
GNUNET_assert (NULL != dh);
cleanup_deposit (dh);
mint_disconnect (mint);
@@ -696,7 +710,7 @@ request_succeeded (struct TALER_MINT_Handle *mint, long resp_code)
parse_response_keys_get (mint->buf, mint->buf_size,
&sign_keys, &n_sign_keys,
&denom_keys, &n_denom_keys))
- gh->cb (gh->cls, sign_keys, denom_keys);
+ gh->cb (gh->cb_cls, sign_keys, denom_keys);
else
emsg = GNUNET_strdup ("Error parsing response");
}
@@ -718,7 +732,7 @@ request_succeeded (struct TALER_MINT_Handle *mint, long resp_code)
GNUNET_assert (NULL != dh);
obj = NULL;
cb = dh->cb;
- cls = dh->cls;
+ cls = dh->cb_cls;
status = 0;
if (200 == resp_code)
{
@@ -894,15 +908,15 @@ download (char *bufptr, size_t size, size_t nitems, void *cls)
* @param ctx the context
* @param hostname the hostname of the mint
* @param port the point where the mint's HTTP service is running.
- * @param mint_key the public key of the mint. This is used to verify the
- * responses of the mint.
+ * @param mint_key the offline master public key of the mint.
+ * This is used to verify the responses of the mint.
* @return the mint handle; NULL upon error
*/
struct TALER_MINT_Handle *
TALER_MINT_connect (struct TALER_MINT_Context *ctx,
const char *hostname,
uint16_t port,
- struct GNUNET_CRYPTO_EddsaPublicKey *mint_key)
+ const struct TALER_MasterPublicKey *mint_key)
{
struct TALER_MINT_Handle *mint;
@@ -943,15 +957,17 @@ TALER_MINT_disconnect (struct TALER_MINT_Handle *mint)
*
* @param mint handle to the mint
* @param cb the callback to call with each retrieved denomination key
- * @param cls closure for the above callback
+ * @param cb_cls closure for the above callback
* @param cont_cb the callback to call after completing this asynchronous call
* @param cont_cls the closure for the continuation callback
* @return a handle to this asynchronous call; NULL upon eror
*/
struct TALER_MINT_KeysGetHandle *
TALER_MINT_keys_get (struct TALER_MINT_Handle *mint,
- TALER_MINT_KeysGetCallback cb, void *cls,
- TALER_MINT_ContinuationCallback cont_cb, void *cont_cls)
+ TALER_MINT_KeysGetCallback cb,
+ void *cb_cls,
+ TALER_MINT_ContinuationCallback cont_cb,
+ void *cont_cls)
{
struct TALER_MINT_KeysGetHandle *gh;
@@ -961,12 +977,17 @@ TALER_MINT_keys_get (struct TALER_MINT_Handle *mint,
mint->req_type = REQUEST_TYPE_KEYSGET;
mint->req.keys_get = gh;
gh->cb = cb;
- gh->cls = cls;
+ gh->cb_cls = cb_cls;
gh->cont_cb = cont_cb;
gh->cont_cls = cont_cls;
- GNUNET_asprintf (&gh->url, "http://%s:%hu/keys", mint->hostname, mint->port);
+ GNUNET_asprintf (&gh->url,
+ "http://%s:%hu/keys",
+ mint->hostname,
+ mint->port);
GNUNET_assert (CURLE_OK ==
- curl_easy_setopt (mint->curl, CURLOPT_URL, gh->url));
+ curl_easy_setopt (mint->curl,
+ CURLOPT_URL,
+ gh->url));
if (GNUNET_NO == mint->connected)
mint_connect (mint);
perform_now (mint->ctx);
@@ -996,7 +1017,7 @@ TALER_MINT_keys_get_cancel (struct TALER_MINT_KeysGetHandle *get)
*
* @param mint the mint handle
* @param cb the callback to call when a reply for this request is available
- * @param cls closure for the above callback
+ * @param cb_cls closure for the above callback
* @param deposit_obj the deposit permission received from the customer along
* with the wireformat JSON object
* @return a handle for this request; NULL if the JSON object could not be
@@ -1006,7 +1027,7 @@ TALER_MINT_keys_get_cancel (struct TALER_MINT_KeysGetHandle *get)
struct TALER_MINT_DepositHandle *
TALER_MINT_deposit_submit_json (struct TALER_MINT_Handle *mint,
TALER_MINT_DepositResultCallback cb,
- void *cls,
+ void *cb_cls,
json_t *deposit_obj)
{
struct TALER_MINT_DepositHandle *dh;
@@ -1017,7 +1038,7 @@ TALER_MINT_deposit_submit_json (struct TALER_MINT_Handle *mint,
mint->req_type = REQUEST_TYPE_DEPOSIT;
mint->req.deposit = dh;
dh->cb = cb;
- dh->cls = cls;
+ dh->cb_cls = cb_cls;
GNUNET_asprintf (&dh->url, "http://%s:%hu/deposit", mint->hostname, mint->port);
GNUNET_assert (NULL != (dh->json_enc = json_dumps (deposit_obj, JSON_COMPACT)));
GNUNET_assert (CURLE_OK ==
diff --git a/src/mint/Makefile.am b/src/mint/Makefile.am
index 19fba62f0..1eba7d61d 100644
--- a/src/mint/Makefile.am
+++ b/src/mint/Makefile.am
@@ -1,17 +1,33 @@
# This Makefile.am is in the public domain
AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/pq/ $(POSTGRESQL_CPPFLAGS)
+plugindir = $(libdir)/taler
+
+plugin_LTLIBRARIES = \
+ libtaler_plugin_mintdb_postgres.la
+
+EXTRA_DIST = plugin_mintdb_common.c
+
+libtaler_plugin_mintdb_postgres_la_SOURCES = \
+ plugin_mintdb_postgres.c
+libtaler_plugin_mintdb_postgres_la_LIBADD = \
+ $(LTLIBINTL)
+libtaler_plugin_mintdb_postgres_la_LDFLAGS = \
+ $(TALER_PLUGIN_LDFLAGS) \
+ -lpq \
+ -lgnunetutil
+
lib_LTLIBRARIES = \
libtalermint_common.la
libtalermint_common_la_SOURCES = \
key_io.c key_io.h \
- mint_db.c
+ plugin.c plugin.h \
+ taler_mintdb_plugin.h
libtalermint_common_la_LIBADD = \
$(top_builddir)/src/util/libtalerutil.la \
- -lgnunetutil \
- -lpq
+ -lgnunetutil
libtalermint_common_la_LDFLAGS = \
$(POSTGRESQL_LDFLAGS) \
@@ -70,7 +86,6 @@ taler_mint_httpd_SOURCES = \
taler-mint-httpd_parsing.c taler-mint-httpd_parsing.h \
taler-mint-httpd_responses.c taler-mint-httpd_responses.h \
taler-mint-httpd_mhd.c \
- taler-mint-httpd_keys.c \
taler-mint-httpd_deposit.c \
taler-mint-httpd_withdraw.c \
taler-mint-httpd_refresh.c
@@ -128,4 +143,4 @@ test_mint_db_LDADD = \
libtalermint_common.la \
$(top_srcdir)/src/util/libtalerutil.la \
$(top_srcdir)/src/pq/libtalerpq.la \
- -lgnunetutil
+ -lgnunetutil -ljansson
diff --git a/src/mint/key_io.c b/src/mint/key_io.c
index 6b70e980a..182d6f3de 100644
--- a/src/mint/key_io.c
+++ b/src/mint/key_io.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2014, 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
@@ -13,9 +13,8 @@
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 key_io.c
+ * @file mint/key_io.c
* @brief I/O operations for the Mint's private keys
* @author Florian Dold
* @author Benedikt Mueller
@@ -26,26 +25,39 @@
#include "key_io.h"
+/**
+ * Closure for the #signkeys_iterate_dir_iter().
+ */
struct SignkeysIterateContext
{
- TALER_MINT_SignkeyIterator it;
- void *it_cls;
-};
+ /**
+ * Function to call on each signing key.
+ */
+ TALER_MINT_SignkeyIterator it;
-struct DenomkeysIterateContext
-{
- const char *alias;
- TALER_MINT_DenomkeyIterator it;
+ /**
+ * Closure for @e it.
+ */
void *it_cls;
};
+/**
+ * Function called on each file in the directory with
+ * our signing keys. Parses the file and calls the
+ * iterator from @a cls.
+ *
+ * @param cls the `struct SignkeysIterateContext *`
+ * @param filename name of the file to parse
+ * @return #GNUNET_OK to continue,
+ * #GNUNET_NO to stop iteration without error,
+ * #GNUNET_SYSERR to stop iteration with error
+ */
static int
signkeys_iterate_dir_iter (void *cls,
const char *filename)
{
-
struct SignkeysIterateContext *skc = cls;
ssize_t nread;
struct TALER_MINT_SignKeyIssuePriv issue;
@@ -55,37 +67,58 @@ signkeys_iterate_dir_iter (void *cls,
sizeof (struct TALER_MINT_SignKeyIssuePriv));
if (nread != sizeof (struct TALER_MINT_SignKeyIssuePriv))
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid signkey file: '%s'\n", filename);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Invalid signkey file `%s': wrong size\n",
+ filename);
return GNUNET_OK;
}
- return skc->it (skc->it_cls, &issue);
+ return skc->it (skc->it_cls,
+ filename,
+ &issue);
}
+/**
+ * Call @a it for each signing key found in the @a mint_base_dir.
+ *
+ * @param mint_base_dir base directory for the mint,
+ * the signing keys must be in the #DIR_SIGNKEYS
+ * subdirectory
+ * @param it function to call on each signing key
+ * @param it_cls closure for @a it
+ * @return number of files found (may not match
+ * number of keys given to @a it as malformed
+ * files are simply skipped), -1 on error
+ */
int
TALER_MINT_signkeys_iterate (const char *mint_base_dir,
- TALER_MINT_SignkeyIterator it, void *cls)
+ TALER_MINT_SignkeyIterator it,
+ void *it_cls)
{
char *signkey_dir;
- size_t len;
struct SignkeysIterateContext skc;
+ int ret;
- len = GNUNET_asprintf (&signkey_dir, ("%s" DIR_SEPARATOR_STR DIR_SIGNKEYS), mint_base_dir);
- GNUNET_assert (len > 0);
-
+ GNUNET_asprintf (&signkey_dir,
+ "%s" DIR_SEPARATOR_STR DIR_SIGNKEYS,
+ mint_base_dir);
skc.it = it;
- skc.it_cls = cls;
-
- return GNUNET_DISK_directory_scan (signkey_dir, &signkeys_iterate_dir_iter, &skc);
+ skc.it_cls = it_cls;
+ ret = GNUNET_DISK_directory_scan (signkey_dir,
+ &signkeys_iterate_dir_iter,
+ &skc);
+ GNUNET_free (signkey_dir);
+ return ret;
}
/**
- * Import a denomination key from the given file
+ * Import a denomination key from the given file.
*
* @param filename the file to import the key from
- * @param dki pointer to return the imported denomination key
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
+ * @param[OUT] dki set to the imported denomination key
+ * @return #GNUNET_OK upon success;
+ * #GNUNET_SYSERR upon failure
*/
int
TALER_MINT_read_denom_key (const char *filename,
@@ -95,42 +128,55 @@ TALER_MINT_read_denom_key (const char *filename,
size_t offset;
void *data;
struct GNUNET_CRYPTO_rsa_PrivateKey *priv;
- int ret;
- ret = GNUNET_SYSERR;
- data = NULL;
- offset = sizeof (struct TALER_MINT_DenomKeyIssuePriv)
- - offsetof (struct TALER_MINT_DenomKeyIssuePriv, issue.signature);
if (GNUNET_OK != GNUNET_DISK_file_size (filename,
&size,
GNUNET_YES,
GNUNET_YES))
- goto cleanup;
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Skipping inaccessable denomination key file `%s'\n",
+ filename);
+ return GNUNET_SYSERR;
+ }
+ offset = sizeof (struct TALER_MINT_DenomKeyIssue);
if (size <= offset)
{
GNUNET_break (0);
- goto cleanup;
+ return GNUNET_SYSERR;
}
data = GNUNET_malloc (size);
- if (size != GNUNET_DISK_fn_read (filename,
- data,
- size))
- goto cleanup;
- if (NULL == (priv = GNUNET_CRYPTO_rsa_private_key_decode (data + offset,
- size - offset)))
- goto cleanup;
- dki->denom_priv = priv;
- memcpy (&dki->issue.signature, data, offset);
- ret = GNUNET_OK;
-
- cleanup:
- GNUNET_free_non_null (data);
- return ret;
+ if (size !=
+ GNUNET_DISK_fn_read (filename,
+ data,
+ size))
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+ "read",
+ filename);
+ GNUNET_free (data);
+ return GNUNET_SYSERR;
+ }
+ if (NULL ==
+ (priv = GNUNET_CRYPTO_rsa_private_key_decode (data + offset,
+ size - offset)))
+ {
+ GNUNET_free (data);
+ return GNUNET_SYSERR;
+ }
+ dki->denom_priv.rsa_private_key = priv;
+ dki->denom_pub.rsa_public_key
+ = GNUNET_CRYPTO_rsa_private_key_get_public (priv);
+ memcpy (&dki->issue,
+ data,
+ offset);
+ GNUNET_free (data);
+ return GNUNET_OK;
}
/**
- * Exports a denomination key to the given file
+ * Exports a denomination key to the given file.
*
* @param filename the file where to write the denomination key
* @param dki the denomination key
@@ -148,25 +194,26 @@ TALER_MINT_write_denom_key (const char *filename,
int ret;
fh = NULL;
- priv_enc_size = GNUNET_CRYPTO_rsa_private_key_encode (dki->denom_priv,
- &priv_enc);
+ priv_enc_size
+ = GNUNET_CRYPTO_rsa_private_key_encode (dki->denom_priv.rsa_private_key,
+ &priv_enc);
ret = GNUNET_SYSERR;
if (NULL == (fh = GNUNET_DISK_file_open
(filename,
GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_TRUNCATE,
GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)))
goto cleanup;
- wsize = sizeof (struct TALER_MINT_DenomKeyIssuePriv)
- - offsetof (struct TALER_MINT_DenomKeyIssuePriv, issue.signature);
+ wsize = sizeof (struct TALER_MINT_DenomKeyIssue);
if (GNUNET_SYSERR == (wrote = GNUNET_DISK_file_write (fh,
&dki->issue.signature,
wsize)))
goto cleanup;
if (wrote != wsize)
goto cleanup;
- if (GNUNET_SYSERR == (wrote = GNUNET_DISK_file_write (fh,
- priv_enc,
- priv_enc_size)))
+ if (GNUNET_SYSERR ==
+ (wrote = GNUNET_DISK_file_write (fh,
+ priv_enc,
+ priv_enc_size)))
goto cleanup;
if (wrote != priv_enc_size)
goto cleanup;
@@ -179,25 +226,74 @@ TALER_MINT_write_denom_key (const char *filename,
}
+/**
+ * Closure for #denomkeys_iterate_keydir_iter() and
+ * #denomkeys_iterate_topdir_iter().
+ */
+struct DenomkeysIterateContext
+{
+
+ /**
+ * Set to the name of the directory below the top-level directory
+ * during the call to #denomkeys_iterate_keydir_iter().
+ */
+ const char *alias;
+
+ /**
+ * Function to call on each denomination key.
+ */
+ TALER_MINT_DenomkeyIterator it;
+
+ /**
+ * Closure for @e it.
+ */
+ void *it_cls;
+};
+
+
+/**
+ * Decode the denomination key in the given file @a filename and call
+ * the callback in @a cls with the information.
+ *
+ * @param cls the `struct DenomkeysIterateContext *`
+ * @param filename name of a file that should contain
+ * a denomination key
+ * @return #GNUNET_OK to continue to iterate
+ * #GNUNET_NO to abort iteration with success
+ * #GNUNET_SYSERR to abort iteration with failure
+ */
static int
denomkeys_iterate_keydir_iter (void *cls,
const char *filename)
{
-
struct DenomkeysIterateContext *dic = cls;
struct TALER_MINT_DenomKeyIssuePriv issue;
- if (GNUNET_OK != TALER_MINT_read_denom_key (filename, &issue))
+ if (GNUNET_OK !=
+ TALER_MINT_read_denom_key (filename,
+ &issue))
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Invalid denomkey file: '%s'\n",
filename);
return GNUNET_OK;
}
- return dic->it (dic->it_cls, dic->alias, &issue);
+ return dic->it (dic->it_cls,
+ dic->alias,
+ &issue);
}
+/**
+ * Function called on each subdirectory in the #DIR_DENOMKEYS. Will
+ * call the #denomkeys_iterate_keydir_iter() on each file in the
+ * subdirectory.
+ *
+ * @param cls the `struct DenomkeysIterateContext *`
+ * @param filename name of the subdirectory to scan
+ * @return #GNUNET_OK on success,
+ * #GNUNET_SYSERR if we need to abort
+ */
static int
denomkeys_iterate_topdir_iter (void *cls,
const char *filename)
@@ -205,36 +301,47 @@ denomkeys_iterate_topdir_iter (void *cls,
struct DenomkeysIterateContext *dic = cls;
dic->alias = GNUNET_STRINGS_get_short_name (filename);
-
- // FIXME: differentiate between error case and normal iteration abortion
- if (0 > GNUNET_DISK_directory_scan (filename, &denomkeys_iterate_keydir_iter, dic))
+ if (0 > GNUNET_DISK_directory_scan (filename,
+ &denomkeys_iterate_keydir_iter,
+ dic))
return GNUNET_SYSERR;
return GNUNET_OK;
}
+/**
+ * Call @a it for each denomination key found in the @a mint_base_dir.
+ *
+ * @param mint_base_dir base directory for the mint,
+ * the signing keys must be in the #DIR_DENOMKEYS
+ * subdirectory
+ * @param it function to call on each denomination key found
+ * @param it_cls closure for @a it
+ * @return -1 on error, 0 if no files were found, otherwise
+ * a positive number (however, even with a positive
+ * number it is possible that @a it was never called
+ * as maybe none of the files were well-formed)
+ */
int
TALER_MINT_denomkeys_iterate (const char *mint_base_dir,
- TALER_MINT_DenomkeyIterator it, void *cls)
+ TALER_MINT_DenomkeyIterator it,
+ void *it_cls)
{
char *dir;
- size_t len;
struct DenomkeysIterateContext dic;
+ int ret;
- len = GNUNET_asprintf (&dir,
- "%s" DIR_SEPARATOR_STR DIR_DENOMKEYS,
- mint_base_dir);
- GNUNET_assert (len > 0);
-
+ GNUNET_asprintf (&dir,
+ "%s" DIR_SEPARATOR_STR DIR_DENOMKEYS,
+ mint_base_dir);
dic.it = it;
- dic.it_cls = cls;
-
- // scan over alias dirs
- return GNUNET_DISK_directory_scan (dir,
- &denomkeys_iterate_topdir_iter,
- &dic);
+ dic.it_cls = it_cls;
+ ret = GNUNET_DISK_directory_scan (dir,
+ &denomkeys_iterate_topdir_iter,
+ &dic);
+ GNUNET_free (dir);
+ return ret;
}
-
-/* end of mint_common.c */
+/* end of key_io.c */
diff --git a/src/mint/key_io.h b/src/mint/key_io.h
index c9fd57625..6c6722a8a 100644
--- a/src/mint/key_io.h
+++ b/src/mint/key_io.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2014, 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
@@ -14,72 +14,103 @@
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file key_io.h
+ * @file mint/key_io.h
* @brief IO operations for the mint's private keys
* @author Florian Dold
* @author Benedikt Mueller
* @author Christian Grothoff
- *
- * TODO:
- * - document better
*/
#ifndef KEY_IO_H
#define KEY_IO_H
#include <gnunet/gnunet_util_lib.h>
-#include <gnunet/gnunet_common.h>
-#include "taler_util.h"
#include "taler_signatures.h"
+/**
+ * Subdirectroy under the mint's base directory which contains
+ * the mint's signing keys.
+ */
#define DIR_SIGNKEYS "signkeys"
+
+/**
+ * Subdirectory under the mint's base directory which contains
+ * the mint's denomination keys.
+ */
#define DIR_DENOMKEYS "denomkeys"
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
/**
- * On disk format used for a mint signing key.
- * Includes the private key followed by the signed
- * issue message.
+ * On disk format used for a mint signing key. Signing keys are used
+ * by the mint to affirm its messages, but not to create coins.
+ * Includes the private key followed by the public information about
+ * the signing key.
*/
struct TALER_MINT_SignKeyIssuePriv
{
- struct GNUNET_CRYPTO_EddsaPrivateKey signkey_priv;
+ /**
+ * Private key part of the mint's signing key.
+ */
+ struct TALER_MintPrivateKey signkey_priv;
+ /**
+ * Public information about a mint signing key.
+ */
struct TALER_MINT_SignKeyIssue issue;
};
+GNUNET_NETWORK_STRUCT_END
+
+/**
+ * All information about a denomination key (which is used to
+ * sign coins into existence).
+ */
struct TALER_MINT_DenomKeyIssuePriv
{
/**
- * The private key of the denomination. Will be NULL if the private key is
- * not available.
+ * The private key of the denomination. Will be NULL if the private
+ * key is not available (this is the case after the key has expired
+ * for signing coins, but is still valid for depositing coins).
*/
- struct GNUNET_CRYPTO_rsa_PrivateKey *denom_priv;
+ struct TALER_DenominationPrivateKey denom_priv;
+ /**
+ * Decoded denomination public key (the hash of it is in
+ * @e issue, but we sometimes need the full public key as well).
+ */
+ struct TALER_DenominationPublicKey denom_pub;
+
+ /**
+ * Signed public information about a denomination key.
+ */
struct TALER_MINT_DenomKeyIssue issue;
};
-
-
/**
- * Iterator for sign keys.
+ * Iterator over signing keys.
*
* @param cls closure
- * @param ski the sign key issue
+ * @param filename name of the file the key came from
+ * @param ski the sign key
* @return #GNUNET_OK to continue to iterate,
* #GNUNET_NO to stop iteration with no error,
* #GNUNET_SYSERR to abort iteration with error!
*/
typedef int
(*TALER_MINT_SignkeyIterator)(void *cls,
+ const char *filename,
const struct TALER_MINT_SignKeyIssuePriv *ski);
+
/**
- * Iterator for denomination keys.
+ * Iterator over denomination keys.
*
* @param cls closure
- * @param dki the denomination key issue
+ * @param dki the denomination key
* @param alias coin alias
* @return #GNUNET_OK to continue to iterate,
* #GNUNET_NO to stop iteration with no error,
@@ -93,23 +124,44 @@ typedef int
/**
- * FIXME
+ * Call @a it for each signing key found in the @a mint_base_dir.
+ *
+ * @param mint_base_dir base directory for the mint,
+ * the signing keys must be in the #DIR_SIGNKEYS
+ * subdirectory
+ * @param it function to call on each signing key
+ * @param it_cls closure for @a it
+ * @return number of files found (may not match
+ * number of keys given to @a it as malformed
+ * files are simply skipped), -1 on error
*/
int
TALER_MINT_signkeys_iterate (const char *mint_base_dir,
- TALER_MINT_SignkeyIterator it, void *cls);
+ TALER_MINT_SignkeyIterator it,
+ void *it_cls);
/**
- * FIXME
+ * Call @a it for each denomination key found in the @a mint_base_dir.
+ *
+ * @param mint_base_dir base directory for the mint,
+ * the signing keys must be in the #DIR_DENOMKEYS
+ * subdirectory
+ * @param it function to call on each denomination key found
+ * @param it_cls closure for @a it
+ * @return -1 on error, 0 if no files were found, otherwise
+ * a positive number (however, even with a positive
+ * number it is possible that @a it was never called
+ * as maybe none of the files were well-formed)
*/
int
TALER_MINT_denomkeys_iterate (const char *mint_base_dir,
- TALER_MINT_DenomkeyIterator it, void *cls);
+ TALER_MINT_DenomkeyIterator it,
+ void *it_cls);
/**
- * Exports a denomination key to the given file
+ * Exports a denomination key to the given file.
*
* @param filename the file where to write the denomination key
* @param dki the denomination key
@@ -121,10 +173,10 @@ TALER_MINT_write_denom_key (const char *filename,
/**
- * Import a denomination key from the given file
+ * Import a denomination key from the given file.
*
* @param filename the file to import the key from
- * @param dki pointer to return the imported denomination key
+ * @param[OUT] dki set to the imported denomination key
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
*/
int
@@ -132,7 +184,4 @@ TALER_MINT_read_denom_key (const char *filename,
struct TALER_MINT_DenomKeyIssuePriv *dki);
-
-
-
#endif
diff --git a/src/mint/mint_db.h b/src/mint/mint_db.h
deleted file mode 100644
index 9818172af..000000000
--- a/src/mint/mint_db.h
+++ /dev/null
@@ -1,974 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014, 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/mint_db.h
- * @brief Low-level (statement-level) database access for the mint
- * @author Florian Dold
- * @author Christian Grothoff
- */
-#ifndef MINT_DB_H
-#define MINT_DB_H
-
-#include <libpq-fe.h>
-#include <microhttpd.h>
-#include <gnunet/gnunet_util_lib.h>
-#include "taler_util.h"
-
-#define TALER_TEMP_SCHEMA_NAME "taler_temporary"
-
-/**
- * Initialize database subsystem.
- *
- * @param connection_cfg configuration for the DB
- * @return #GNUNET_OK on success
- */
-int
-TALER_MINT_DB_init (const char *connection_cfg);
-
-
-/**
- * Get the thread-local database-handle.
- * Connect to the db if the connection does not exist yet.
- *
- * @param temporary #GNUNET_YES to use a temporary schema; #GNUNET_NO to use the
- * database default one
- * @param the database connection, or NULL on error
- */
-PGconn *
-TALER_MINT_DB_get_connection (int temporary);
-
-
-/**
- * Drop the temporary taler schema. This is only useful for testcases
- *
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
-int
-TALER_MINT_DB_drop_temporary (PGconn *db);
-
-
-/**
- * Create the necessary tables if they are not present
- *
- * @param temporary should we use a temporary schema
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
-int
-TALER_MINT_DB_create_tables (int temporary);
-
-/**
- * Setup prepared statements. FIXME: should this be part of the API,
- * or just internal to "TALER_MINT_DB_get_connection()"?
- *
- * @param db_conn connection handle to initialize
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
- */
-int
-TALER_MINT_DB_prepare (PGconn *db_conn);
-
-
-/**
- * Start a transaction.
- *
- * @param db_conn connection to use
- * @return #GNUNET_OK on success
- */
-int
-TALER_MINT_DB_transaction (PGconn *db_conn);
-
-
-/**
- * Commit a transaction.
- *
- * @param db_conn connection to use
- * @return #GNUNET_OK on success
- */
-int
-TALER_MINT_DB_commit (PGconn *db_conn);
-
-
-/**
- * Abort/rollback a transaction.
- *
- * @param db_conn connection to use
- */
-void
-TALER_MINT_DB_rollback (PGconn *db_conn);
-
-
-/**
- * Information we keep on a bank transfer that
- * established a reserve.
- */
-struct BankTransfer
-{
-
- /**
- * Public key of the reserve that was filled.
- */
- struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
-
- /**
- * Amount that was transferred to the mint.
- */
- struct TALER_Amount amount;
-
- /**
- * Detailed wire information about the transaction.
- */
- const json_t *wire;
-
-};
-
-
-/* FIXME: add functions to add bank transfers to our DB
- (and to test if we already did add one) (#3633) */
-
-/**
- * A summary of a Reserve
- */
-struct Reserve
-{
- /**
- * The reserve's public key. This uniquely identifies the reserve
- */
- struct GNUNET_CRYPTO_EddsaPublicKey *pub;
-
- /**
- * The balance amount existing in the reserve
- */
- struct TALER_Amount balance;
-
- /**
- * The expiration date of this reserve
- */
- struct GNUNET_TIME_Absolute expiry;
-};
-
-
-/**
- * Information we keep for a withdrawn coin to reproduce
- * the /withdraw operation if needed, and to have proof
- * that a reserve was drained by this amount.
- */
-struct CollectableBlindcoin
-{
-
- /**
- * Our signature over the (blinded) coin.
- */
- struct GNUNET_CRYPTO_rsa_Signature *sig;
-
- /**
- * Denomination key (which coin was generated).
- */
- struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub;
-
- /**
- * Public key of the reserve that was drained.
- */
- struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
-
- /**
- * Hash over the blinded message, needed to verify
- * the @e reserve_sig.
- */
- struct GNUNET_HashCode h_coin_envelope;
-
- /**
- * Signature confirming the withdrawl, matching @e reserve_pub,
- * @e denom_pub and @e h_coin_envelope.
- */
- struct GNUNET_CRYPTO_EddsaSignature reserve_sig;
-};
-
-
-/**
- * Get the summary of a reserve.
- *
- * @param db the database connection handle
- * @param reserve the reserve data. The public key of the reserve should be set
- * in this structure; it is used to query the database. The balance
- * and expiration are then filled accordingly.
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
- */
-int
-TALER_MINT_DB_reserve_get (PGconn *db,
- struct Reserve *reserve);
-
-
-/**
- * Insert a incoming transaction into reserves. New reserves are also created
- * through this function.
- *
- * @param db the database connection handle
- * @param reserve the reserve structure. The public key of the reserve should
- * be set here. Upon successful execution of this function, the
- * balance and expiration of the reserve will be updated.
- * @param balance the amount that has to be added to the reserve
- * @param expiry the new expiration time for the reserve
- * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failures
- */
-int
-TALER_MINT_DB_reserves_in_insert (PGconn *db,
- struct Reserve *reserve,
- const struct TALER_Amount balance,
- const struct GNUNET_TIME_Absolute expiry);
-
-
-/**
- * Locate the response for a /withdraw request under the
- * key of the hash of the blinded message.
- *
- * @param db_conn database connection to use
- * @param h_blind hash of the blinded message
- * @param collectable corresponding collectable coin (blind signature)
- * if a coin is found
- * @return #GNUNET_SYSERR on internal error
- * #GNUNET_NO if the collectable was not found
- * #GNUNET_YES on success
- */
-int
-TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn,
- const struct GNUNET_HashCode *h_blind,
- struct CollectableBlindcoin *collectable);
-
-
-/**
- * Store collectable bit coin under the corresponding
- * hash of the blinded message.
- *
- * @param db_conn database connection to use
- * @param h_blind hash of the blinded message
- * @param collectable corresponding collectable coin (blind signature)
- * if a coin is found
- * @return #GNUNET_SYSERR on internal error
- * #GNUNET_NO if the collectable was not found
- * #GNUNET_YES on success
- */
-int
-TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn,
- const struct GNUNET_HashCode *h_blind,
- const struct CollectableBlindcoin *collectable);
-
-
-
-/**
- * Types of operations on a reserved.
- */
-enum TALER_MINT_DB_ReserveOperation
-{
- /**
- * Money was deposited into the reserve via a bank transfer.
- */
- TALER_MINT_DB_RO_BANK_TO_MINT = 0,
-
- /**
- * A Coin was withdrawn from the reserve using /withdraw.
- */
- TALER_MINT_DB_RO_WITHDRAW_COIN = 1
-};
-
-
-/**
- * Reserve history as a linked list. Lists all of the transactions
- * associated with this reserve (such as the bank transfers that
- * established the reserve and all /withdraw operations we have done
- * since).
- */
-struct ReserveHistory
-{
-
- /**
- * Next entry in the reserve history.
- */
- struct ReserveHistory *next;
-
- /**
- * Type of the event, determins @e details.
- */
- enum TALER_MINT_DB_ReserveOperation type;
-
- /**
- * Details of the operation, depending on @e type.
- */
- union
- {
-
- /**
- * Details about a bank transfer to the mint.
- */
- struct BankTransfer *bank;
-
- /**
- * Details about a /withdraw operation.
- */
- struct CollectableBlindcoin *withdraw;
-
- } details;
-
-};
-
-
-/**
- * Get all of the transaction history associated with the specified
- * reserve.
- *
- * @param db_conn connection to use
- * @param reserve_pub public key of the reserve
- * @return known transaction history (NULL if reserve is unknown)
- */
-struct ReserveHistory *
-TALER_MINT_DB_get_reserve_history (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub);
-
-
-/**
- * Free memory associated with the given reserve history.
- *
- * @param rh history to free.
- */
-void
-TALER_MINT_DB_free_reserve_history (struct ReserveHistory *rh);
-
-
-/**
- * Specification for a /deposit operation.
- */
-struct Deposit
-{
- /**
- * Information about the coin that is being deposited.
- */
- struct TALER_CoinPublicInfo coin;
-
- /**
- * ECDSA signature affirming that the customer intends
- * this coin to be deposited at the merchant identified
- * by @e h_wire in relation to the contract identified
- * by @e h_contract.
- */
- struct GNUNET_CRYPTO_EcdsaSignature csig;
-
- /**
- * Public key of the merchant. Enables later identification
- * of the merchant in case of a need to rollback transactions.
- */
- struct GNUNET_CRYPTO_EddsaPublicKey merchant_pub;
-
- /**
- * Hash over the contract between merchant and customer
- * (remains unknown to the Mint).
- */
- struct GNUNET_HashCode h_contract;
-
- /**
- * Hash of the (canonical) representation of @e wire, used
- * to check the signature on the request. Generated by
- * the mint from the detailed wire data provided by the
- * merchant.
- */
- struct GNUNET_HashCode h_wire;
-
- /**
- * Detailed wire information for executing the transaction.
- */
- const json_t *wire;
-
- /**
- * Merchant-generated transaction ID to detect duplicate
- * transactions.
- */
- uint64_t transaction_id;
-
- /**
- * Fraction of the coin's remaining value to be deposited.
- * The coin is identified by @e coin_pub.
- */
- struct TALER_Amount amount;
-
-};
-
-
-/**
- * Check if we have the specified deposit already in the database.
- *
- * @param db_conn 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 internal error
- */
-int
-TALER_MINT_DB_have_deposit (PGconn *db_conn,
- const struct Deposit *deposit);
-
-
-/**
- * Insert information about deposited coin into the
- * database.
- *
- * @param db_conn connection to the database
- * @param deposit deposit information to store
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-int
-TALER_MINT_DB_insert_deposit (PGconn *db_conn,
- const struct Deposit *deposit);
-
-
-
-/**
- * Global information for a refreshing session. Includes
- * dimensions of the operation, security parameters and
- * client signatures from "/refresh/melt" and "/refresh/commit".
- */
-struct RefreshSession
-{
- /**
- * Signature over the commitments by the client,
- * only valid if @e has_commit_sig is set.
- */
- struct GNUNET_CRYPTO_EddsaSignature commit_sig;
-
- /**
- * Hash over coins to melt and coins to create of the
- * refresh session.
- */
- struct GNUNET_HashCode session_hash;
-
- /**
- * Signature over the melt by the client.
- */
- struct GNUNET_CRYPTO_EddsaSignature melt_sig;
-
- /**
- * Number of coins we are melting.
- */
- uint16_t num_oldcoins;
-
- /**
- * Number of new coins we are creating.
- */
- uint16_t num_newcoins;
-
- /**
- * Number of parallel operations we perform for the cut and choose.
- * (must be greater or equal to three for security). 0 if not yet
- * known.
- */
- uint16_t kappa;
-
- /**
- * Index (smaller @e kappa) which the mint has chosen to not
- * have revealed during cut and choose.
- */
- uint16_t noreveal_index;
-
-};
-
-
-/**
- * Lookup refresh session data under the given public key.
- *
- * @param db_conn database handle to use
- * @param refresh_session_pub public key to use for the lookup
- * @param session[OUT] where to store the result
- * @return #GNUNET_YES on success,
- * #GNUNET_NO if not found,
- * #GNUNET_SYSERR on DB failure
- */
-int
-TALER_MINT_DB_get_refresh_session (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- struct RefreshSession *session);
-
-
-/**
- * Store new refresh session data under the given public key.
- *
- * @param db_conn database handle to use
- * @param refresh_session_pub public key to use to locate the session
- * @param session session data to store
- * @return #GNUNET_YES on success,
- * #GNUNET_SYSERR on DB failure
- */
-int
-TALER_MINT_DB_create_refresh_session (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
- const struct RefreshSession *session);
-
-
-/**
- * Specification for coin in a /refresh/melt operation.
- */
-struct RefreshMelt
-{
- /**
- * Information about the coin that is being melted.
- */
- struct TALER_CoinPublicInfo coin;
-
- /**
- * Signature over the melting operation.
- */
- struct GNUNET_CRYPTO_EcdsaSignature coin_sig;
-
- /**
- * Which melting operation should the coin become a part of.
- */
- struct GNUNET_HashCode melt_hash;
-
- /**
- * How much value is being melted?
- * This amount includes the fees, so the final amount contributed
- * to the melt is this value minus the fee for melting the coin.
- */
- struct TALER_Amount amount;
-
-};
-
-
-/**
- * Store the given /refresh/melt request in the database.
- *
- * @param db_conn database connection
- * @param session session key of the melt operation
- * @param oldcoin_index index of the coin to store
- * @param melt coin melt operation details to store
- * @return #GNUNET_OK on success
- * #GNUNET_SYSERR on internal error
- */
-int
-TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session,
- uint16_t oldcoin_index,
- const struct RefreshMelt *melt);
-
-
-
-/**
- * Get information about melted coin details from the database.
- *
- * @param db_conn database connection
- * @param session session key of the melt operation
- * @param oldcoin_index index of the coin to retrieve
- * @param melt melt data to fill in
- * @return #GNUNET_OK on success
- * #GNUNET_SYSERR on internal error
- */
-int
-TALER_MINT_DB_get_refresh_melt (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session,
- uint16_t oldcoin_index,
- struct RefreshMelt *melt);
-
-
-/**
- * Store in the database which coin(s) we want to create
- * in a given refresh operation.
- *
- * @param db_conn database connection
- * @param session_pub refresh session key
- * @param newcoin_index index of the coin to generate
- * @param denom_pub denomination of the coin to create
- * @return #GNUNET_OK on success
- * #GNUNET_SYSERR on internal error
- */
-int
-TALER_MINT_DB_insert_refresh_order (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
- uint16_t newcoin_index,
- const struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub);
-
-
-/**
- * Lookup in the database the @a newcoin_index coin that we want to
- * create in the given refresh operation.
- *
- * @param db_conn database connection
- * @param session_pub refresh session key
- * @param newcoin_index index of the coin to generate
- * @param denom_pub denomination of the coin to create
- * @return NULL on error (not found or internal error)
- */
-struct GNUNET_CRYPTO_rsa_PublicKey *
-TALER_MINT_DB_get_refresh_order (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
- uint16_t newcoin_index);
-
-
-/**
- * We have as many `struct RefreshCommitCoin` as there are new
- * coins being created by the refresh (for each of the kappa
- * sets). These are the coins we ask the mint to sign if the
- * respective set is selected.
- */
-struct RefreshCommitCoin
-{
-
- /**
- * Encrypted data allowing those able to decrypt it to derive
- * the private keys of the new coins created by the refresh.
- */
- struct TALER_RefreshLinkEncrypted *refresh_link;
-
- /**
- * Blinded message to be signed (in envelope), with @e coin_env_size bytes.
- */
- char *coin_ev;
-
- /**
- * Number of bytes in @e coin_ev.
- */
- size_t coin_ev_size;
-
-};
-
-
-/**
- * Store information about the commitment of the
- * given coin for the given refresh session in the database.
- *
- * @param db_conn database connection to use
- * @param refresh_session_pub refresh session this commitment belongs to
- * @param i set index (1st dimension)
- * @param j coin index (2nd dimension), corresponds to refreshed (new) coins
- * @param commit_coin coin commitment to store
- * @return #GNUNET_OK on success
- * #GNUNET_SYSERR on error
- */
-int
-TALER_MINT_DB_insert_refresh_commit_coin (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- unsigned int i,
- unsigned int j,
- const struct RefreshCommitCoin *commit_coin);
-
-
-/**
- * Obtain information about the commitment of the
- * given coin of the given refresh session from the database.
- *
- * @param db_conn database connection to use
- * @param refresh_session_pub refresh session the commitment belongs to
- * @param i set index (1st dimension)
- * @param j coin index (2nd dimension), corresponds to refreshed (new) coins
- * @param commit_coin[OUT] coin commitment to return
- * @return #GNUNET_OK on success
- * #GNUNET_NO if not found
- * #GNUNET_SYSERR on error
- */
-int
-TALER_MINT_DB_get_refresh_commit_coin (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- unsigned int i,
- unsigned int j,
- struct RefreshCommitCoin *commit_coin);
-
-
-/**
- * For each (old) coin being melted, we have a `struct
- * RefreshCommitLink` that allows the user to find the shared secret
- * to decrypt the respective refresh links for the new coins in the
- * `struct RefreshCommitCoin`.
- */
-struct RefreshCommitLink
-{
- /**
- * Transfer public key (FIXME: explain!)
- */
- struct GNUNET_CRYPTO_EcdsaPublicKey transfer_pub;
-
- /**
- * Encrypted shared secret to decrypt the link.
- */
- struct TALER_EncryptedLinkSecret shared_secret_enc;
-};
-
-
-/**
- * Store the commitment to the given (encrypted) refresh link data
- * for the given refresh session.
- *
- * @param db_conn database connection to use
- * @param refresh_session_pub public key of the refresh session this
- * commitment belongs with
- * @param i set index (1st dimension)
- * @param j coin index (2nd dimension), corresponds to melted (old) coins
- * @param commit_link link information to store
- * @return #GNUNET_SYSERR on internal error, #GNUNET_OK on success
- */
-int
-TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- unsigned int i,
- unsigned int j,
- const struct RefreshCommitLink *commit_link);
-
-/**
- * Obtain the commited (encrypted) refresh link data
- * for the given refresh session.
- *
- * @param db_conn database connection to use
- * @param refresh_session_pub public key of the refresh session this
- * commitment belongs with
- * @param i set index (1st dimension)
- * @param j coin index (2nd dimension), corresponds to melted (old) coins
- * @param cc[OUT] link information to return
- * @return #GNUNET_SYSERR on internal error,
- * #GNUNET_NO if commitment was not found
- * #GNUNET_OK on success
- */
-int
-TALER_MINT_DB_get_refresh_commit_link (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- unsigned int i,
- unsigned int j,
- struct RefreshCommitLink *cc);
-
-
-/**
- * Insert signature of a new coin generated during refresh into
- * the database indexed by the refresh session and the index
- * of the coin. This data is later used should an old coin
- * be used to try to obtain the private keys during "/refresh/link".
- *
- * @param db_conn database connection
- * @param session_pub refresh session
- * @param newcoin_index coin index
- * @param ev_sig coin signature
- * @return #GNUNET_OK on success
- */
-int
-TALER_MINT_DB_insert_refresh_collectable (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
- uint16_t newcoin_index,
- const struct GNUNET_CRYPTO_rsa_Signature *ev_sig);
-
-
-/**
- * Linked list of refresh information linked to a coin.
- */
-struct LinkDataList
-{
- /**
- * Information is stored in a NULL-terminated linked list.
- */
- struct LinkDataList *next;
-
- /**
- * Link data, used to recover the private key of the coin
- * by the owner of the old coin.
- */
- struct TALER_RefreshLinkEncrypted *link_data_enc;
-
- /**
- * Denomination public key, determines the value of the coin.
- */
- struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub;
-
- /**
- * Signature over the blinded envelope.
- */
- struct GNUNET_CRYPTO_rsa_Signature *ev_sig;
-};
-
-
-/**
- * Obtain the link data of a coin, that is the encrypted link
- * information, the denomination keys and the signatures.
- *
- * @param db_conn database connection
- * @param coin_pub public key to use to retrieve linkage data
- * @return all known link data for the coin
- */
-struct LinkDataList *
-TALER_db_get_link (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub);
-
-
-/**
- * Free memory of the link data list.
- *
- * @param ldl link data list to release
- */
-void
-TALER_db_link_data_list_free (struct LinkDataList *ldl);
-
-
-/**
- * Obtain shared secret and transfer public key from the public key of
- * the coin. This information and the link information returned by
- * #TALER_db_get_link() enable the owner of an old coin to determine
- * the private keys of the new coins after the melt.
- *
- *
- * @param db_conn database connection
- * @param coin_pub public key of the coin
- * @param transfer_pub[OUT] public transfer key
- * @param shared_secret_enc[OUT] set to shared secret
- * @return #GNUNET_OK on success,
- * #GNUNET_NO on failure (not found)
- * #GNUNET_SYSERR on internal failure (database issue)
- */
-int
-TALER_db_get_transfer (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
- struct GNUNET_CRYPTO_EcdsaPublicKey *transfer_pub,
- struct TALER_EncryptedLinkSecret *shared_secret_enc);
-
-
-/**
- * Specification for a /lock operation.
- */
-struct Lock
-{
- /**
- * Information about the coin that is being melted.
- */
- struct TALER_CoinPublicInfo coin;
-
- /**
- * Signature over the melting operation.
- */
- const struct GNUNET_CRYPTO_EcdsaSignature coin_sig;
-
- /**
- * How much value is being melted?
- */
- struct TALER_Amount amount;
-
- // FIXME: more needed...
-};
-
-
-/**
- * Test if the given /lock request is known to us.
- *
- * @param db_conn database connection
- * @param lock lock operation
- * @return #GNUNET_YES if known,
- * #GNUENT_NO if not,
- * #GNUNET_SYSERR on internal error
- */
-int
-TALER_MINT_DB_have_lock (PGconn *db_conn,
- const struct Lock *lock);
-
-
-/**
- * Store the given /lock request in the database.
- *
- * @param db_conn database connection
- * @param lock lock operation
- * @return #GNUNET_OK on success
- * #GNUNET_SYSERR on internal error
- */
-int
-TALER_MINT_DB_insert_lock (PGconn *db_conn,
- const struct Lock *lock);
-
-
-/**
- * Enumeration to classify the different types of transactions
- * that can be done with a coin.
- */
-enum TALER_MINT_DB_TransactionType
-{
- /**
- * /deposit operation.
- */
- TALER_MINT_DB_TT_DEPOSIT = 0,
-
- /**
- * /refresh/melt operation.
- */
- TALER_MINT_DB_TT_REFRESH_MELT = 1,
-
- /**
- * /lock operation.
- */
- TALER_MINT_DB_TT_LOCK = 2
-};
-
-
-/**
- * List of transactions we performed for a particular coin.
- */
-struct TALER_MINT_DB_TransactionList
-{
-
- /**
- * Next pointer in the NULL-terminated linked list.
- */
- struct TALER_MINT_DB_TransactionList *next;
-
- /**
- * Type of the transaction, determines what is stored in @e details.
- */
- enum TALER_MINT_DB_TransactionType type;
-
- /**
- * Details about the transaction, depending on @e type.
- */
- union
- {
-
- /**
- * Details if transaction was a /deposit operation.
- */
- struct Deposit *deposit;
-
- /**
- * Details if transaction was a /refresh/melt operation.
- */
- struct RefreshMelt *melt;
-
- /**
- * Details if transaction was a /lock operation.
- */
- struct Lock *lock;
-
- } details;
-
-};
-
-
-/**
- * Compile a list of all (historic) transactions performed
- * with the given coin (/refresh/melt and /deposit operations).
- *
- * @param db_conn database connection
- * @param coin_pub coin to investigate
- * @return list of transactions, NULL if coin is fresh
- */
-struct TALER_MINT_DB_TransactionList *
-TALER_MINT_DB_get_coin_transactions (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub);
-
-
-/**
- * Free linked list of transactions.
- *
- * @param list list to free
- */
-void
-TALER_MINT_DB_free_coin_transaction_list (struct TALER_MINT_DB_TransactionList *list);
-
-
-
-#endif /* _NEURO_MINT_DB_H */
diff --git a/src/mint/plugin.c b/src/mint/plugin.c
new file mode 100644
index 000000000..4fb75f87a
--- /dev/null
+++ b/src/mint/plugin.c
@@ -0,0 +1,118 @@
+/*
+ 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/plugin.c
+ * @brief Logic to load database plugin
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "plugin.h"
+#include <ltdl.h>
+
+
+/**
+ * Global variable with the plugin (once loaded).
+ */
+struct TALER_MINTDB_Plugin *plugin;
+
+/**
+ * Libtool search path before we started.
+ */
+static char *old_dlsearchpath;
+
+
+/**
+ * Initialize the plugin.
+ *
+ * @param cfg configuration to use
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_MINT_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Shutdown the plugin.
+ */
+void
+TALER_MINT_plugin_unload ()
+{
+ if (NULL == plugin)
+ return;
+}
+
+
+/**
+ * Setup libtool paths.
+ */
+void __attribute__ ((constructor))
+plugin_init ()
+{
+ int err;
+ const char *opath;
+ char *path;
+ char *cpath;
+
+ err = lt_dlinit ();
+ if (err > 0)
+ {
+ FPRINTF (stderr,
+ _("Initialization of plugin mechanism failed: %s!\n"),
+ lt_dlerror ());
+ return;
+ }
+ opath = lt_dlgetsearchpath ();
+ if (NULL != opath)
+ old_dlsearchpath = GNUNET_strdup (opath);
+ path = TALER_OS_installation_get_path (GNUNET_OS_IPK_LIBDIR);
+ if (NULL != path)
+ {
+ if (NULL != opath)
+ {
+ GNUNET_asprintf (&cpath, "%s:%s", opath, path);
+ lt_dlsetsearchpath (cpath);
+ GNUNET_free (path);
+ GNUNET_free (cpath);
+ }
+ else
+ {
+ lt_dlsetsearchpath (path);
+ GNUNET_free (path);
+ }
+ }
+}
+
+
+/**
+ * Shutdown libtool.
+ */
+void __attribute__ ((destructor))
+plugin_fini ()
+{
+ lt_dlsetsearchpath (old_dlsearchpath);
+ if (NULL != old_dlsearchpath)
+ {
+ GNUNET_free (old_dlsearchpath);
+ old_dlsearchpath = NULL;
+ }
+ lt_dlexit ();
+}
+
+
+/* end of plugin.c */
diff --git a/src/mint/plugin.h b/src/mint/plugin.h
new file mode 100644
index 000000000..0dfb866da
--- /dev/null
+++ b/src/mint/plugin.h
@@ -0,0 +1,50 @@
+/*
+ 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/plugin.h
+ * @brief Logic to load database plugins
+ * @author Christian Grothoff
+ */
+#ifndef PLUGIN_H
+#define PLUGIN_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_mintdb_plugin.h"
+
+/**
+ * Global variable with the plugin (once loaded).
+ */
+extern struct TALER_MINTDB_Plugin *plugin;
+
+
+/**
+ * Initialize the plugin.
+ *
+ * @param cfg configuration to use
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_MINT_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg);
+
+
+/**
+ * Shutdown the plugin.
+ */
+void
+TALER_MINT_plugin_unload (void);
+
+
+#endif
diff --git a/src/mint/plugin_mintdb_common.c b/src/mint/plugin_mintdb_common.c
new file mode 100644
index 000000000..a95cf4be2
--- /dev/null
+++ b/src/mint/plugin_mintdb_common.c
@@ -0,0 +1,118 @@
+/*
+ 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/plugin_mintdb_common.c
+ * @brief Functions shared across plugins, this file is meant to be
+ * #include-d in each plugin.
+ * @author Christian Grothoff
+ */
+
+/**
+ * Free memory associated with the given reserve history.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state (unused)
+ * @param rh history to free.
+ */
+static void
+common_free_reserve_history (void *cls,
+ struct ReserveHistory *rh)
+{
+ struct BankTransfer *bt;
+ struct CollectableBlindcoin *cbc;
+ struct ReserveHistory *backref;
+
+ while (NULL != rh)
+ {
+ switch(rh->type)
+ {
+ case TALER_MINT_DB_RO_BANK_TO_MINT:
+ bt = rh->details.bank;
+ if (NULL != bt->wire)
+ json_decref (bt->wire);
+ GNUNET_free (bt);
+ break;
+ case TALER_MINT_DB_RO_WITHDRAW_COIN:
+ cbc = rh->details.withdraw;
+ GNUNET_CRYPTO_rsa_signature_free (cbc->sig.rsa_signature);
+ GNUNET_CRYPTO_rsa_public_key_free (cbc->denom_pub.rsa_public_key);
+ GNUNET_free (cbc);
+ break;
+ }
+ backref = rh;
+ rh = rh->next;
+ GNUNET_free (backref);
+ }
+}
+
+
+/**
+ * Free memory of the link data list.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state (unused)
+ * @param ldl link data list to release
+ */
+static void
+common_free_link_data_list (void *cls,
+ struct LinkDataList *ldl)
+{
+ struct LinkDataList *next;
+
+ while (NULL != ldl)
+ {
+ next = ldl->next;
+ GNUNET_free (ldl->link_data_enc);
+ GNUNET_free (ldl);
+ ldl = next;
+ }
+}
+
+
+/**
+ * Free linked list of transactions.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state (unused)
+ * @param list list to free
+ */
+static void
+common_free_coin_transaction_list (void *cls,
+ struct TALER_MINT_DB_TransactionList *list)
+{
+ struct TALER_MINT_DB_TransactionList *next;
+
+ while (NULL != list)
+ {
+ next = list->next;
+
+ switch (list->type)
+ {
+ case TALER_MINT_DB_TT_DEPOSIT:
+ json_decref (list->details.deposit->wire);
+ GNUNET_free (list->details.deposit);
+ break;
+ case TALER_MINT_DB_TT_REFRESH_MELT:
+ GNUNET_free (list->details.melt);
+ break;
+ case TALER_MINT_DB_TT_LOCK:
+ GNUNET_free (list->details.lock);
+ /* FIXME: look at this again once locking is implemented (#3625) */
+ break;
+ }
+ GNUNET_free (list);
+ list = next;
+ }
+}
+
+/* end of plugin_mintdb_common.c */
diff --git a/src/mint/mint_db.c b/src/mint/plugin_mintdb_postgres.c
index 848f9e045..5a1ff8c0c 100644
--- a/src/mint/mint_db.c
+++ b/src/mint/plugin_mintdb_postgres.c
@@ -15,41 +15,26 @@
*/
/**
- * @file mint_db.c
- * @brief Low-level (statement-level) database access for the mint
+ * @file plugin_mintdb_postgres.c
+ * @brief Low-level (statement-level) Postgres database access for the mint
* @author Florian Dold
* @author Christian Grothoff
* @author Sree Harsha Totakura
- *
- * TODO:
- * - The mint_db.h-API should ideally be what we need to port
- * when using other databases; so here we should enable
- * alternative implementations by returning
- * a more opaque DB handle.
*/
#include "platform.h"
#include "db_pq.h"
#include "taler_signatures.h"
-#include "taler-mint-httpd_responses.h"
-#include "mint_db.h"
+#include "taler_mintdb_plugin.h"
#include <pthread.h>
+#include <libpq-fe.h>
+#include "plugin_mintdb_common.c"
-/**
- * Thread-local database connection.
- * Contains a pointer to PGconn or NULL.
- */
-static pthread_key_t db_conn_threadlocal;
-
+#define TALER_TEMP_SCHEMA_NAME "taler_temporary"
#define QUERY_ERR(result) \
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Query failed at %s:%u: %s\n", __FILE__, __LINE__, PQresultErrorMessage (result))
-/**
- * Database connection string, as read from
- * the configuration.
- */
-static char *TALER_MINT_db_connection_cfg_str;
#define BREAK_DB_ERR(result) do { \
GNUNET_break(0); \
@@ -84,6 +69,41 @@ static char *TALER_MINT_db_connection_cfg_str;
*/
#define TALER_DB_CURRENCY_LEN 3
+
+/**
+ * Handle for a database session (per-thread, for transactions).
+ */
+struct TALER_MINTDB_Session
+{
+ /**
+ * Postgres connection handle.
+ */
+ PGconn *conn;
+};
+
+
+/**
+ * Type of the "cls" argument given to each of the functions in
+ * our API.
+ */
+struct PostgresClosure
+{
+
+ /**
+ * Thread-local database connection.
+ * Contains a pointer to PGconn or NULL.
+ */
+ pthread_key_t db_conn_threadlocal;
+
+ /**
+ * Database connection string, as read from
+ * the configuration.
+ */
+ char *TALER_MINT_db_connection_cfg_str;
+};
+
+
+
/**
* Set the given connection to use a temporary schema
*
@@ -108,14 +128,16 @@ set_temporary_schema (PGconn *db)
/**
* Drop the temporary taler schema. This is only useful for testcases
*
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
*/
-int
-TALER_MINT_DB_drop_temporary (PGconn *db)
+static int
+postgres_drop_temporary (void *cls,
+ struct TALER_MINTDB_Session *session)
{
PGresult *result;
- SQLEXEC_ (db,
+ SQLEXEC_ (session->conn,
"DROP SCHEMA " TALER_TEMP_SCHEMA_NAME " CASCADE;",
result);
return GNUNET_OK;
@@ -127,17 +149,20 @@ TALER_MINT_DB_drop_temporary (PGconn *db)
/**
* Create the necessary tables if they are not present
*
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
* @param temporary should we use a temporary schema
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
*/
-int
-TALER_MINT_DB_create_tables (int temporary)
+static int
+postgres_create_tables (void *cls,
+ int temporary)
{
+ struct PostgresClosure *pc = cls;
PGresult *result;
PGconn *conn;
result = NULL;
- conn = PQconnectdb (TALER_MINT_db_connection_cfg_str);
+ conn = PQconnectdb (pc->TALER_MINT_db_connection_cfg_str);
if (CONNECTION_OK != PQstatus (conn))
{
LOG_ERROR ("Database connection failed: %s\n",
@@ -145,8 +170,8 @@ TALER_MINT_DB_create_tables (int temporary)
GNUNET_break (0);
return GNUNET_SYSERR;
}
- if ((GNUNET_YES == temporary)
- && (GNUNET_SYSERR == set_temporary_schema (conn)))
+ if ( (GNUNET_YES == temporary) &&
+ (GNUNET_SYSERR == set_temporary_schema (conn)))
{
PQfinish (conn);
return GNUNET_SYSERR;
@@ -195,11 +220,11 @@ TALER_MINT_DB_create_tables (int temporary)
",expended_value INT4 NOT NULL"
",expended_fraction INT4 NOT NULL"
",expended_currency VARCHAR(4) NOT NULL"
- ",refresh_session_pub BYTEA"
+ ",refresh_session_hash BYTEA"
")");
SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_sessions "
"("
- " session_pub BYTEA PRIMARY KEY CHECK (length(session_pub) = 32)"
+ " session_hash BYTEA PRIMARY KEY CHECK (length(session_hash) = 32)"
",session_melt_sig BYTEA"
",session_commit_sig BYTEA"
",noreveal_index INT2 NOT NULL"
@@ -209,25 +234,25 @@ TALER_MINT_DB_create_tables (int temporary)
") ");
SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_order "
"( "
- " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub)"
+ " session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash)"
",newcoin_index INT2 NOT NULL "
",denom_pub BYTEA NOT NULL "
- ",PRIMARY KEY (session_pub, newcoin_index)"
+ ",PRIMARY KEY (session_hash, newcoin_index)"
") ");
SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_commit_link"
"("
- " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub)"
+ " session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash)"
",transfer_pub BYTEA NOT NULL"
",link_secret_enc BYTEA NOT NULL"
// index of the old coin in the customer's request
",oldcoin_index INT2 NOT NULL"
// index for cut and choose,
- // ranges from 0 to kappa-1
+ // ranges from 0 to #KAPPA-1
",cnc_index INT2 NOT NULL"
")");
SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_commit_coin"
"("
- " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub) "
+ " session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash) "
",link_vector_enc BYTEA NOT NULL"
// index of the new coin in the customer's request
",newcoin_index INT2 NOT NULL"
@@ -237,32 +262,34 @@ TALER_MINT_DB_create_tables (int temporary)
")");
SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_melt"
"("
- " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub) "
+ " session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash) "
",coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) "
",denom_pub BYTEA NOT NULL "
",oldcoin_index INT2 NOT NULL"
")");
SQLEXEC("CREATE TABLE IF NOT EXISTS refresh_collectable"
"("
- " session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub) "
+ " session_hash BYTEA NOT NULL REFERENCES refresh_sessions (session_hash) "
",ev_sig BYTEA NOT NULL"
",newcoin_index INT2 NOT NULL"
")");
SQLEXEC("CREATE TABLE IF NOT EXISTS deposits "
"( "
" coin_pub BYTEA NOT NULL PRIMARY KEY CHECK (length(coin_pub)=32)"
- ",denom_pub BYTEA NOT NULL CHECK (length(denom_pub)=32)"
+ ",denom_pub BYTEA NOT NULL" /* FIXME: Link this as a foreign key? */
+ ",denom_sig BYTEA NOT NULL"
",transaction_id INT8 NOT NULL"
",amount_currency VARCHAR(4) NOT NULL"
",amount_value INT4 NOT NULL"
",amount_fraction INT4 NOT NULL"
- ",merchant_pub BYTEA NOT NULL"
+ ",merchant_pub BYTEA NOT NULL CHECK (length(merchant_pub)=32)"
",h_contract BYTEA NOT NULL CHECK (length(h_contract)=64)"
",h_wire BYTEA NOT NULL CHECK (length(h_wire)=64)"
",coin_sig BYTEA NOT NULL CHECK (length(coin_sig)=64)"
",wire TEXT NOT NULL"
")");
#undef SQLEXEC
+
PQfinish (conn);
return GNUNET_OK;
@@ -278,8 +305,8 @@ TALER_MINT_DB_create_tables (int temporary)
* @param db_conn connection handle to initialize
* @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
*/
-int
-TALER_MINT_DB_prepare (PGconn *db_conn)
+static int
+postgres_prepare (PGconn *db_conn)
{
PGresult *result;
@@ -366,16 +393,16 @@ TALER_MINT_DB_prepare (PGconn *db_conn)
#if 0
PREPARE ("get_refresh_session",
"SELECT "
- " (SELECT count(*) FROM refresh_melt WHERE session_pub = $1)::INT2 as num_oldcoins "
+ " (SELECT count(*) FROM refresh_melt WHERE session_hash = $1)::INT2 as num_oldcoins "
",(SELECT count(*) FROM refresh_blind_session_keys "
- " WHERE session_pub = $1 and cnc_index = 0)::INT2 as num_newcoins "
+ " WHERE session_hash = $1 and cnc_index = 0)::INT2 as num_newcoins "
",(SELECT count(*) FROM refresh_blind_session_keys "
- " WHERE session_pub = $1 and newcoin_index = 0)::INT2 as kappa "
+ " WHERE session_hash = $1 and newcoin_index = 0)::INT2 as kappa "
",noreveal_index"
",session_commit_sig "
",reveal_ok "
"FROM refresh_sessions "
- "WHERE session_pub = $1",
+ "WHERE session_hash = $1",
1, NULL);
#endif
@@ -383,7 +410,7 @@ TALER_MINT_DB_prepare (PGconn *db_conn)
"SELECT "
" coin_pub, denom_pub, denom_sig "
",expended_value, expended_fraction, expended_currency "
- ",refresh_session_pub "
+ ",refresh_session_hash "
"FROM known_coins "
"WHERE coin_pub = $1",
1, NULL);
@@ -395,7 +422,7 @@ TALER_MINT_DB_prepare (PGconn *db_conn)
",expended_value = $4 "
",expended_fraction = $5 "
",expended_currency = $6 "
- ",refresh_session_pub = $7 "
+ ",refresh_session_hash = $7 "
"WHERE "
" coin_pub = $1 ",
7, NULL);
@@ -407,7 +434,7 @@ TALER_MINT_DB_prepare (PGconn *db_conn)
",expended_value"
",expended_fraction"
",expended_currency"
- ",refresh_session_pub"
+ ",refresh_session_hash"
")"
"VALUES ($1,$2,$3,$4,$5,$6,$7)",
7, NULL);
@@ -416,26 +443,26 @@ TALER_MINT_DB_prepare (PGconn *db_conn)
" transfer_pub "
",link_secret_enc "
"FROM refresh_commit_link "
- "WHERE session_pub = $1 AND cnc_index = $2 AND oldcoin_index = $3",
+ "WHERE session_hash = $1 AND cnc_index = $2 AND oldcoin_index = $3",
3, NULL);
PREPARE ("get_refresh_commit_coin",
"SELECT "
" link_vector_enc "
",coin_ev "
"FROM refresh_commit_coin "
- "WHERE session_pub = $1 AND cnc_index = $2 AND newcoin_index = $3",
+ "WHERE session_hash = $1 AND cnc_index = $2 AND newcoin_index = $3",
3, NULL);
PREPARE ("insert_refresh_order",
"INSERT INTO refresh_order ( "
" newcoin_index "
- ",session_pub "
+ ",session_hash "
",denom_pub "
") "
"VALUES ($1, $2, $3) ",
3, NULL);
PREPARE ("insert_refresh_melt",
"INSERT INTO refresh_melt ( "
- " session_pub "
+ " session_hash "
",oldcoin_index "
",coin_pub "
",denom_pub "
@@ -445,28 +472,28 @@ TALER_MINT_DB_prepare (PGconn *db_conn)
PREPARE ("get_refresh_order",
"SELECT denom_pub "
"FROM refresh_order "
- "WHERE session_pub = $1 AND newcoin_index = $2",
+ "WHERE session_hash = $1 AND newcoin_index = $2",
2, NULL);
PREPARE ("get_refresh_collectable",
"SELECT ev_sig "
"FROM refresh_collectable "
- "WHERE session_pub = $1 AND newcoin_index = $2",
+ "WHERE session_hash = $1 AND newcoin_index = $2",
2, NULL);
PREPARE ("get_refresh_melt",
"SELECT coin_pub "
"FROM refresh_melt "
- "WHERE session_pub = $1 AND oldcoin_index = $2",
+ "WHERE session_hash = $1 AND oldcoin_index = $2",
2, NULL);
PREPARE ("insert_refresh_session",
"INSERT INTO refresh_sessions ( "
- " session_pub "
+ " session_hash "
",noreveal_index "
") "
"VALUES ($1, $2) ",
2, NULL);
PREPARE ("insert_refresh_commit_link",
"INSERT INTO refresh_commit_link ( "
- " session_pub "
+ " session_hash "
",transfer_pub "
",cnc_index "
",oldcoin_index "
@@ -476,7 +503,7 @@ TALER_MINT_DB_prepare (PGconn *db_conn)
5, NULL);
PREPARE ("insert_refresh_commit_coin",
"INSERT INTO refresh_commit_coin ( "
- " session_pub "
+ " session_hash "
",coin_ev "
",cnc_index "
",newcoin_index "
@@ -486,7 +513,7 @@ TALER_MINT_DB_prepare (PGconn *db_conn)
5, NULL);
PREPARE ("insert_refresh_collectable",
"INSERT INTO refresh_collectable ( "
- " session_pub "
+ " session_hash "
",newcoin_index "
",ev_sig "
") "
@@ -495,39 +522,40 @@ TALER_MINT_DB_prepare (PGconn *db_conn)
PREPARE ("set_reveal_ok",
"UPDATE refresh_sessions "
"SET reveal_ok = TRUE "
- "WHERE session_pub = $1 ",
+ "WHERE session_hash = $1 ",
1, NULL);
PREPARE ("get_link",
"SELECT link_vector_enc, ro.denom_pub, ev_sig "
"FROM refresh_melt rm "
- " JOIN refresh_order ro USING (session_pub) "
- " JOIN refresh_commit_coin rcc USING (session_pub) "
- " JOIN refresh_sessions rs USING (session_pub) "
- " JOIN refresh_collectable rc USING (session_pub) "
+ " JOIN refresh_order ro USING (session_hash) "
+ " JOIN refresh_commit_coin rcc USING (session_hash) "
+ " JOIN refresh_sessions rs USING (session_hash) "
+ " JOIN refresh_collectable rc USING (session_hash) "
"WHERE rm.coin_pub = $1 "
"AND ro.newcoin_index = rcc.newcoin_index "
"AND ro.newcoin_index = rc.newcoin_index "
"AND rcc.cnc_index = rs.noreveal_index % ( "
" SELECT count(*) FROM refresh_commit_coin rcc2 "
- " WHERE rcc2.newcoin_index = 0 AND rcc2.session_pub = rs.session_pub "
+ " WHERE rcc2.newcoin_index = 0 AND rcc2.session_hash = rs.session_hash "
" ) ",
1, NULL);
PREPARE ("get_transfer",
"SELECT transfer_pub, link_secret_enc "
"FROM refresh_melt rm "
- " JOIN refresh_commit_link rcl USING (session_pub) "
- " JOIN refresh_sessions rs USING (session_pub) "
+ " JOIN refresh_commit_link rcl USING (session_hash) "
+ " JOIN refresh_sessions rs USING (session_hash) "
"WHERE rm.coin_pub = $1 "
"AND rm.oldcoin_index = rcl.oldcoin_index "
"AND rcl.cnc_index = rs.noreveal_index % ( "
" SELECT count(*) FROM refresh_commit_coin rcc2 "
- " WHERE newcoin_index = 0 AND rcc2.session_pub = rm.session_pub "
+ " WHERE newcoin_index = 0 AND rcc2.session_hash = rm.session_hash "
" ) ",
1, NULL);
PREPARE ("insert_deposit",
"INSERT INTO deposits ("
"coin_pub,"
"denom_pub,"
+ "denom_sig,"
"transaction_id,"
"amount_value,"
"amount_fraction,"
@@ -538,9 +566,9 @@ TALER_MINT_DB_prepare (PGconn *db_conn)
"coin_sig,"
"wire"
") VALUES ("
- "$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11"
+ "$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12"
")",
- 11, NULL);
+ 12, NULL);
PREPARE ("get_deposit",
"SELECT "
"coin_pub,"
@@ -554,9 +582,11 @@ TALER_MINT_DB_prepare (PGconn *db_conn)
"h_wire,"
"coin_sig"
" FROM deposits WHERE ("
- "coin_pub = $1"
+ "(coin_pub = $1) AND"
+ "(transaction_id = $2) AND"
+ "(merchant_pub = $3)"
")",
- 1, NULL);
+ 3, NULL);
return GNUNET_OK;
#undef PREPARE
}
@@ -578,41 +608,25 @@ db_conn_destroy (void *cls)
/**
- * Initialize database subsystem.
- *
- * @param connection_cfg configuration to use to talk to DB
- * @return #GNUNET_OK on success
- */
-int
-TALER_MINT_DB_init (const char *connection_cfg)
-{
- if (0 != pthread_key_create (&db_conn_threadlocal,
- &db_conn_destroy))
- {
- LOG_ERROR ("Cannnot create pthread key.\n");
- return GNUNET_SYSERR;
- }
- TALER_MINT_db_connection_cfg_str = GNUNET_strdup (connection_cfg);
- return GNUNET_OK;
-}
-
-
-/**
* Get the thread-local database-handle.
* Connect to the db if the connection does not exist yet.
*
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
* @param temporary #GNUNET_YES to use a temporary schema; #GNUNET_NO to use the
* database default one
* @return the database connection, or NULL on error
*/
-PGconn *
-TALER_MINT_DB_get_connection (int temporary)
+static struct TALER_MINTDB_Session *
+postgres_get_session (void *cls,
+ int temporary)
{
+ struct PostgresClosure *pc = cls;
PGconn *db_conn;
+ struct TALER_MINTDB_Session *session;
- if (NULL != (db_conn = pthread_getspecific (db_conn_threadlocal)))
- return db_conn;
- db_conn = PQconnectdb (TALER_MINT_db_connection_cfg_str);
+ if (NULL != (session = pthread_getspecific (pc->db_conn_threadlocal)))
+ return session;
+ db_conn = PQconnectdb (pc->TALER_MINT_db_connection_cfg_str);
if (CONNECTION_OK !=
PQstatus (db_conn))
{
@@ -628,33 +642,39 @@ TALER_MINT_DB_get_connection (int temporary)
return NULL;
}
if (GNUNET_OK !=
- TALER_MINT_DB_prepare (db_conn))
+ postgres_prepare (db_conn))
{
GNUNET_break (0);
return NULL;
}
- if (0 != pthread_setspecific (db_conn_threadlocal,
- db_conn))
+ session = GNUNET_new (struct TALER_MINTDB_Session);
+ session->conn = db_conn;
+ if (0 != pthread_setspecific (pc->db_conn_threadlocal,
+ session))
{
GNUNET_break (0);
+ // FIXME: close db_conn!
+ GNUNET_free (session);
return NULL;
}
- return db_conn;
+ return session;
}
/**
* Start a transaction.
*
- * @param db_conn the database connection
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session the database connection
* @return #GNUNET_OK on success
*/
-int
-TALER_MINT_DB_transaction (PGconn *db_conn)
+static int
+postgres_start (void *cls,
+ struct TALER_MINTDB_Session *session)
{
PGresult *result;
- result = PQexec (db_conn,
+ result = PQexec (session->conn,
"BEGIN");
if (PGRES_COMMAND_OK !=
PQresultStatus (result))
@@ -674,15 +694,17 @@ TALER_MINT_DB_transaction (PGconn *db_conn)
/**
* Roll back the current transaction of a database connection.
*
- * @param db_conn the database connection
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session the database connection
* @return #GNUNET_OK on success
*/
-void
-TALER_MINT_DB_rollback (PGconn *db_conn)
+static void
+postgres_rollback (void *cls,
+ struct TALER_MINTDB_Session *session)
{
PGresult *result;
- result = PQexec (db_conn,
+ result = PQexec (session->conn,
"ROLLBACK");
GNUNET_break (PGRES_COMMAND_OK ==
PQresultStatus (result));
@@ -693,15 +715,17 @@ TALER_MINT_DB_rollback (PGconn *db_conn)
/**
* Commit the current transaction of a database connection.
*
- * @param db_conn the database connection
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session the database connection
* @return #GNUNET_OK on success
*/
-int
-TALER_MINT_DB_commit (PGconn *db_conn)
+static int
+postgres_commit (void *cls,
+ struct TALER_MINTDB_Session *session)
{
PGresult *result;
- result = PQexec (db_conn,
+ result = PQexec (session->conn,
"COMMIT");
if (PGRES_COMMAND_OK !=
PQresultStatus (result))
@@ -719,29 +743,26 @@ TALER_MINT_DB_commit (PGconn *db_conn)
/**
* Get the summary of a reserve.
*
- * @param db the database connection handle
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session the database connection handle
* @param reserve the reserve data. The public key of the reserve should be set
* in this structure; it is used to query the database. The balance
* and expiration are then filled accordingly.
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
*/
-int
-TALER_MINT_DB_reserve_get (PGconn *db,
- struct Reserve *reserve)
+static int
+postgres_reserve_get (void *cls,
+ struct TALER_MINTDB_Session *session,
+ struct Reserve *reserve)
{
PGresult *result;
uint64_t expiration_date_nbo;
struct TALER_DB_QueryParam params[] = {
- TALER_DB_QUERY_PARAM_PTR(reserve->pub),
+ TALER_DB_QUERY_PARAM_PTR(&reserve->pub),
TALER_DB_QUERY_PARAM_END
};
- if (NULL == reserve->pub)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- result = TALER_DB_exec_prepared (db,
+ result = TALER_DB_exec_prepared (session->conn,
"get_reserve",
params);
if (PGRES_TUPLES_OK != PQresultStatus (result))
@@ -779,33 +800,36 @@ TALER_MINT_DB_reserve_get (PGconn *db,
/**
* Updates a reserve with the data from the given reserve structure.
*
- * @param db the database connection
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session the database connection
* @param reserve the reserve structure whose data will be used to update the
* corresponding record in the database.
* @return #GNUNET_OK upon successful update; #GNUNET_SYSERR upon any error
*/
-int
-reserves_update (PGconn *db,
- struct Reserve *reserve)
+static int
+postgres_reserves_update (void *cls,
+ struct TALER_MINTDB_Session *session,
+ struct Reserve *reserve)
{
PGresult *result;
struct TALER_AmountNBO balance_nbo;
struct GNUNET_TIME_AbsoluteNBO expiry_nbo;
int ret;
- if ((NULL == reserve) || (NULL == reserve->pub))
+ if (NULL == reserve)
return GNUNET_SYSERR;
ret = GNUNET_OK;
struct TALER_DB_QueryParam params[] = {
- TALER_DB_QUERY_PARAM_PTR (reserve->pub),
+ TALER_DB_QUERY_PARAM_PTR (&reserve->pub),
TALER_DB_QUERY_PARAM_PTR (&balance_nbo.value),
TALER_DB_QUERY_PARAM_PTR (&balance_nbo.fraction),
TALER_DB_QUERY_PARAM_PTR (&expiry_nbo),
TALER_DB_QUERY_PARAM_END
};
- balance_nbo = TALER_amount_hton (reserve->balance);
+ TALER_amount_hton (&balance_nbo,
+ &reserve->balance);
expiry_nbo = GNUNET_TIME_absolute_hton (reserve->expiry);
- result = TALER_DB_exec_prepared (db,
+ result = TALER_DB_exec_prepared (session->conn,
"update_reserve",
params);
if (PGRES_COMMAND_OK != PQresultStatus(result))
@@ -822,7 +846,8 @@ reserves_update (PGconn *db,
* Insert a incoming transaction into reserves. New reserves are also created
* through this function.
*
- * @param db the database connection handle
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session the database connection handle
* @param reserve the reserve structure. The public key of the reserve should
* be set here. Upon successful execution of this function, the
* balance and expiration of the reserve will be updated.
@@ -830,11 +855,12 @@ reserves_update (PGconn *db,
* @param expiry the new expiration time for the reserve
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failures
*/
-int
-TALER_MINT_DB_reserves_in_insert (PGconn *db,
- struct Reserve *reserve,
- const struct TALER_Amount balance,
- const struct GNUNET_TIME_Absolute expiry)
+static int
+postgres_reserves_in_insert (void *cls,
+ struct TALER_MINTDB_Session *session,
+ struct Reserve *reserve,
+ const struct TALER_Amount *balance,
+ const struct GNUNET_TIME_Absolute expiry)
{
struct TALER_AmountNBO balance_nbo;
struct GNUNET_TIME_AbsoluteNBO expiry_nbo;
@@ -847,25 +873,30 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db,
GNUNET_break (0);
return GNUNET_SYSERR;
}
- if (GNUNET_OK != TALER_MINT_DB_transaction (db))
+ if (GNUNET_OK != postgres_start (cls,
+ session))
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
- reserve_exists = TALER_MINT_DB_reserve_get (db, reserve);
+ reserve_exists = postgres_reserve_get (cls,
+ session,
+ reserve);
if (GNUNET_SYSERR == reserve_exists)
{
- TALER_MINT_DB_rollback (db);
+ postgres_rollback (cls,
+ session);
return GNUNET_SYSERR;
}
- balance_nbo = TALER_amount_hton (balance);
+ TALER_amount_hton (&balance_nbo,
+ balance);
expiry_nbo = GNUNET_TIME_absolute_hton (expiry);
if (GNUNET_NO == reserve_exists)
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Reserve does not exist; creating a new one\n");
struct TALER_DB_QueryParam params[] = {
- TALER_DB_QUERY_PARAM_PTR (reserve->pub),
+ TALER_DB_QUERY_PARAM_PTR (&reserve->pub),
TALER_DB_QUERY_PARAM_PTR (&balance_nbo.value),
TALER_DB_QUERY_PARAM_PTR (&balance_nbo.fraction),
TALER_DB_QUERY_PARAM_PTR_SIZED (balance_nbo.currency,
@@ -873,7 +904,7 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db,
TALER_DB_QUERY_PARAM_PTR (&expiry_nbo),
TALER_DB_QUERY_PARAM_END
};
- result = TALER_DB_exec_prepared (db,
+ result = TALER_DB_exec_prepared (session->conn,
"create_reserve",
params);
if (PGRES_COMMAND_OK != PQresultStatus(result))
@@ -887,7 +918,7 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db,
result = NULL;
/* create new incoming transaction */
struct TALER_DB_QueryParam params[] = {
- TALER_DB_QUERY_PARAM_PTR (reserve->pub),
+ TALER_DB_QUERY_PARAM_PTR (&reserve->pub),
TALER_DB_QUERY_PARAM_PTR (&balance_nbo.value),
TALER_DB_QUERY_PARAM_PTR (&balance_nbo.fraction),
TALER_DB_QUERY_PARAM_PTR_SIZED (&balance_nbo.currency,
@@ -895,7 +926,7 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db,
TALER_DB_QUERY_PARAM_PTR (&expiry_nbo),
TALER_DB_QUERY_PARAM_END
};
- result = TALER_DB_exec_prepared (db,
+ result = TALER_DB_exec_prepared (session->conn,
"create_reserves_in_transaction",
params);
if (PGRES_COMMAND_OK != PQresultStatus(result))
@@ -903,23 +934,35 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db,
QUERY_ERR (result);
goto rollback;
}
- PQclear (result); result = NULL;
+ PQclear (result);
+ result = NULL;
if (GNUNET_NO == reserve_exists)
{
- if (GNUNET_OK != TALER_MINT_DB_commit (db))
+ if (GNUNET_OK != postgres_commit (cls,
+ session))
return GNUNET_SYSERR;
- reserve->balance = balance;
+ reserve->balance = *balance;
reserve->expiry = expiry;
return GNUNET_OK;
}
/* Update reserve */
struct Reserve updated_reserve;
updated_reserve.pub = reserve->pub;
- updated_reserve.balance = TALER_amount_add (reserve->balance, balance);
+
+ if (GNUNET_OK !=
+ TALER_amount_add (&updated_reserve.balance,
+ &reserve->balance,
+ balance))
+ {
+ return GNUNET_SYSERR;
+ }
updated_reserve.expiry = GNUNET_TIME_absolute_max (expiry, reserve->expiry);
- if (GNUNET_OK != reserves_update (db, &updated_reserve))
+ if (GNUNET_OK != postgres_reserves_update (cls,
+ session,
+ &updated_reserve))
goto rollback;
- if (GNUNET_OK != TALER_MINT_DB_commit (db))
+ if (GNUNET_OK != postgres_commit (cls,
+ session))
return GNUNET_SYSERR;
reserve->balance = updated_reserve.balance;
reserve->expiry = updated_reserve.expiry;
@@ -927,7 +970,8 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db,
rollback:
PQclear (result);
- TALER_MINT_DB_rollback (db);
+ postgres_rollback (cls,
+ session);
return GNUNET_SYSERR;
}
@@ -936,7 +980,8 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db,
* Locate the response for a /withdraw request under the
* key of the hash of the blinded message.
*
- * @param db_conn database connection to use
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection to use
* @param h_blind hash of the blinded message
* @param collectable corresponding collectable coin (blind signature)
* if a coin is found
@@ -944,10 +989,11 @@ TALER_MINT_DB_reserves_in_insert (PGconn *db,
* #GNUNET_NO if the collectable was not found
* #GNUNET_YES on success
*/
-int
-TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn,
- const struct GNUNET_HashCode *h_blind,
- struct CollectableBlindcoin *collectable)
+static int
+postgres_get_collectable_blindcoin (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_HashCode *h_blind,
+ struct CollectableBlindcoin *collectable)
{
PGresult *result;
struct TALER_DB_QueryParam params[] = {
@@ -966,7 +1012,7 @@ TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn,
denom_pub = NULL;
denom_pub_enc = NULL;
denom_sig_enc = NULL;
- result = TALER_DB_exec_prepared (db_conn,
+ result = TALER_DB_exec_prepared (session->conn,
"get_collectable_blindcoin",
params);
@@ -1002,8 +1048,8 @@ TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn,
GNUNET_break (0);
goto cleanup;
}
- collectable->denom_pub = denom_pub;
- collectable->sig = denom_sig;
+ collectable->denom_pub.rsa_public_key = denom_pub;
+ collectable->sig.rsa_signature = denom_sig;
ret = GNUNET_YES;
cleanup:
@@ -1024,20 +1070,26 @@ TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn,
* Store collectable bit coin under the corresponding
* hash of the blinded message.
*
- * @param db_conn database connection to use
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection to use
* @param h_blind hash of the blinded message
+ * @param withdraw amount by which the reserve will be withdrawn with this
+ * transaction
* @param collectable corresponding collectable coin (blind signature)
* if a coin is found
* @return #GNUNET_SYSERR on internal error
* #GNUNET_NO if the collectable was not found
* #GNUNET_YES on success
*/
-int
-TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn,
- const struct GNUNET_HashCode *h_blind,
- const struct CollectableBlindcoin *collectable)
+static int
+postgres_insert_collectable_blindcoin (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_HashCode *h_blind,
+ struct TALER_Amount withdraw,
+ const struct CollectableBlindcoin *collectable)
{
PGresult *result;
+ struct Reserve reserve;
char *denom_pub_enc = NULL;
char *denom_sig_enc = NULL;
size_t denom_pub_enc_size;
@@ -1046,10 +1098,11 @@ TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn,
ret = GNUNET_SYSERR;
denom_pub_enc_size =
- GNUNET_CRYPTO_rsa_public_key_encode (collectable->denom_pub,
+ GNUNET_CRYPTO_rsa_public_key_encode (collectable->denom_pub.rsa_public_key,
&denom_pub_enc);
denom_sig_enc_size =
- GNUNET_CRYPTO_rsa_signature_encode (collectable->sig, &denom_sig_enc);
+ GNUNET_CRYPTO_rsa_signature_encode (collectable->sig.rsa_signature,
+ &denom_sig_enc);
struct TALER_DB_QueryParam params[] = {
TALER_DB_QUERY_PARAM_PTR (h_blind),
TALER_DB_QUERY_PARAM_PTR_SIZED (denom_pub_enc, denom_pub_enc_size - 1),
@@ -1058,16 +1111,41 @@ TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn,
TALER_DB_QUERY_PARAM_PTR (&collectable->reserve_sig),
TALER_DB_QUERY_PARAM_END
};
- result = TALER_DB_exec_prepared (db_conn,
+ if (GNUNET_OK != postgres_start (cls,
+ session))
+ goto cleanup;
+ result = TALER_DB_exec_prepared (session->conn,
"insert_collectable_blindcoin",
params);
if (PGRES_COMMAND_OK != PQresultStatus (result))
{
QUERY_ERR (result);
+ goto rollback;
+ }
+ reserve.pub = collectable->reserve_pub;
+ if (GNUNET_OK != postgres_reserve_get (cls,
+ session,
+ &reserve))
+ goto rollback;
+ if (GNUNET_SYSERR ==
+ TALER_amount_subtract (&reserve.balance,
+ &reserve.balance,
+ &withdraw))
+ goto rollback;
+ if (GNUNET_OK != postgres_reserves_update (cls,
+ session,
+ &reserve))
+ goto rollback;
+ if (GNUNET_OK == postgres_commit (cls,
+ session))
+ {
+ ret = GNUNET_OK;
goto cleanup;
}
- ret = GNUNET_OK;
+ rollback:
+ postgres_rollback (cls,
+ session);
cleanup:
PQclear (result);
GNUNET_free_non_null (denom_pub_enc);
@@ -1080,13 +1158,15 @@ TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn,
* Get all of the transaction history associated with the specified
* reserve.
*
- * @param db_conn connection to use
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session connection to use
* @param reserve_pub public key of the reserve
* @return known transaction history (NULL if reserve is unknown)
*/
-struct ReserveHistory *
-TALER_MINT_DB_get_reserve_history (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub)
+static struct ReserveHistory *
+postgres_get_reserve_history (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct TALER_ReservePublicKey *reserve_pub)
{
PGresult *result;
struct ReserveHistory *rh;
@@ -1105,7 +1185,7 @@ TALER_MINT_DB_get_reserve_history (PGconn *db_conn,
TALER_DB_QUERY_PARAM_END
};
- result = TALER_DB_exec_prepared (db_conn,
+ result = TALER_DB_exec_prepared (session->conn,
"get_reserves_in_transactions",
params);
if (PGRES_TUPLES_OK != PQresultStatus (result))
@@ -1133,7 +1213,7 @@ TALER_MINT_DB_get_reserve_history (PGconn *db_conn,
GNUNET_break (0);
goto cleanup;
}
- (void) memcpy (&bt->reserve_pub, reserve_pub, sizeof (bt->reserve_pub));
+ bt->reserve_pub = *reserve_pub;
if (NULL != rh_head)
{
rh_head->next = GNUNET_new (struct ReserveHistory);
@@ -1152,7 +1232,7 @@ TALER_MINT_DB_get_reserve_history (PGconn *db_conn,
result = NULL;
{
struct GNUNET_HashCode blind_ev;
- struct GNUNET_CRYPTO_EddsaSignature reserve_sig;
+ struct TALER_ReserveSignature reserve_sig;
struct CollectableBlindcoin *cbc;
char *denom_pub_enc;
char *denom_sig_enc;
@@ -1163,7 +1243,7 @@ TALER_MINT_DB_get_reserve_history (PGconn *db_conn,
TALER_DB_QUERY_PARAM_PTR (reserve_pub),
TALER_DB_QUERY_PARAM_END
};
- result = TALER_DB_exec_prepared (db_conn,
+ result = TALER_DB_exec_prepared (session->conn,
"get_reserves_blindcoins",
params);
if (PGRES_TUPLES_OK != PQresultStatus (result))
@@ -1194,20 +1274,23 @@ TALER_MINT_DB_get_reserve_history (PGconn *db_conn,
goto cleanup;
}
cbc = GNUNET_new (struct CollectableBlindcoin);
- cbc->sig = GNUNET_CRYPTO_rsa_signature_decode (denom_sig_enc,
- denom_sig_enc_size);
+ cbc->sig.rsa_signature
+ = GNUNET_CRYPTO_rsa_signature_decode (denom_sig_enc,
+ denom_sig_enc_size);
GNUNET_free (denom_sig_enc);
denom_sig_enc = NULL;
- cbc->denom_pub = GNUNET_CRYPTO_rsa_public_key_decode (denom_pub_enc,
- denom_pub_enc_size);
+ cbc->denom_pub.rsa_public_key
+ = GNUNET_CRYPTO_rsa_public_key_decode (denom_pub_enc,
+ denom_pub_enc_size);
GNUNET_free (denom_pub_enc);
denom_pub_enc = NULL;
- if ((NULL == cbc->sig) || (NULL == cbc->denom_pub))
+ if ( (NULL == cbc->sig.rsa_signature) ||
+ (NULL == cbc->denom_pub.rsa_public_key) )
{
- if (NULL != cbc->sig)
- GNUNET_CRYPTO_rsa_signature_free (cbc->sig);
- if (NULL != cbc->denom_pub)
- GNUNET_CRYPTO_rsa_public_key_free (cbc->denom_pub);
+ if (NULL != cbc->sig.rsa_signature)
+ GNUNET_CRYPTO_rsa_signature_free (cbc->sig.rsa_signature);
+ if (NULL != cbc->denom_pub.rsa_public_key)
+ GNUNET_CRYPTO_rsa_public_key_free (cbc->denom_pub.rsa_public_key);
GNUNET_free (cbc);
GNUNET_break (0);
goto cleanup;
@@ -1228,7 +1311,8 @@ TALER_MINT_DB_get_reserve_history (PGconn *db_conn,
PQclear (result);
if (GNUNET_SYSERR == ret)
{
- TALER_MINT_DB_free_reserve_history (rh);
+ common_free_reserve_history (cls,
+ rh);
rh = NULL;
}
return rh;
@@ -1236,77 +1320,49 @@ TALER_MINT_DB_get_reserve_history (PGconn *db_conn,
/**
- * Free memory associated with the given reserve history.
- *
- * @param rh history to free.
- */
-void
-TALER_MINT_DB_free_reserve_history (struct ReserveHistory *rh)
-{
- struct BankTransfer *bt;
- struct CollectableBlindcoin *cbc;
- struct ReserveHistory *backref;
-
- while (NULL != rh)
- {
- switch(rh->type)
- {
- case TALER_MINT_DB_RO_BANK_TO_MINT:
- bt = rh->details.bank;
- if (NULL != bt->wire)
- json_decref ((json_t *) bt->wire); /* FIXME: avoid cast? */
- GNUNET_free (bt);
- break;
- case TALER_MINT_DB_RO_WITHDRAW_COIN:
- cbc = rh->details.withdraw;
- GNUNET_CRYPTO_rsa_signature_free (cbc->sig);
- GNUNET_CRYPTO_rsa_public_key_free (cbc->denom_pub);
- GNUNET_free (cbc);
- break;
- }
- backref = rh;
- rh = rh->next;
- GNUNET_free (backref);
- }
-}
-
-
-/**
* Check if we have the specified deposit already in the database.
*
- * @param db_conn database connection
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @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
*/
-int
-TALER_MINT_DB_have_deposit (PGconn *db_conn,
- const struct Deposit *deposit)
+static int
+postgres_have_deposit (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct Deposit *deposit)
{
- // FIXME: check logic!
struct TALER_DB_QueryParam params[] = {
- TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub), // FIXME
+ TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub),
+ TALER_DB_QUERY_PARAM_PTR (&deposit->transaction_id),
+ TALER_DB_QUERY_PARAM_PTR (&deposit->merchant_pub),
TALER_DB_QUERY_PARAM_END
};
PGresult *result;
+ int ret;
- result = TALER_DB_exec_prepared (db_conn,
+ ret = GNUNET_SYSERR;
+ result = TALER_DB_exec_prepared (session->conn,
"get_deposit",
params);
if (PGRES_TUPLES_OK !=
PQresultStatus (result))
{
BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
+ goto cleanup;
}
if (0 == PQntuples (result))
{
- PQclear (result);
- return GNUNET_NO;
+ ret = GNUNET_NO;
+ goto cleanup;
}
- return GNUNET_YES;
+ ret = GNUNET_YES;
+
+ cleanup:
+ PQclear (result);
+ return ret;
}
@@ -1314,69 +1370,96 @@ TALER_MINT_DB_have_deposit (PGconn *db_conn,
* Insert information about deposited coin into the
* database.
*
- * @param db_conn connection to the database
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session connection to the database
* @param deposit deposit information to store
* @return #GNUNET_OK on success, #GNUNET_SYSERR on error
*/
-int
-TALER_MINT_DB_insert_deposit (PGconn *db_conn,
- const struct Deposit *deposit)
+static int
+postgres_insert_deposit (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct Deposit *deposit)
{
- // FIXME: check logic!
+ char *denom_pub_enc;
+ char *denom_sig_enc;
+ char *json_wire_enc;
+ PGresult *result;
+ struct TALER_AmountNBO amount_nbo;
+ size_t denom_pub_enc_size;
+ size_t denom_sig_enc_size;
+ int ret;
+
+ ret = GNUNET_SYSERR;
+ denom_pub_enc_size =
+ GNUNET_CRYPTO_rsa_public_key_encode (deposit->coin.denom_pub.rsa_public_key,
+ &denom_pub_enc);
+ denom_sig_enc_size =
+ GNUNET_CRYPTO_rsa_signature_encode (deposit->coin.denom_sig.rsa_signature,
+ &denom_sig_enc);
+ json_wire_enc = json_dumps (deposit->wire, JSON_COMPACT);
+ TALER_amount_hton (&amount_nbo,
+ &deposit->amount_with_fee);
struct TALER_DB_QueryParam params[]= {
TALER_DB_QUERY_PARAM_PTR (&deposit->coin.coin_pub),
- TALER_DB_QUERY_PARAM_PTR (&deposit->coin.denom_pub), // FIXME!
- TALER_DB_QUERY_PARAM_PTR (&deposit->coin.denom_sig), // FIXME!
+ TALER_DB_QUERY_PARAM_PTR_SIZED (denom_pub_enc, denom_pub_enc_size),
+ TALER_DB_QUERY_PARAM_PTR_SIZED (denom_sig_enc, denom_sig_enc_size),
TALER_DB_QUERY_PARAM_PTR (&deposit->transaction_id),
- TALER_DB_QUERY_PARAM_PTR (&deposit->amount.value),
- TALER_DB_QUERY_PARAM_PTR (&deposit->amount.fraction),
- TALER_DB_QUERY_PARAM_PTR_SIZED (deposit->amount.currency,
- strlen (deposit->amount.currency)),
+ TALER_DB_QUERY_PARAM_PTR (&amount_nbo.value),
+ TALER_DB_QUERY_PARAM_PTR (&amount_nbo.fraction),
+ TALER_DB_QUERY_PARAM_PTR_SIZED (amount_nbo.currency,
+ TALER_CURRENCY_LEN - 1),
TALER_DB_QUERY_PARAM_PTR (&deposit->merchant_pub),
TALER_DB_QUERY_PARAM_PTR (&deposit->h_contract),
TALER_DB_QUERY_PARAM_PTR (&deposit->h_wire),
TALER_DB_QUERY_PARAM_PTR (&deposit->csig),
- TALER_DB_QUERY_PARAM_PTR_SIZED (deposit->wire,
- strlen ("FIXME")), // FIXME! json!
+ TALER_DB_QUERY_PARAM_PTR_SIZED (json_wire_enc,
+ strlen (json_wire_enc)),
TALER_DB_QUERY_PARAM_END
};
- PGresult *result;
-
- result = TALER_DB_exec_prepared (db_conn, "insert_deposit", params);
+ result = TALER_DB_exec_prepared (session->conn, "insert_deposit", params);
if (PGRES_COMMAND_OK != PQresultStatus (result))
{
BREAK_DB_ERR (result);
- PQclear (result);
- return GNUNET_SYSERR;
+ goto cleanup;
}
+ ret = GNUNET_OK;
+
+ cleanup:
PQclear (result);
- return GNUNET_OK;
+ GNUNET_free_non_null (denom_pub_enc);
+ GNUNET_free_non_null (denom_sig_enc);
+ GNUNET_free_non_null (json_wire_enc);
+ return ret;
}
/**
- * Lookup refresh session data under the given public key.
+ * Lookup refresh session data under the given @a session_hash.
*
- * @param db_conn database handle to use
- * @param refresh_session_pub public key to use for the lookup
- * @param session[OUT] where to store the result
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database handle to use
+ * @param session_hash hash over the melt to use to locate the session
+ * @param refresh_session[OUT] where to store the result
* @return #GNUNET_YES on success,
* #GNUNET_NO if not found,
* #GNUNET_SYSERR on DB failure
*/
-int
-TALER_MINT_DB_get_refresh_session (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- struct RefreshSession *session)
+static int
+postgres_get_refresh_session (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ struct RefreshSession *refresh_session)
{
// FIXME: check logic!
int res;
struct TALER_DB_QueryParam params[] = {
- TALER_DB_QUERY_PARAM_PTR(refresh_session_pub),
+ TALER_DB_QUERY_PARAM_PTR(session_hash),
TALER_DB_QUERY_PARAM_END
};
- PGresult *result = TALER_DB_exec_prepared (db_conn, "get_refresh_session", params);
+ PGresult *result = TALER_DB_exec_prepared (session->conn,
+ "get_refresh_session",
+ params);
if (PGRES_TUPLES_OK != PQresultStatus (result))
{
@@ -1395,16 +1478,15 @@ TALER_MINT_DB_get_refresh_session (PGconn *db_conn,
/* We're done if the caller is only interested in
* whether the session exists or not */
- if (NULL == session)
+ if (NULL == refresh_session)
return GNUNET_YES;
memset (session, 0, sizeof (struct RefreshSession));
struct TALER_DB_ResultSpec rs[] = {
- TALER_DB_RESULT_SPEC("num_oldcoins", &session->num_oldcoins),
- TALER_DB_RESULT_SPEC("num_newcoins", &session->num_newcoins),
- TALER_DB_RESULT_SPEC("kappa", &session->kappa),
- TALER_DB_RESULT_SPEC("noreveal_index", &session->noreveal_index),
+ TALER_DB_RESULT_SPEC("num_oldcoins", &refresh_session->num_oldcoins),
+ TALER_DB_RESULT_SPEC("num_newcoins", &refresh_session->num_newcoins),
+ TALER_DB_RESULT_SPEC("noreveal_index", &refresh_session->noreveal_index),
TALER_DB_RESULT_SPEC_END
};
@@ -1417,10 +1499,9 @@ TALER_MINT_DB_get_refresh_session (PGconn *db_conn,
return GNUNET_SYSERR;
}
- session->num_oldcoins = ntohs (session->num_oldcoins);
- session->num_newcoins = ntohs (session->num_newcoins);
- session->kappa = ntohs (session->kappa);
- session->noreveal_index = ntohs (session->noreveal_index);
+ refresh_session->num_oldcoins = ntohs (refresh_session->num_oldcoins);
+ refresh_session->num_newcoins = ntohs (refresh_session->num_newcoins);
+ refresh_session->noreveal_index = ntohs (refresh_session->noreveal_index);
PQclear (result);
return GNUNET_YES;
@@ -1428,23 +1509,25 @@ TALER_MINT_DB_get_refresh_session (PGconn *db_conn,
/**
- * Store new refresh session data under the given public key.
+ * Store new refresh session data under the given @a session_hash.
*
- * @param db_conn database handle to use
- * @param refresh_session_pub public key to use to locate the session
- * @param session session data to store
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database handle to use
+ * @param session_hash hash over the melt to use to locate the session
+ * @param refresh_session session data to store
* @return #GNUNET_YES on success,
* #GNUNET_SYSERR on DB failure
*/
-int
-TALER_MINT_DB_create_refresh_session (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
- const struct RefreshSession *session)
+static int
+postgres_create_refresh_session (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ const struct RefreshSession *refresh_session)
{
// FIXME: actually store session data!
uint16_t noreveal_index;
struct TALER_DB_QueryParam params[] = {
- TALER_DB_QUERY_PARAM_PTR(session_pub),
+ TALER_DB_QUERY_PARAM_PTR(session_hash),
TALER_DB_QUERY_PARAM_PTR(&noreveal_index),
TALER_DB_QUERY_PARAM_END
};
@@ -1452,7 +1535,9 @@ TALER_MINT_DB_create_refresh_session (PGconn *db_conn,
noreveal_index = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1<<15);
noreveal_index = htonl (noreveal_index);
- PGresult *result = TALER_DB_exec_prepared (db_conn, "insert_refresh_session", params);
+ PGresult *result = TALER_DB_exec_prepared (session->conn,
+ "insert_refresh_session",
+ params);
if (PGRES_COMMAND_OK != PQresultStatus (result))
{
@@ -1469,18 +1554,19 @@ TALER_MINT_DB_create_refresh_session (PGconn *db_conn,
/**
* Store the given /refresh/melt request in the database.
*
- * @param db_conn database connection
- * @param session session key of the melt operation
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
* @param oldcoin_index index of the coin to store
- * @param melt melt operation
+ * @param melt melt operation details to store; includes
+ * the session hash of the melt
* @return #GNUNET_OK on success
* #GNUNET_SYSERR on internal error
*/
-int
-TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session,
- uint16_t oldcoin_index,
- const struct RefreshMelt *melt)
+static int
+postgres_insert_refresh_melt (void *cls,
+ struct TALER_MINTDB_Session *session,
+ uint16_t oldcoin_index,
+ const struct RefreshMelt *melt)
{
// FIXME: check logic!
uint16_t oldcoin_index_nbo = htons (oldcoin_index);
@@ -1488,17 +1574,19 @@ TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn,
size_t buf_size;
PGresult *result;
- buf_size = GNUNET_CRYPTO_rsa_public_key_encode (melt->coin.denom_pub,
+ buf_size = GNUNET_CRYPTO_rsa_public_key_encode (melt->coin.denom_pub.rsa_public_key,
&buf);
{
struct TALER_DB_QueryParam params[] = {
- TALER_DB_QUERY_PARAM_PTR(session),
+ TALER_DB_QUERY_PARAM_PTR(&melt->session_hash),
TALER_DB_QUERY_PARAM_PTR(&oldcoin_index_nbo),
TALER_DB_QUERY_PARAM_PTR(&melt->coin.coin_pub),
TALER_DB_QUERY_PARAM_PTR_SIZED(buf, buf_size),
TALER_DB_QUERY_PARAM_END
};
- result = TALER_DB_exec_prepared (db_conn, "insert_refresh_melt", params);
+ result = TALER_DB_exec_prepared (session->conn,
+ "insert_refresh_melt",
+ params);
}
GNUNET_free (buf);
if (PGRES_COMMAND_OK != PQresultStatus (result))
@@ -1515,18 +1603,20 @@ TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn,
/**
* Get information about melted coin details from the database.
*
- * @param db_conn database connection
- * @param session session key of the melt operation
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
+ * @param refresh_session session key of the melt operation
* @param oldcoin_index index of the coin to retrieve
* @param melt melt data to fill in
* @return #GNUNET_OK on success
* #GNUNET_SYSERR on internal error
*/
-int
-TALER_MINT_DB_get_refresh_melt (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session,
- uint16_t oldcoin_index,
- struct RefreshMelt *melt)
+static int
+postgres_get_refresh_melt (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t oldcoin_index,
+ struct RefreshMelt *melt)
{
// FIXME: check logic!
GNUNET_break (0);
@@ -1538,36 +1628,38 @@ TALER_MINT_DB_get_refresh_melt (PGconn *db_conn,
* Store in the database which coin(s) we want to create
* in a given refresh operation.
*
- * @param db_conn database connection
- * @param session_pub refresh session key
- * @param newcoin_index index of the coin to generate
- * @param denom_pub denomination of the coin to create
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
+ * @param session_hash hash to identify refresh session
+ * @param num_newcoins number of coins to generate, size of the @a denom_pubs array
+ * @param denom_pubs array denominations of the coins to create
* @return #GNUNET_OK on success
* #GNUNET_SYSERR on internal error
*/
-int
-TALER_MINT_DB_insert_refresh_order (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
- uint16_t newcoin_index,
- const struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub)
+static int
+postgres_insert_refresh_order (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t num_newcoins,
+ const struct TALER_DenominationPublicKey *denom_pubs)
{
- // FIXME: check logic
- uint16_t newcoin_index_nbo = htons (newcoin_index);
+ // FIXME: check logic: was written for just one COIN!
+ uint16_t newcoin_index_nbo = htons (num_newcoins);
char *buf;
size_t buf_size;
PGresult *result;
- buf_size = GNUNET_CRYPTO_rsa_public_key_encode (denom_pub,
+ buf_size = GNUNET_CRYPTO_rsa_public_key_encode (denom_pubs->rsa_public_key,
&buf);
{
struct TALER_DB_QueryParam params[] = {
TALER_DB_QUERY_PARAM_PTR (&newcoin_index_nbo),
- TALER_DB_QUERY_PARAM_PTR (session_pub),
+ TALER_DB_QUERY_PARAM_PTR (session_hash),
TALER_DB_QUERY_PARAM_PTR_SIZED (buf, buf_size),
TALER_DB_QUERY_PARAM_END
};
- result = TALER_DB_exec_prepared (db_conn,
+ result = TALER_DB_exec_prepared (session->conn,
"insert_refresh_order",
params);
}
@@ -1589,46 +1681,50 @@ TALER_MINT_DB_insert_refresh_order (PGconn *db_conn,
/**
- * Lookup in the database the @a newcoin_index coin that we want to
+ * Lookup in the database the coins that we want to
* create in the given refresh operation.
*
- * @param db_conn database connection
- * @param session_pub refresh session key
- * @param newcoin_index index of the coin to generate
- * @param denom_pub denomination of the coin to create
- * @return NULL on error (not found or internal error)
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
+ * @param session_hash hash to identify refresh session
+ * @param newcoin_index array of the @a denom_pubs array
+ * @param denom_pubs where to store the deomination keys
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on internal error
*/
-struct GNUNET_CRYPTO_rsa_PublicKey *
-TALER_MINT_DB_get_refresh_order (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
- uint16_t newcoin_index)
+static int
+postgres_get_refresh_order (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t num_newcoins,
+ struct TALER_DenominationPublicKey *denom_pubs)
{
- // FIXME: check logic
+ // FIXME: check logic -- was written for just one coin!
char *buf;
size_t buf_size;
- struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub;
- uint16_t newcoin_index_nbo = htons (newcoin_index);
+ uint16_t newcoin_index_nbo = htons (num_newcoins);
struct TALER_DB_QueryParam params[] = {
- TALER_DB_QUERY_PARAM_PTR(session_pub),
+ TALER_DB_QUERY_PARAM_PTR(session_hash),
TALER_DB_QUERY_PARAM_PTR(&newcoin_index_nbo),
TALER_DB_QUERY_PARAM_END
};
- PGresult *result = TALER_DB_exec_prepared (db_conn, "get_refresh_order", params);
+ PGresult *result = TALER_DB_exec_prepared (session->conn,
+ "get_refresh_order", params);
if (PGRES_TUPLES_OK != PQresultStatus (result))
{
BREAK_DB_ERR (result);
PQclear (result);
- return NULL;
+ return GNUNET_SYSERR;
}
if (0 == PQntuples (result))
{
PQclear (result);
/* FIXME: may want to distinguish between different error cases! */
- return NULL;
+ return GNUNET_SYSERR;
}
GNUNET_assert (1 == PQntuples (result));
struct TALER_DB_ResultSpec rs[] = {
@@ -1639,12 +1735,14 @@ TALER_MINT_DB_get_refresh_order (PGconn *db_conn,
{
PQclear (result);
GNUNET_break (0);
- return NULL;
+ return GNUNET_SYSERR;
}
PQclear (result);
- denom_pub = GNUNET_CRYPTO_rsa_public_key_decode (buf, buf_size);
+ denom_pubs->rsa_public_key
+ = GNUNET_CRYPTO_rsa_public_key_decode (buf,
+ buf_size);
GNUNET_free (buf);
- return denom_pub;
+ return GNUNET_OK;
}
@@ -1653,36 +1751,40 @@ TALER_MINT_DB_get_refresh_order (PGconn *db_conn,
* Store information about the commitment of the
* given coin for the given refresh session in the database.
*
- * @param db_conn database connection to use
- * @param refresh_session_pub refresh session this commitment belongs to
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection to use
+ * @param session_hash hash to identify refresh session
* @param i set index (1st dimension)
- * @param j coin index (2nd dimension), corresponds to refreshed (new) coins
- * @param commit_coin coin commitment to store
+ * @param num_newcoins coin index size of the @a commit_coins array
+ * @param commit_coins array of coin commitments to store
* @return #GNUNET_OK on success
* #GNUNET_SYSERR on error
*/
-int
-TALER_MINT_DB_insert_refresh_commit_coin (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- unsigned int i,
- unsigned int j,
- const struct RefreshCommitCoin *commit_coin)
+static int
+postgres_insert_refresh_commit_coins (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ unsigned int i,
+ unsigned int num_newcoins,
+ const struct RefreshCommitCoin *commit_coins)
{
- // FIXME: check logic!
+ // FIXME: check logic! -- was written for single commit_coin!
uint16_t cnc_index_nbo = htons (i);
- uint16_t newcoin_index_nbo = htons (j);
+ uint16_t newcoin_index_nbo = htons (num_newcoins);
struct TALER_DB_QueryParam params[] = {
- TALER_DB_QUERY_PARAM_PTR(refresh_session_pub),
- TALER_DB_QUERY_PARAM_PTR_SIZED(commit_coin->coin_ev, commit_coin->coin_ev_size),
+ TALER_DB_QUERY_PARAM_PTR(session_hash),
+ TALER_DB_QUERY_PARAM_PTR_SIZED(commit_coins->coin_ev, commit_coins->coin_ev_size),
TALER_DB_QUERY_PARAM_PTR(&cnc_index_nbo),
TALER_DB_QUERY_PARAM_PTR(&newcoin_index_nbo),
- TALER_DB_QUERY_PARAM_PTR_SIZED(commit_coin->refresh_link->coin_priv_enc,
- commit_coin->refresh_link->blinding_key_enc_size +
- sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)),
+ TALER_DB_QUERY_PARAM_PTR_SIZED (commit_coins->refresh_link->coin_priv_enc,
+ commit_coins->refresh_link->blinding_key_enc_size +
+ sizeof (struct TALER_CoinSpendPrivateKey)),
TALER_DB_QUERY_PARAM_END
};
- PGresult *result = TALER_DB_exec_prepared (db_conn, "insert_refresh_commit_coin", params);
+ PGresult *result = TALER_DB_exec_prepared (session->conn,
+ "insert_refresh_commit_coin",
+ params);
if (PGRES_COMMAND_OK != PQresultStatus (result))
{
@@ -1706,8 +1808,9 @@ TALER_MINT_DB_insert_refresh_commit_coin (PGconn *db_conn,
* Obtain information about the commitment of the
* given coin of the given refresh session from the database.
*
- * @param db_conn database connection to use
- * @param refresh_session_pub refresh session the commitment belongs to
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection to use
+ * @param session_hash hash to identify refresh session
* @param i set index (1st dimension)
* @param j coin index (2nd dimension), corresponds to refreshed (new) coins
* @param commit_coin[OUT] coin commitment to return
@@ -1715,18 +1818,19 @@ TALER_MINT_DB_insert_refresh_commit_coin (PGconn *db_conn,
* #GNUNET_NO if not found
* #GNUNET_SYSERR on error
*/
-int
-TALER_MINT_DB_get_refresh_commit_coin (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- unsigned int cnc_index,
- unsigned int newcoin_index,
- struct RefreshCommitCoin *cc)
+static int
+postgres_get_refresh_commit_coins (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ unsigned int cnc_index,
+ unsigned int newcoin_index,
+ struct RefreshCommitCoin *cc)
{
// FIXME: check logic!
uint16_t cnc_index_nbo = htons (cnc_index);
uint16_t newcoin_index_nbo = htons (newcoin_index);
struct TALER_DB_QueryParam params[] = {
- TALER_DB_QUERY_PARAM_PTR(refresh_session_pub),
+ TALER_DB_QUERY_PARAM_PTR(session_hash),
TALER_DB_QUERY_PARAM_PTR(&cnc_index_nbo),
TALER_DB_QUERY_PARAM_PTR(&newcoin_index_nbo),
TALER_DB_QUERY_PARAM_END
@@ -1737,7 +1841,9 @@ TALER_MINT_DB_get_refresh_commit_coin (PGconn *db_conn,
size_t rl_buf_size;
struct TALER_RefreshLinkEncrypted *rl;
- PGresult *result = TALER_DB_exec_prepared (db_conn, "get_refresh_commit_coin", params);
+ PGresult *result = TALER_DB_exec_prepared (session->conn,
+ "get_refresh_commit_coin",
+ params);
if (PGRES_TUPLES_OK != PQresultStatus (result))
{
@@ -1763,7 +1869,7 @@ TALER_MINT_DB_get_refresh_commit_coin (PGconn *db_conn,
return GNUNET_SYSERR;
}
PQclear (result);
- if (rl_buf_size < sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))
+ if (rl_buf_size < sizeof (struct TALER_CoinSpendPrivateKey))
{
GNUNET_free (c_buf);
GNUNET_free (rl_buf);
@@ -1783,26 +1889,27 @@ TALER_MINT_DB_get_refresh_commit_coin (PGconn *db_conn,
* Store the commitment to the given (encrypted) refresh link data
* for the given refresh session.
*
- * @param db_conn database connection to use
- * @param refresh_session_pub public key of the refresh session this
- * commitment belongs with
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection to use
+ * @param session_hash hash to identify refresh session
* @param i set index (1st dimension)
* @param j coin index (2nd dimension), corresponds to melted (old) coins
* @param commit_link link information to store
* @return #GNUNET_SYSERR on internal error, #GNUNET_OK on success
*/
-int
-TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- unsigned int i,
- unsigned int j,
- const struct RefreshCommitLink *commit_link)
+static int
+postgres_insert_refresh_commit_links (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ unsigned int i,
+ unsigned int j,
+ const struct RefreshCommitLink *commit_link)
{
// FIXME: check logic!
uint16_t cnc_index_nbo = htons (i);
uint16_t oldcoin_index_nbo = htons (j);
struct TALER_DB_QueryParam params[] = {
- TALER_DB_QUERY_PARAM_PTR(refresh_session_pub),
+ TALER_DB_QUERY_PARAM_PTR(session_hash),
TALER_DB_QUERY_PARAM_PTR(&commit_link->transfer_pub),
TALER_DB_QUERY_PARAM_PTR(&cnc_index_nbo),
TALER_DB_QUERY_PARAM_PTR(&oldcoin_index_nbo),
@@ -1810,7 +1917,7 @@ TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn,
TALER_DB_QUERY_PARAM_END
};
- PGresult *result = TALER_DB_exec_prepared (db_conn,
+ PGresult *result = TALER_DB_exec_prepared (session->conn,
"insert_refresh_commit_link",
params);
if (PGRES_COMMAND_OK != PQresultStatus (result))
@@ -1835,35 +1942,36 @@ TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn,
* Obtain the commited (encrypted) refresh link data
* for the given refresh session.
*
- * @param db_conn database connection to use
- * @param refresh_session_pub public key of the refresh session this
- * commitment belongs with
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection to use
+ * @param session_hash hash to identify refresh session
* @param i set index (1st dimension)
- * @param j coin index (2nd dimension), corresponds to melted (old) coins
- * @param cc[OUT] link information to return
+ * @param num_links size of the @a commit_link array
+ * @param links[OUT] array of link information to return
* @return #GNUNET_SYSERR on internal error,
* #GNUNET_NO if commitment was not found
* #GNUNET_OK on success
*/
-int
-TALER_MINT_DB_get_refresh_commit_link (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- unsigned int cnc_index,
- unsigned int oldcoin_index,
- struct RefreshCommitLink *cc)
+static int
+postgres_get_refresh_commit_links (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ unsigned int i,
+ unsigned int num_links,
+ struct RefreshCommitLink *links)
{
- // FIXME: check logic!
- uint16_t cnc_index_nbo = htons (cnc_index);
- uint16_t oldcoin_index_nbo = htons (oldcoin_index);
+ // FIXME: check logic: was written for a single link!
+ uint16_t cnc_index_nbo = htons (i);
+ uint16_t oldcoin_index_nbo = htons (num_links);
struct TALER_DB_QueryParam params[] = {
- TALER_DB_QUERY_PARAM_PTR(refresh_session_pub),
+ TALER_DB_QUERY_PARAM_PTR(session_hash),
TALER_DB_QUERY_PARAM_PTR(&cnc_index_nbo),
TALER_DB_QUERY_PARAM_PTR(&oldcoin_index_nbo),
TALER_DB_QUERY_PARAM_END
};
- PGresult *result = TALER_DB_exec_prepared (db_conn,
+ PGresult *result = TALER_DB_exec_prepared (session->conn,
"get_refresh_commit_link",
params);
if (PGRES_TUPLES_OK != PQresultStatus (result))
@@ -1880,15 +1988,14 @@ TALER_MINT_DB_get_refresh_commit_link (PGconn *db_conn,
}
struct TALER_DB_ResultSpec rs[] = {
- TALER_DB_RESULT_SPEC("transfer_pub", &cc->transfer_pub),
- TALER_DB_RESULT_SPEC("link_secret_enc", &cc->shared_secret_enc),
+ TALER_DB_RESULT_SPEC("transfer_pub", &links->transfer_pub),
+ TALER_DB_RESULT_SPEC("link_secret_enc", &links->shared_secret_enc),
TALER_DB_RESULT_SPEC_END
};
if (GNUNET_YES != TALER_DB_extract_result (result, rs, 0))
{
PQclear (result);
- GNUNET_free (cc);
return GNUNET_SYSERR;
}
@@ -1903,17 +2010,19 @@ TALER_MINT_DB_get_refresh_commit_link (PGconn *db_conn,
* of the coin. This data is later used should an old coin
* be used to try to obtain the private keys during "/refresh/link".
*
- * @param db_conn database connection
- * @param session_pub refresh session
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
+ * @param session_hash hash to identify refresh session
* @param newcoin_index coin index
* @param ev_sig coin signature
* @return #GNUNET_OK on success
*/
-int
-TALER_MINT_DB_insert_refresh_collectable (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
- uint16_t newcoin_index,
- const struct GNUNET_CRYPTO_rsa_Signature *ev_sig)
+static int
+postgres_insert_refresh_collectable (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t newcoin_index,
+ const struct TALER_DenominationSignature *ev_sig)
{
// FIXME: check logic!
uint16_t newcoin_index_nbo = htons (newcoin_index);
@@ -1921,16 +2030,16 @@ TALER_MINT_DB_insert_refresh_collectable (PGconn *db_conn,
size_t buf_size;
PGresult *result;
- buf_size = GNUNET_CRYPTO_rsa_signature_encode (ev_sig,
+ buf_size = GNUNET_CRYPTO_rsa_signature_encode (ev_sig->rsa_signature,
&buf);
{
struct TALER_DB_QueryParam params[] = {
- TALER_DB_QUERY_PARAM_PTR(session_pub),
+ TALER_DB_QUERY_PARAM_PTR(session_hash),
TALER_DB_QUERY_PARAM_PTR(&newcoin_index_nbo),
TALER_DB_QUERY_PARAM_PTR_SIZED(buf, buf_size),
TALER_DB_QUERY_PARAM_END
};
- result = TALER_DB_exec_prepared (db_conn,
+ result = TALER_DB_exec_prepared (session->conn,
"insert_refresh_collectable",
params);
}
@@ -1950,13 +2059,15 @@ TALER_MINT_DB_insert_refresh_collectable (PGconn *db_conn,
* Obtain the link data of a coin, that is the encrypted link
* information, the denomination keys and the signatures.
*
- * @param db_conn database connection
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
* @param coin_pub public key to use to retrieve linkage data
* @return all known link data for the coin
*/
-struct LinkDataList *
-TALER_db_get_link (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub)
+static struct LinkDataList *
+postgres_get_link_data_list (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct TALER_CoinSpendPublicKey *coin_pub)
{
// FIXME: check logic!
struct LinkDataList *ldl;
@@ -1965,7 +2076,7 @@ TALER_db_get_link (PGconn *db_conn,
TALER_DB_QUERY_PARAM_PTR(coin_pub),
TALER_DB_QUERY_PARAM_END
};
- PGresult *result = TALER_DB_exec_prepared (db_conn, "get_link", params);
+ PGresult *result = TALER_DB_exec_prepared (session->conn, "get_link", params);
ldl = NULL;
if (PGRES_TUPLES_OK != PQresultStatus (result))
@@ -2006,7 +2117,8 @@ TALER_db_get_link (PGconn *db_conn,
{
PQclear (result);
GNUNET_break (0);
- TALER_db_link_data_list_free (ldl);
+ common_free_link_data_list (cls,
+ ldl);
return NULL;
}
if (ld_buf_size < sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))
@@ -2015,7 +2127,8 @@ TALER_db_get_link (PGconn *db_conn,
GNUNET_free (pk_buf);
GNUNET_free (sig_buf);
GNUNET_free (ld_buf);
- TALER_db_link_data_list_free (ldl);
+ common_free_link_data_list (cls,
+ ldl);
return NULL;
}
// FIXME: use util API for this!
@@ -2027,10 +2140,12 @@ TALER_db_get_link (PGconn *db_conn,
ld_buf,
ld_buf_size);
- sig = GNUNET_CRYPTO_rsa_signature_decode (sig_buf,
- sig_buf_size);
- denom_pub = GNUNET_CRYPTO_rsa_public_key_decode (pk_buf,
- pk_buf_size);
+ sig
+ = GNUNET_CRYPTO_rsa_signature_decode (sig_buf,
+ sig_buf_size);
+ denom_pub
+ = GNUNET_CRYPTO_rsa_public_key_decode (pk_buf,
+ pk_buf_size);
GNUNET_free (pk_buf);
GNUNET_free (sig_buf);
GNUNET_free (ld_buf);
@@ -2044,14 +2159,15 @@ TALER_db_get_link (PGconn *db_conn,
GNUNET_free (link_enc);
GNUNET_break (0);
PQclear (result);
- TALER_db_link_data_list_free (ldl);
+ common_free_link_data_list (cls,
+ ldl);
return NULL;
}
pos = GNUNET_new (struct LinkDataList);
pos->next = ldl;
pos->link_data_enc = link_enc;
- pos->denom_pub = denom_pub;
- pos->ev_sig = sig;
+ pos->denom_pub.rsa_public_key = denom_pub;
+ pos->ev_sig.rsa_signature = sig;
ldl = pos;
}
return ldl;
@@ -2059,25 +2175,13 @@ TALER_db_get_link (PGconn *db_conn,
/**
- * Free memory of the link data list.
- *
- * @param ldl link data list to release
- */
-void
-TALER_db_link_data_list_free (struct LinkDataList *ldl)
-{
- GNUNET_break (0); // FIXME
-}
-
-
-/**
* Obtain shared secret and transfer public key from the public key of
* the coin. This information and the link information returned by
- * #TALER_db_get_link() enable the owner of an old coin to determine
- * the private keys of the new coins after the melt.
- *
+ * #postgres_get_link_data_list() enable the owner of an old coin to
+ * determine the private keys of the new coins after the melt.
*
- * @param db_conn database connection
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
* @param coin_pub public key of the coin
* @param transfer_pub[OUT] public transfer key
* @param shared_secret_enc[OUT] set to shared secret
@@ -2085,10 +2189,11 @@ TALER_db_link_data_list_free (struct LinkDataList *ldl)
* #GNUNET_NO on failure (not found)
* #GNUNET_SYSERR on internal failure (database issue)
*/
-int
-TALER_db_get_transfer (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
- struct GNUNET_CRYPTO_EcdsaPublicKey *transfer_pub,
+static int
+postgres_get_transfer (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct TALER_CoinSpendPublicKey *coin_pub,
+ struct TALER_TransferPublicKey *transfer_pub,
struct TALER_EncryptedLinkSecret *shared_secret_enc)
{
// FIXME: check logic!
@@ -2097,7 +2202,7 @@ TALER_db_get_transfer (PGconn *db_conn,
TALER_DB_QUERY_PARAM_END
};
- PGresult *result = TALER_DB_exec_prepared (db_conn, "get_transfer", params);
+ PGresult *result = TALER_DB_exec_prepared (session->conn, "get_transfer", params);
if (PGRES_TUPLES_OK != PQresultStatus (result))
{
@@ -2139,19 +2244,19 @@ TALER_db_get_transfer (PGconn *db_conn,
}
-
-
/**
* Compile a list of all (historic) transactions performed
* with the given coin (/refresh/melt and /deposit operations).
*
- * @param db_conn database connection
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param session database connection
* @param coin_pub coin to investigate
* @return list of transactions, NULL if coin is fresh
*/
-struct TALER_MINT_DB_TransactionList *
-TALER_MINT_DB_get_coin_transactions (PGconn *db_conn,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub)
+static struct TALER_MINT_DB_TransactionList *
+postgres_get_coin_transactions (void *cls,
+ struct TALER_MINTDB_Session *session,
+ const struct TALER_CoinSpendPublicKey *coin_pub)
{
// FIXME: check logic!
GNUNET_break (0); // FIXME: implement!
@@ -2159,17 +2264,92 @@ TALER_MINT_DB_get_coin_transactions (PGconn *db_conn,
}
+
/**
- * Free linked list of transactions.
+ * Initialize Postgres database subsystem.
*
- * @param list list to free
+ * @param cls a configuration instance
+ * @return NULL on error, otherwise a `struct TALER_MINTDB_Plugin`
*/
-void
-TALER_MINT_DB_free_coin_transaction_list (struct TALER_MINT_DB_TransactionList *list)
+void *
+libtaler_plugin_mintdb_postgres_init (void *cls)
{
- // FIXME: check logic!
- GNUNET_break (0);
+ struct GNUNET_CONFIGURATION_Handle *cfg = cls;
+ struct PostgresClosure *pg;
+ struct TALER_MINTDB_Plugin *plugin;
+
+ pg = GNUNET_new (struct PostgresClosure);
+
+ if (0 != pthread_key_create (&pg->db_conn_threadlocal,
+ &db_conn_destroy))
+ {
+ LOG_ERROR ("Cannnot create pthread key.\n");
+ return NULL;
+ }
+ /* FIXME: use configuration section with "postgres" in its name... */
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "mint", "db",
+ &pg->TALER_MINT_db_connection_cfg_str))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "mint",
+ "db");
+ return NULL;
+ }
+ plugin = GNUNET_new (struct TALER_MINTDB_Plugin);
+ plugin->cls = pg;
+ plugin->get_session = &postgres_get_session;
+ plugin->drop_temporary = &postgres_drop_temporary;
+ plugin->create_tables = &postgres_create_tables;
+ plugin->start = &postgres_start;
+ plugin->commit = &postgres_commit;
+ plugin->rollback = &postgres_rollback;
+ plugin->reserve_get = &postgres_reserve_get;
+ plugin->reserves_in_insert = &postgres_reserves_in_insert;
+ plugin->get_collectable_blindcoin = &postgres_get_collectable_blindcoin;
+ plugin->insert_collectable_blindcoin = &postgres_insert_collectable_blindcoin;
+ plugin->get_reserve_history = &postgres_get_reserve_history;
+ plugin->free_reserve_history = &common_free_reserve_history;
+ plugin->have_deposit = &postgres_have_deposit;
+ plugin->insert_deposit = &postgres_insert_deposit;
+ plugin->get_refresh_session = &postgres_get_refresh_session;
+ plugin->create_refresh_session = &postgres_create_refresh_session;
+ plugin->insert_refresh_melt = &postgres_insert_refresh_melt;
+ plugin->get_refresh_melt = &postgres_get_refresh_melt;
+ plugin->insert_refresh_order = &postgres_insert_refresh_order;
+ plugin->get_refresh_order = &postgres_get_refresh_order;
+ plugin->insert_refresh_commit_coins = &postgres_insert_refresh_commit_coins;
+ plugin->get_refresh_commit_coins = &postgres_get_refresh_commit_coins;
+ plugin->insert_refresh_commit_links = &postgres_insert_refresh_commit_links;
+ plugin->get_refresh_commit_links = &postgres_get_refresh_commit_links;
+ plugin->insert_refresh_collectable = &postgres_insert_refresh_collectable;
+ plugin->get_link_data_list = &postgres_get_link_data_list;
+ plugin->free_link_data_list = &common_free_link_data_list;
+ plugin->get_transfer = &postgres_get_transfer;
+ // plugin->have_lock = &postgres_have_lock;
+ // plugin->insert_lock = &postgres_insert_lock;
+ plugin->get_coin_transactions = &postgres_get_coin_transactions;
+ plugin->free_coin_transaction_list = &common_free_coin_transaction_list;
+ return plugin;
}
-/* end of mint_db.c */
+/**
+ * Shutdown Postgres database subsystem.
+ *
+ * @param cls a `struct TALER_MINTDB_Plugin`
+ * @return NULL (always)
+ */
+void *
+libtaler_plugin_mintdb_postgres_done (void *cls)
+{
+ struct TALER_MINTDB_Plugin *plugin = cls;
+ struct PostgresClosure *pg = plugin->cls;
+
+ GNUNET_free (pg);
+ GNUNET_free (plugin);
+ return NULL;
+}
+
+/* end of plugin_mintdb_postgres.c */
diff --git a/src/mint/taler-mint-dbinit.c b/src/mint/taler-mint-dbinit.c
index 8106b54c4..8056b7df0 100644
--- a/src/mint/taler-mint-dbinit.c
+++ b/src/mint/taler-mint-dbinit.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2014, 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
@@ -14,7 +14,7 @@
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file taler-mint-dbinit.c
+ * @file mint/taler-mint-dbinit.c
* @brief Create tables for the mint database.
* @author Florian Dold
*/
@@ -22,76 +22,80 @@
#include <gnunet/gnunet_util_lib.h>
#include <libpq-fe.h>
#include "taler_util.h"
-#include "mint_db.h"
-
-#define break_db_err(result) do { \
- GNUNET_break(0); \
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Database failure: %s\n", PQresultErrorMessage (result)); \
- PQclear (result); \
- } while (0)
-
+#include "taler_mintdb_plugin.h"
+#include "plugin.h"
+/**
+ * Mint directory with the keys.
+ */
static char *mint_base_dir;
-static struct GNUNET_CONFIGURATION_Handle *cfg;
-static PGconn *db_conn;
-static char *TALER_MINT_db_connection_cfg_str;
-
-
+/**
+ * Our configuration.
+ */
+static struct GNUNET_CONFIGURATION_Handle *cfg;
/**
- * The main function of the serve tool
+ * The main function of the database initialization tool.
+ * Used to initialize the Taler Mint's database.
*
* @param argc number of arguments from the command line
* @param argv command line arguments
* @return 0 ok, 1 on error
*/
int
-main (int argc, char *const *argv)
+main (int argc,
+ char *const *argv)
{
static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- GNUNET_GETOPT_OPTION_HELP ("gnunet-mint-keyup OPTIONS"),
+ GNUNET_GETOPT_OPTION_HELP ("gnunet-mint-dbinit OPTIONS"),
{'d', "mint-dir", "DIR",
"mint directory", 1,
&GNUNET_GETOPT_set_filename, &mint_base_dir},
GNUNET_GETOPT_OPTION_END
};
- if (GNUNET_GETOPT_run ("taler-mint-serve", options, argc, argv) < 0)
+ if (GNUNET_GETOPT_run ("taler-mint-dbinit",
+ options,
+ argc, argv) < 0)
return 1;
- GNUNET_assert (GNUNET_OK == GNUNET_log_setup ("taler-mint-dbinit", "INFO", NULL));
-
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_log_setup ("taler-mint-dbinit",
+ "INFO",
+ NULL));
if (NULL == mint_base_dir)
{
- fprintf (stderr, "Mint base directory not given.\n");
+ fprintf (stderr,
+ "Mint base directory not given.\n");
return 1;
}
-
cfg = TALER_config_load (mint_base_dir);
if (NULL == cfg)
{
- fprintf (stderr, "Can't load mint configuration.\n");
+ fprintf (stderr,
+ "Failed to load mint configuration.\n");
return 1;
}
- if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "mint", "db", &TALER_MINT_db_connection_cfg_str))
- {
- fprintf (stderr, "Configuration 'mint.db' not found.\n");
- return 42;
- }
- db_conn = PQconnectdb (TALER_MINT_db_connection_cfg_str);
- if (CONNECTION_OK != PQstatus (db_conn))
+ if (GNUNET_OK !=
+ TALER_MINT_plugin_load (cfg))
{
- fprintf (stderr, "Database connection failed: %s\n", PQerrorMessage (db_conn));
+ fprintf (stderr,
+ "Failed to initialize database plugin.\n");
return 1;
}
-
- if (GNUNET_OK != TALER_MINT_DB_create_tables (GNUNET_NO))
+ if (GNUNET_OK !=
+ plugin->create_tables (plugin->cls,
+ GNUNET_NO))
{
- fprintf (stderr, "Failed to initialize database.\n");
+ fprintf (stderr,
+ "Failed to initialize database.\n");
+ TALER_MINT_plugin_unload ();
return 1;
}
-
+ TALER_MINT_plugin_unload ();
return 0;
}
+
+/* end of taler-mint-dbinit.c */
diff --git a/src/mint/taler-mint-httpd.c b/src/mint/taler-mint-httpd.c
index 416851066..70d3b64f0 100644
--- a/src/mint/taler-mint-httpd.c
+++ b/src/mint/taler-mint-httpd.c
@@ -31,12 +31,12 @@
#include "taler_util.h"
#include "taler-mint-httpd_parsing.h"
#include "taler-mint-httpd_mhd.h"
-#include "taler-mint-httpd_keys.h"
#include "taler-mint-httpd_deposit.h"
#include "taler-mint-httpd_withdraw.h"
#include "taler-mint-httpd_refresh.h"
#include "taler-mint-httpd_keystate.h"
-#include "mint_db.h"
+#include "taler_mintdb_plugin.h"
+#include "plugin.h"
/**
@@ -230,7 +230,6 @@ mint_serve_process_config (const char *mint_directory)
unsigned long long port;
unsigned long long kappa;
char *master_pub_str;
- char *db_cfg;
cfg = TALER_config_load (mint_directory);
if (NULL == cfg)
@@ -261,16 +260,7 @@ mint_serve_process_config (const char *mint_directory)
GNUNET_free (master_pub_str);
if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "mint", "db",
- &db_cfg))
- {
- fprintf (stderr,
- "invalid configuration: mint.db\n");
- return GNUNET_NO;
- }
- if (GNUNET_OK !=
- TALER_MINT_DB_init (db_cfg))
+ TALER_MINT_plugin_load (cfg))
{
fprintf (stderr,
"failed to initialize DB subsystem\n");
diff --git a/src/mint/taler-mint-httpd.h b/src/mint/taler-mint-httpd.h
index a86b06e43..50b745703 100644
--- a/src/mint/taler-mint-httpd.h
+++ b/src/mint/taler-mint-httpd.h
@@ -23,12 +23,7 @@
#ifndef TALER_MINT_HTTPD_H
#define TALER_MINT_HTTPD_H
-
-/**
- * Cut-and-choose size for refreshing.
- * FIXME: maybe make it a config option?
- */
-#define KAPPA 3
+#include <microhttpd.h>
/**
* For now, we just do EUR. Should become configurable
diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c
index 63bca2ecc..17f44c9c9 100644
--- a/src/mint/taler-mint-httpd_db.c
+++ b/src/mint/taler-mint-httpd_db.c
@@ -17,41 +17,73 @@
* @file taler-mint-httpd_db.c
* @brief High-level (transactional-layer) database operations for the mint.
* @author Christian Grothoff
- *
- * TODO:
- * - actually abstract DB implementation (i.e. via plugin logic)
- * (this file should remain largely unchanged with the exception
- * of the PQ-specific DB handle types)
*/
#include "platform.h"
#include <pthread.h>
#include <jansson.h>
#include "taler-mint-httpd_db.h"
#include "taler_signatures.h"
-#include "taler-mint-httpd_keys.h"
#include "taler-mint-httpd_responses.h"
-#include "mint_db.h"
#include "taler_util.h"
#include "taler-mint-httpd_keystate.h"
+#include "plugin.h"
/**
- * Get an amount in the mint's currency that is zero.
+ * Calculate the total value of all transactions performed.
+ * Stores @a off plus the cost of all transactions in @a tl
+ * in @a ret.
*
- * @return zero amount in the mint's currency
+ * @param pos transaction list to process
+ * @param off offset to use as the starting value
+ * @param ret where the resulting total is to be stored
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
*/
-static struct TALER_Amount
-mint_amount_native_zero ()
+static int
+calculate_transaction_list_totals (struct TALER_MINT_DB_TransactionList *tl,
+ const struct TALER_Amount *off,
+ struct TALER_Amount *ret)
{
- struct TALER_Amount amount;
-
- memset (&amount,
- 0,
- sizeof (amount));
- memcpy (amount.currency,
- MINT_CURRENCY,
- strlen (MINT_CURRENCY) + 1);
- return amount;
+ struct TALER_Amount spent = *off;
+ struct TALER_MINT_DB_TransactionList *pos;
+
+ for (pos = tl; NULL != pos; pos = pos->next)
+ {
+ switch (pos->type)
+ {
+ case TALER_MINT_DB_TT_DEPOSIT:
+ if (GNUNET_OK !=
+ TALER_amount_add (&spent,
+ &spent,
+ &pos->details.deposit->amount_with_fee))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ break;
+ case TALER_MINT_DB_TT_REFRESH_MELT:
+ if (GNUNET_OK !=
+ TALER_amount_add (&spent,
+ &spent,
+ &pos->details.melt->amount_with_fee))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ break;
+ case TALER_MINT_DB_TT_LOCK:
+ /* should check if lock is still active,
+ and if it is for THIS operation; if
+ lock is inactive, delete it; if lock
+ is for THIS operation, ignore it;
+ if lock is for another operation,
+ count it! */
+ GNUNET_assert (0); // FIXME: not implemented! (#3625)
+ return GNUNET_SYSERR;
+ }
+ }
+ *ret = spent;
+ return GNUNET_OK;
}
@@ -69,26 +101,24 @@ int
TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
const struct Deposit *deposit)
{
- PGconn *db_conn;
+ struct TALER_MINTDB_Session *session;
struct TALER_MINT_DB_TransactionList *tl;
- struct TALER_MINT_DB_TransactionList *pos;
struct TALER_Amount spent;
struct TALER_Amount value;
- struct TALER_Amount fee_deposit;
- struct TALER_Amount fee_withdraw;
- struct TALER_Amount fee_refresh;
struct MintKeyState *mks;
struct TALER_MINT_DenomKeyIssuePriv *dki;
int ret;
- if (NULL == (db_conn = TALER_MINT_DB_get_connection (GNUNET_NO)))
+ if (NULL == (session = plugin->get_session (plugin->cls,
+ GNUNET_NO)))
{
GNUNET_break (0);
return TALER_MINT_reply_internal_db_error (connection);
}
if (GNUNET_YES ==
- TALER_MINT_DB_have_deposit (db_conn,
- deposit))
+ plugin->have_deposit (plugin->cls,
+ session,
+ deposit))
{
return TALER_MINT_reply_deposit_success (connection,
&deposit->coin.coin_pub,
@@ -96,79 +126,67 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
&deposit->h_contract,
deposit->transaction_id,
&deposit->merchant_pub,
- &deposit->amount);
+ &deposit->amount_with_fee);
}
mks = TALER_MINT_key_state_acquire ();
dki = TALER_MINT_get_denom_key (mks,
- deposit->coin.denom_pub);
- value = TALER_amount_ntoh (dki->issue.value);
- fee_deposit = TALER_amount_ntoh (dki->issue.fee_deposit);
- fee_refresh = TALER_amount_ntoh (dki->issue.fee_refresh);
+ &deposit->coin.denom_pub);
+ TALER_amount_ntoh (&value,
+ &dki->issue.value);
TALER_MINT_key_state_release (mks);
if (GNUNET_OK !=
- TALER_MINT_DB_transaction (db_conn))
+ plugin->start (plugin->cls,
+ session))
{
GNUNET_break (0);
return TALER_MINT_reply_internal_db_error (connection);
}
- tl = TALER_MINT_DB_get_coin_transactions (db_conn,
- &deposit->coin.coin_pub);
- spent = fee_withdraw; /* fee for THIS transaction */
- /* FIXME: need to deal better with integer overflows
- in the logic that follows! (change amount.c API! -- #3637) */
- spent = TALER_amount_add (spent,
- deposit->amount);
-
- for (pos = tl; NULL != pos; pos = pos->next)
+ /* fee for THIS transaction */
+ spent = deposit->amount_with_fee;
+ /* add cost of all previous transactions */
+ tl = plugin->get_coin_transactions (plugin->cls,
+ session,
+ &deposit->coin.coin_pub);
+ if (GNUNET_OK !=
+ calculate_transaction_list_totals (tl,
+ &spent,
+ &spent))
{
- switch (pos->type)
- {
- case TALER_MINT_DB_TT_DEPOSIT:
- spent = TALER_amount_add (spent,
- pos->details.deposit->amount);
- spent = TALER_amount_add (spent,
- fee_deposit);
- break;
- case TALER_MINT_DB_TT_REFRESH_MELT:
- spent = TALER_amount_add (spent,
- pos->details.melt->amount);
- spent = TALER_amount_add (spent,
- fee_refresh);
- break;
- case TALER_MINT_DB_TT_LOCK:
- /* should check if lock is still active,
- and if it is for THIS operation; if
- lock is inactive, delete it; if lock
- is for THIS operation, ignore it;
- if lock is for another operation,
- count it! */
- GNUNET_assert (0); // FIXME: not implemented! (#3625)
- break;
- }
+ plugin->free_coin_transaction_list (plugin->cls,
+ tl);
+ return TALER_MINT_reply_internal_db_error (connection);
}
-
- if (0 < TALER_amount_cmp (spent, value))
+ /* Check that cost of all transactions is smaller than
+ the value of the coin. */
+ if (0 < TALER_amount_cmp (&spent,
+ &value))
{
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
ret = TALER_MINT_reply_deposit_insufficient_funds (connection,
- tl);
- TALER_MINT_DB_free_coin_transaction_list (tl);
+ tl);
+ plugin->free_coin_transaction_list (plugin->cls,
+ tl);
return ret;
}
- TALER_MINT_DB_free_coin_transaction_list (tl);
+ plugin->free_coin_transaction_list (plugin->cls,
+ tl);
if (GNUNET_OK !=
- TALER_MINT_DB_insert_deposit (db_conn,
- deposit))
+ plugin->insert_deposit (plugin->cls,
+ session,
+ deposit))
{
LOG_WARNING ("Failed to store /deposit information in database\n");
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
return TALER_MINT_reply_internal_db_error (connection);
}
if (GNUNET_OK !=
- TALER_MINT_DB_commit (db_conn))
+ plugin->commit (plugin->cls,
+ session))
{
LOG_WARNING ("/deposit transaction commit failed\n");
return TALER_MINT_reply_commit_error (connection);
@@ -179,7 +197,7 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
&deposit->h_contract,
deposit->transaction_id,
&deposit->merchant_pub,
- &deposit->amount);
+ &deposit->amount_with_fee);
}
@@ -193,19 +211,21 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
*/
int
TALER_MINT_db_execute_withdraw_status (struct MHD_Connection *connection,
- const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub)
+ const struct TALER_ReservePublicKey *reserve_pub)
{
- PGconn *db_conn;
+ struct TALER_MINTDB_Session *session;
struct ReserveHistory *rh;
int res;
- if (NULL == (db_conn = TALER_MINT_DB_get_connection (GNUNET_NO)))
+ if (NULL == (session = plugin->get_session (plugin->cls,
+ GNUNET_NO)))
{
GNUNET_break (0);
return TALER_MINT_reply_internal_db_error (connection);
}
- rh = TALER_MINT_DB_get_reserve_history (db_conn,
- reserve_pub);
+ rh = plugin->get_reserve_history (plugin->cls,
+ session,
+ reserve_pub);
if (NULL == rh)
return TALER_MINT_reply_json_pack (connection,
MHD_HTTP_NOT_FOUND,
@@ -213,7 +233,8 @@ TALER_MINT_db_execute_withdraw_status (struct MHD_Connection *connection,
"error", "Reserve not found");
res = TALER_MINT_reply_withdraw_status_success (connection,
rh);
- TALER_MINT_DB_free_reserve_history (rh);
+ plugin->free_reserve_history (plugin->cls,
+ rh);
return res;
}
@@ -234,13 +255,13 @@ TALER_MINT_db_execute_withdraw_status (struct MHD_Connection *connection,
*/
int
TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
- const struct GNUNET_CRYPTO_EddsaPublicKey *reserve,
- const struct GNUNET_CRYPTO_rsa_PublicKey *denomination_pub,
+ const struct TALER_ReservePublicKey *reserve,
+ const struct TALER_DenominationPublicKey *denomination_pub,
const char *blinded_msg,
size_t blinded_msg_len,
- const struct GNUNET_CRYPTO_EddsaSignature *signature)
+ const struct TALER_ReserveSignature *signature)
{
- PGconn *db_conn;
+ struct TALER_MINTDB_Session *session;
struct ReserveHistory *rh;
const struct ReserveHistory *pos;
struct MintKeyState *key_state;
@@ -253,6 +274,7 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
struct TALER_Amount withdraw_total;
struct TALER_Amount balance;
struct TALER_Amount value;
+ struct TALER_Amount fee_withdraw;
struct GNUNET_HashCode h_blind;
int res;
@@ -260,14 +282,16 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
blinded_msg_len,
&h_blind);
- if (NULL == (db_conn = TALER_MINT_DB_get_connection (GNUNET_NO)))
+ if (NULL == (session = plugin->get_session (plugin->cls,
+ GNUNET_NO)))
{
GNUNET_break (0);
return TALER_MINT_reply_internal_db_error (connection);
}
- res = TALER_MINT_DB_get_collectable_blindcoin (db_conn,
- &h_blind,
- &collectable);
+ res = plugin->get_collectable_blindcoin (plugin->cls,
+ session,
+ &h_blind,
+ &collectable);
if (GNUNET_SYSERR == res)
{
GNUNET_break (0);
@@ -279,8 +303,8 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
{
res = TALER_MINT_reply_withdraw_sign_success (connection,
&collectable);
- GNUNET_CRYPTO_rsa_signature_free (collectable.sig);
- GNUNET_CRYPTO_rsa_public_key_free (collectable.denom_pub);
+ GNUNET_CRYPTO_rsa_signature_free (collectable.sig.rsa_signature);
+ GNUNET_CRYPTO_rsa_public_key_free (collectable.denom_pub.rsa_public_key);
return res;
}
GNUNET_assert (GNUNET_NO == res);
@@ -299,18 +323,21 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
"Denomination not found");
}
if (GNUNET_OK !=
- TALER_MINT_DB_transaction (db_conn))
+ plugin->start (plugin->cls,
+ session))
{
GNUNET_break (0);
TALER_MINT_key_state_release (key_state);
return TALER_MINT_reply_internal_db_error (connection);
}
- rh = TALER_MINT_DB_get_reserve_history (db_conn,
- reserve);
+ rh = plugin->get_reserve_history (plugin->cls,
+ session,
+ reserve);
if (NULL == rh)
{
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
TALER_MINT_key_state_release (key_state);
return TALER_MINT_reply_json_pack (connection,
MHD_HTTP_NOT_FOUND,
@@ -320,8 +347,21 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
}
/* calculate amount required including fees */
- amount_required = TALER_amount_add (TALER_amount_ntoh (dki->issue.value),
- TALER_amount_ntoh (dki->issue.fee_withdraw));
+ TALER_amount_ntoh (&value,
+ &dki->issue.value);
+ TALER_amount_ntoh (&fee_withdraw,
+ &dki->issue.fee_withdraw);
+
+ if (GNUNET_OK !=
+ TALER_amount_add (&amount_required,
+ &value,
+ &fee_withdraw))
+ {
+ plugin->rollback (plugin->cls,
+ session);
+ TALER_MINT_key_state_release (key_state);
+ return TALER_MINT_reply_internal_db_error (connection);
+ }
/* calculate balance of the reserve */
res = 0;
@@ -333,70 +373,96 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
if (0 == (res & 1))
deposit_total = pos->details.bank->amount;
else
- deposit_total = TALER_amount_add (deposit_total,
- pos->details.bank->amount);
+ if (GNUNET_OK !=
+ TALER_amount_add (&deposit_total,
+ &deposit_total,
+ &pos->details.bank->amount))
+ {
+ plugin->rollback (plugin->cls,
+ session);
+ TALER_MINT_key_state_release (key_state);
+ return TALER_MINT_reply_internal_db_error (connection);
+ }
res |= 1;
break;
case TALER_MINT_DB_RO_WITHDRAW_COIN:
tdki = TALER_MINT_get_denom_key (key_state,
- pos->details.withdraw->denom_pub);
- value = TALER_amount_ntoh (tdki->issue.value);
+ &pos->details.withdraw->denom_pub);
+ TALER_amount_ntoh (&value,
+ &tdki->issue.value);
if (0 == (res & 2))
withdraw_total = value;
else
- withdraw_total = TALER_amount_add (withdraw_total,
- value);
+ if (GNUNET_OK !=
+ TALER_amount_add (&withdraw_total,
+ &withdraw_total,
+ &value))
+ {
+ plugin->rollback (plugin->cls,
+ session);
+ TALER_MINT_key_state_release (key_state);
+ return TALER_MINT_reply_internal_db_error (connection);
+ }
res |= 2;
break;
}
}
- GNUNET_break (0 > TALER_amount_cmp (withdraw_total,
- deposit_total));
- balance = TALER_amount_subtract (deposit_total,
- withdraw_total);
- if (0 < TALER_amount_cmp (amount_required,
- balance))
+ /* All reserve balances should be non-negative */
+ GNUNET_break (GNUNET_SYSERR !=
+ TALER_amount_subtract (&balance,
+ &deposit_total,
+ &withdraw_total));
+ if (0 < TALER_amount_cmp (&amount_required,
+ &balance))
{
TALER_MINT_key_state_release (key_state);
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
res = TALER_MINT_reply_withdraw_sign_insufficient_funds (connection,
rh);
- TALER_MINT_DB_free_reserve_history (rh);
+ plugin->free_reserve_history (plugin->cls,
+ rh);
return res;
}
- TALER_MINT_DB_free_reserve_history (rh);
+ plugin->free_reserve_history (plugin->cls,
+ rh);
/* Balance is good, sign the coin! */
- sig = GNUNET_CRYPTO_rsa_sign (dki->denom_priv,
+ sig = GNUNET_CRYPTO_rsa_sign (dki->denom_priv.rsa_private_key,
blinded_msg,
blinded_msg_len);
TALER_MINT_key_state_release (key_state);
if (NULL == sig)
{
GNUNET_break (0);
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
return TALER_MINT_reply_internal_error (connection,
"Internal error");
}
- collectable.sig = sig;
- collectable.denom_pub = (struct GNUNET_CRYPTO_rsa_PublicKey *) denomination_pub;
+ collectable.sig.rsa_signature = sig;
+ collectable.denom_pub = *denomination_pub;
collectable.reserve_pub = *reserve;
GNUNET_CRYPTO_hash (blinded_msg,
blinded_msg_len,
&collectable.h_coin_envelope);
collectable.reserve_sig = *signature;
if (GNUNET_OK !=
- TALER_MINT_DB_insert_collectable_blindcoin (db_conn,
- &h_blind,
- &collectable))
+ plugin->insert_collectable_blindcoin (plugin->cls,
+ session,
+ &h_blind,
+ amount_required,
+ &collectable))
{
GNUNET_break (0);
GNUNET_CRYPTO_rsa_signature_free (sig);
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
return TALER_MINT_reply_internal_db_error (connection);
}
if (GNUNET_OK !=
- TALER_MINT_DB_commit (db_conn))
+ plugin->commit (plugin->cls,
+ session))
{
LOG_WARNING ("/withdraw/sign transaction commit failed\n");
return TALER_MINT_reply_commit_error (connection);
@@ -413,9 +479,9 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
* the database.
*
* @param connection the connection to send errors to
- * @param db_conn the database connection
+ * @param session the database connection
* @param key_state the mint's key state
- * @param session_pub the refresh session's public key
+ * @param session_hash hash identifying the refresh session
* @param coin_public_info the coin to melt
* @param coin_details details about the coin being melted
* @param oldcoin_index what is the number assigned to this coin
@@ -425,10 +491,9 @@ TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
*/
static int
refresh_accept_melts (struct MHD_Connection *connection,
- PGconn *db_conn,
+ struct TALER_MINTDB_Session *session,
const struct MintKeyState *key_state,
- const struct GNUNET_HashCode *melt_hash,
- const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
+ const struct GNUNET_HashCode *session_hash,
const struct TALER_CoinPublicInfo *coin_public_info,
const struct MeltDetails *coin_details,
uint16_t oldcoin_index)
@@ -437,11 +502,12 @@ refresh_accept_melts (struct MHD_Connection *connection,
struct TALER_MINT_DB_TransactionList *tl;
struct TALER_Amount coin_value;
struct TALER_Amount coin_residual;
+ struct TALER_Amount spent;
struct RefreshMelt melt;
int res;
dki = &TALER_MINT_get_denom_key (key_state,
- coin_public_info->denom_pub)->issue;
+ &coin_public_info->denom_pub)->issue;
if (NULL == dki)
return (MHD_YES ==
@@ -452,40 +518,57 @@ refresh_accept_melts (struct MHD_Connection *connection,
"denom not found"))
? GNUNET_NO : GNUNET_SYSERR;
- coin_value = TALER_amount_ntoh (dki->value);
- tl = TALER_MINT_DB_get_coin_transactions (db_conn,
- &coin_public_info->coin_pub);
- /* FIXME: #3636: compute how much value is left with this coin and
- compare to `expected_value`! (subtract from "coin_value") */
- coin_residual = coin_value;
- /* Refuse to refresh when the coin does not have enough money left to
- * pay the refreshing fees of the coin. */
-
- if (TALER_amount_cmp (coin_residual,
- coin_details->melt_amount) < 0)
+ TALER_amount_ntoh (&coin_value,
+ &dki->value);
+ /* fee for THIS transaction; the melt amount includes the fee! */
+ spent = coin_details->melt_amount_with_fee;
+ /* add historic transaction costs of this coin */
+ tl = plugin->get_coin_transactions (plugin->cls,
+ session,
+ &coin_public_info->coin_pub);
+ if (GNUNET_OK !=
+ calculate_transaction_list_totals (tl,
+ &spent,
+ &spent))
+ {
+ GNUNET_break (0);
+ plugin->free_coin_transaction_list (plugin->cls,
+ tl);
+ return TALER_MINT_reply_internal_db_error (connection);
+ }
+ /* Refuse to refresh when the coin's value is insufficient
+ for the cost of all transactions. */
+ if (TALER_amount_cmp (&coin_value,
+ &spent) < 0)
{
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_subtract (&coin_residual,
+ &spent,
+ &coin_details->melt_amount_with_fee));
res = (MHD_YES ==
TALER_MINT_reply_refresh_melt_insufficient_funds (connection,
&coin_public_info->coin_pub,
coin_value,
tl,
- coin_details->melt_amount,
+ coin_details->melt_amount_with_fee,
coin_residual))
? GNUNET_NO : GNUNET_SYSERR;
- TALER_MINT_DB_free_coin_transaction_list (tl);
+ plugin->free_coin_transaction_list (plugin->cls,
+ tl);
return res;
}
- TALER_MINT_DB_free_coin_transaction_list (tl);
+ plugin->free_coin_transaction_list (plugin->cls,
+ tl);
melt.coin = *coin_public_info;
melt.coin_sig = coin_details->melt_sig;
- melt.melt_hash = *melt_hash;
- melt.amount = coin_details->melt_amount;
+ melt.session_hash = *session_hash;
+ melt.amount_with_fee = coin_details->melt_amount_with_fee;
if (GNUNET_OK !=
- TALER_MINT_DB_insert_refresh_melt (db_conn,
- session_pub,
- oldcoin_index,
- &melt))
+ plugin->insert_refresh_melt (plugin->cls,
+ session,
+ oldcoin_index,
+ &melt))
{
GNUNET_break (0);
return GNUNET_SYSERR;
@@ -502,69 +585,68 @@ refresh_accept_melts (struct MHD_Connection *connection,
* melted and confirm the melting operation to the client.
*
* @param connection the MHD connection to handle
- * @param melt_hash hash code of the session the coins are melted into
- * @param refresh_session_pub public key of the refresh session
- * @param client_signature signature of the client (matching @a refresh_session_pub)
- * over the melting request
+ * @param session_hash hash code of the session the coins are melted into
* @param num_new_denoms number of entries in @a denom_pubs, size of y-dimension of @commit_coin array
* @param denum_pubs public keys of the coins we want to withdraw in the end
* @param coin_count number of entries in @a coin_public_infos and @a coin_melt_details, size of y-dimension of @commit_link array
* @param coin_public_infos information about the coins to melt
* @param coin_melt_details signatures and (residual) value of the respective coin should be melted
- * @param kappa size of x-dimension of @commit_coin and @commit_link arrays
* @param commit_coin 2d array of coin commitments (what the mint is to sign
- * once the "/refres/reveal" of cut and choose is done)
+ * once the "/refres/reveal" of cut and choose is done),
+ * x-dimension must be #KAPPA
* @param commit_link 2d array of coin link commitments (what the mint is
* to return via "/refresh/link" to enable linkage in the
* future)
+ * x-dimension must be #KAPPA
* @return MHD result code
*/
int
TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
- const struct GNUNET_HashCode *melt_hash,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- const struct GNUNET_CRYPTO_EddsaSignature *client_signature,
+ const struct GNUNET_HashCode *session_hash,
unsigned int num_new_denoms,
- struct GNUNET_CRYPTO_rsa_PublicKey *const*denom_pubs,
+ const struct TALER_DenominationPublicKey *denom_pubs,
unsigned int coin_count,
const struct TALER_CoinPublicInfo *coin_public_infos,
const struct MeltDetails *coin_melt_details,
- unsigned int kappa,
struct RefreshCommitCoin *const* commit_coin,
struct RefreshCommitLink *const* commit_link)
{
struct MintKeyState *key_state;
- struct RefreshSession session;
- PGconn *db_conn;
+ struct RefreshSession refresh_session;
+ struct TALER_MINTDB_Session *session;
int res;
unsigned int i;
- unsigned int j;
- if (NULL == (db_conn = TALER_MINT_DB_get_connection (GNUNET_NO)))
+ if (NULL == (session = plugin->get_session (plugin->cls,
+ GNUNET_NO)))
{
GNUNET_break (0);
return TALER_MINT_reply_internal_db_error (connection);
}
if (GNUNET_OK !=
- TALER_MINT_DB_transaction (db_conn))
+ plugin->start (plugin->cls,
+ session))
{
GNUNET_break (0);
return TALER_MINT_reply_internal_db_error (connection);
}
- res = TALER_MINT_DB_get_refresh_session (db_conn,
- refresh_session_pub,
- &session);
+ res = plugin->get_refresh_session (plugin->cls,
+ session,
+ session_hash,
+ &refresh_session);
if (GNUNET_YES == res)
{
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
res = TALER_MINT_reply_refresh_melt_success (connection,
- &session.session_hash,
- session.noreveal_index);
+ session_hash,
+ refresh_session.noreveal_index);
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
}
if (GNUNET_SYSERR == res)
{
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
return TALER_MINT_reply_internal_db_error (connection);
}
@@ -574,98 +656,95 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
{
if (GNUNET_OK !=
(res = refresh_accept_melts (connection,
- db_conn,
+ session,
key_state,
- melt_hash,
- refresh_session_pub,
+ session_hash,
&coin_public_infos[i],
&coin_melt_details[i],
i)))
{
TALER_MINT_key_state_release (key_state);
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
}
}
TALER_MINT_key_state_release (key_state);
/* store requested new denominations */
- for (i=0;i<num_new_denoms;i++)
+ if (GNUNET_OK !=
+ plugin->insert_refresh_order (plugin->cls,
+ session,
+ session_hash,
+ num_new_denoms,
+ denom_pubs))
{
- if (GNUNET_OK !=
- TALER_MINT_DB_insert_refresh_order (db_conn,
- refresh_session_pub,
- i,
- denom_pubs[i]))
- {
- TALER_MINT_DB_rollback (db_conn);
- return TALER_MINT_reply_internal_db_error (connection);
- }
+ plugin->rollback (plugin->cls,
+ session);
+ return TALER_MINT_reply_internal_db_error (connection);
}
- for (i = 0; i < kappa; i++)
+ for (i = 0; i < KAPPA; i++)
{
- for (j = 0; j < num_new_denoms; j++)
+ if (GNUNET_OK !=
+ plugin->insert_refresh_commit_coins (plugin->cls,
+ session,
+ session_hash,
+ i,
+ num_new_denoms,
+ commit_coin[i]))
{
- if (GNUNET_OK !=
- TALER_MINT_DB_insert_refresh_commit_coin (db_conn,
- refresh_session_pub,
- i,
- j,
- &commit_coin[i][j]))
- {
- TALER_MINT_DB_rollback (db_conn);
- return TALER_MINT_reply_internal_db_error (connection);
- }
+ plugin->rollback (plugin->cls,
+ session);
+ return TALER_MINT_reply_internal_db_error (connection);
}
}
- for (i = 0; i < kappa; i++)
+ for (i = 0; i < KAPPA; i++)
{
- for (j = 0; j < coin_count; j++)
+ if (GNUNET_OK !=
+ plugin->insert_refresh_commit_links (plugin->cls,
+ session,
+ session_hash,
+ i,
+ coin_count,
+ commit_link[i]))
{
- if (GNUNET_OK !=
- TALER_MINT_DB_insert_refresh_commit_link (db_conn,
- refresh_session_pub,
- i,
- j,
- &commit_link[i][j]))
- {
- TALER_MINT_DB_rollback (db_conn);
- return TALER_MINT_reply_internal_db_error (connection);
- }
+ plugin->rollback (plugin->cls,
+ session);
+ return TALER_MINT_reply_internal_db_error (connection);
}
}
/* store 'global' session data */
- session.melt_sig = *client_signature;
- session.session_hash = *melt_hash;
- session.num_oldcoins = coin_count;
- session.num_newcoins = num_new_denoms;
- session.kappa = KAPPA; // FIXME...
- session.noreveal_index
+ refresh_session.num_oldcoins = coin_count;
+ refresh_session.num_newcoins = num_new_denoms;
+ refresh_session.noreveal_index
= GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG,
- session.kappa);
+ KAPPA);
if (GNUNET_OK !=
- (res = TALER_MINT_DB_create_refresh_session (db_conn,
- refresh_session_pub,
- &session)))
+ (res = plugin->create_refresh_session (plugin->cls,
+ session,
+ session_hash,
+ &refresh_session)))
{
- TALER_MINT_DB_rollback (db_conn);
+ plugin->rollback (plugin->cls,
+ session);
return TALER_MINT_reply_internal_db_error (connection);
}
if (GNUNET_OK !=
- TALER_MINT_DB_commit (db_conn))
+ plugin->commit (plugin->cls,
+ session))
{
LOG_WARNING ("/refresh/melt transaction commit failed\n");
return TALER_MINT_reply_commit_error (connection);
}
return TALER_MINT_reply_refresh_melt_success (connection,
- &session.session_hash,
- session.noreveal_index);
+ session_hash,
+ refresh_session.noreveal_index);
}
@@ -673,67 +752,74 @@ TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
* Check if the given @a transfer_privs correspond to an honest
* commitment for the given session.
* Checks that the transfer private keys match their commitments.
- * Then derives the shared secret for each kappa, and check that they match.
+ * Then derives the shared secret for each #KAPPA, and check that they match.
*
* @param connection the MHD connection to handle
- * @param db_conn database connection to use
- * @param refresh_session session to query
+ * @param session database connection to use
+ * @param session_hash hash of session to query
* @param off commitment offset to check
* @param num_oldcoins size of the @a transfer_privs and @a melts arrays
* @param transfer_privs private transfer keys
* @param melts array of melted coins
* @param num_newcoins number of newcoins being generated
- * @param denom_pub array of @a num_newcoins keys for the new coins
+ * @param denom_pubs array of @a num_newcoins keys for the new coins
* @return #GNUNET_OK if the committment was honest,
* #GNUNET_NO if there was a problem and we generated an error message
* #GNUNET_SYSERR if we could not even generate an error message
*/
static int
check_commitment (struct MHD_Connection *connection,
- PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
unsigned int off,
unsigned int num_oldcoins,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *transfer_privs,
+ const struct TALER_TransferPrivateKey *transfer_privs,
const struct RefreshMelt *melts,
unsigned int num_newcoins,
- struct GNUNET_CRYPTO_rsa_PublicKey *const*denom_pubs)
+ const struct TALER_DenominationPublicKey *denom_pubs)
{
unsigned int j;
- int res;
struct TALER_LinkSecret last_shared_secret;
int secret_initialized = GNUNET_NO;
+ struct GNUNET_CRYPTO_EcdhePublicKey coin_ecdhe;
+ struct GNUNET_CRYPTO_EcdhePrivateKey transfer_ecdhe;
+ struct RefreshCommitLink *commit_links;
+ struct RefreshCommitCoin *commit_coins;
+
+ commit_links = GNUNET_malloc (num_oldcoins *
+ sizeof (struct RefreshCommitLink));
+ if (GNUNET_OK !=
+ plugin->get_refresh_commit_links (plugin->cls,
+ session,
+ session_hash,
+ off,
+ num_oldcoins,
+ commit_links))
+ {
+ GNUNET_break (0);
+ GNUNET_free (commit_links);
+ return (MHD_YES == TALER_MINT_reply_internal_db_error (connection))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ }
for (j = 0; j < num_oldcoins; j++)
{
- struct RefreshCommitLink commit_link;
struct TALER_TransferSecret transfer_secret;
struct TALER_LinkSecret shared_secret;
- struct GNUNET_CRYPTO_EcdsaPublicKey transfer_pub_check;
-
- res = TALER_MINT_DB_get_refresh_commit_link (db_conn,
- refresh_session,
- off,
- j,
- &commit_link);
- if (GNUNET_OK != res)
- {
- GNUNET_break (0);
- return (MHD_YES == TALER_MINT_reply_internal_db_error (connection))
- ? GNUNET_NO : GNUNET_SYSERR;
- }
+ struct TALER_TransferPublicKey transfer_pub_check;
- GNUNET_CRYPTO_ecdsa_key_get_public (&transfer_privs[j],
- &transfer_pub_check);
+ GNUNET_CRYPTO_ecdsa_key_get_public (&transfer_privs[j].ecdsa_priv,
+ &transfer_pub_check.ecdsa_pub);
if (0 !=
memcmp (&transfer_pub_check,
- &commit_link.transfer_pub,
- sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
+ &commit_links[j].transfer_pub,
+ sizeof (struct TALER_TransferPublicKey)))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"transfer keys do not match\n");
+ GNUNET_free (commit_links);
/* FIXME: return more specific error with original signature (#3712) */
- return (MHD_YES ==
+ return (MHD_YES ==
TALER_MINT_reply_refresh_reveal_missmatch (connection,
off,
j,
@@ -743,25 +829,31 @@ check_commitment (struct MHD_Connection *connection,
/* We're converting key types here, which is not very nice
* but necessary and harmless (keys will be thrown away later). */
- /* FIXME: ECDHE/ECDSA-key type confusion! Can we reduce/avoid this? */
+ GNUNET_CRYPTO_ecdsa_public_to_ecdhe (&melts[j].coin.coin_pub.ecdsa_pub,
+ &coin_ecdhe);
+ GNUNET_CRYPTO_ecdsa_private_to_ecdhe (&transfer_privs[j].ecdsa_priv,
+ &transfer_ecdhe);
if (GNUNET_OK !=
- GNUNET_CRYPTO_ecc_ecdh ((const struct GNUNET_CRYPTO_EcdhePrivateKey *) &transfer_privs[j],
- (const struct GNUNET_CRYPTO_EcdhePublicKey *) &melts[j].coin.coin_pub,
+ GNUNET_CRYPTO_ecc_ecdh (&transfer_ecdhe,
+ &coin_ecdhe,
&transfer_secret.key))
{
GNUNET_break (0);
+ GNUNET_CRYPTO_ecdhe_key_clear (&transfer_ecdhe);
+ GNUNET_free (commit_links);
return (MHD_YES == TALER_MINT_reply_internal_error (connection,
"ECDH error"))
? GNUNET_NO : GNUNET_SYSERR;
}
-
+ GNUNET_CRYPTO_ecdhe_key_clear (&transfer_ecdhe);
if (GNUNET_OK !=
- TALER_transfer_decrypt (&commit_link.shared_secret_enc,
+ TALER_transfer_decrypt (&commit_links[j].shared_secret_enc,
&transfer_secret,
&shared_secret))
{
GNUNET_break (0);
- return (MHD_YES ==
+ GNUNET_free (commit_links);
+ return (MHD_YES ==
TALER_MINT_reply_internal_error (connection,
"Decryption error"))
? GNUNET_NO : GNUNET_SYSERR;
@@ -778,6 +870,7 @@ check_commitment (struct MHD_Connection *connection,
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"shared secrets do not match\n");
+ GNUNET_free (commit_links);
/* FIXME: return more specific error with original signature (#3712) */
return (MHD_YES ==
TALER_MINT_reply_refresh_reveal_missmatch (connection,
@@ -788,71 +881,75 @@ check_commitment (struct MHD_Connection *connection,
}
}
GNUNET_break (GNUNET_YES == secret_initialized);
-
+ GNUNET_free (commit_links);
/* Check that the commitments for all new coins were correct */
+ commit_coins = GNUNET_malloc (num_newcoins *
+ sizeof (struct RefreshCommitCoin));
+
+ if (GNUNET_OK !=
+ plugin->get_refresh_commit_coins (plugin->cls,
+ session,
+ session_hash,
+ off,
+ num_newcoins,
+ commit_coins))
+ {
+ GNUNET_break (0);
+ GNUNET_free (commit_coins);
+ return (MHD_YES == TALER_MINT_reply_internal_db_error (connection))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ }
+
for (j = 0; j < num_newcoins; j++)
{
- struct RefreshCommitCoin commit_coin;
struct TALER_RefreshLinkDecrypted *link_data;
- struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub;
+ struct TALER_CoinSpendPublicKey coin_pub;
struct GNUNET_HashCode h_msg;
char *buf;
size_t buf_len;
- res = TALER_MINT_DB_get_refresh_commit_coin (db_conn,
- refresh_session,
- off,
- j,
- &commit_coin);
- if (GNUNET_OK != res)
- {
- GNUNET_break (0);
- return (MHD_YES == TALER_MINT_reply_internal_db_error (connection))
- ? GNUNET_NO : GNUNET_SYSERR;
- }
-
- link_data = TALER_refresh_decrypt (commit_coin.refresh_link,
+ link_data = TALER_refresh_decrypt (commit_coins[j].refresh_link,
&last_shared_secret);
if (NULL == link_data)
{
GNUNET_break (0);
+ GNUNET_free (commit_coins);
return (MHD_YES == TALER_MINT_reply_internal_error (connection,
"Decryption error"))
? GNUNET_NO : GNUNET_SYSERR;
}
- GNUNET_CRYPTO_ecdsa_key_get_public (&link_data->coin_priv,
- &coin_pub);
- /* FIXME: we had envisioned a more complex scheme to derive
- the message to sign for a blinded coin...
- FIXME: we should have a function in util/ to do this! */
+ GNUNET_CRYPTO_ecdsa_key_get_public (&link_data->coin_priv.ecdsa_priv,
+ &coin_pub.ecdsa_pub);
GNUNET_CRYPTO_hash (&coin_pub,
- sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
+ sizeof (struct TALER_CoinSpendPublicKey),
&h_msg);
if (0 == (buf_len =
GNUNET_CRYPTO_rsa_blind (&h_msg,
- link_data->blinding_key,
- denom_pubs[j],
+ link_data->blinding_key.rsa_blinding_key,
+ denom_pubs[j].rsa_public_key,
&buf)))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"blind failed\n");
+ GNUNET_free (commit_coins);
return (MHD_YES == TALER_MINT_reply_internal_error (connection,
"Blinding error"))
? GNUNET_NO : GNUNET_SYSERR;
}
- if ( (buf_len != commit_coin.coin_ev_size) ||
+ if ( (buf_len != commit_coins[j].coin_ev_size) ||
(0 != memcmp (buf,
- commit_coin.coin_ev,
+ commit_coins[j].coin_ev,
buf_len)) )
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "blind envelope does not match for kappa=%u, old=%d\n",
+ "blind envelope does not match for k=%u, old=%d\n",
off,
(int) j);
/* FIXME: return more specific error with original signature (#3712) */
+ GNUNET_free (commit_coins);
return (MHD_YES ==
TALER_MINT_reply_refresh_reveal_missmatch (connection,
off,
@@ -862,6 +959,7 @@ check_commitment (struct MHD_Connection *connection,
}
GNUNET_free (buf);
}
+ GNUNET_free (commit_coins);
return GNUNET_OK;
}
@@ -872,62 +970,53 @@ check_commitment (struct MHD_Connection *connection,
* envelope from the database and performs the signing operation.
*
* @param connection the MHD connection to handle
- * @param db_conn database connection to use
- * @param refresh_session session to query
+ * @param session database connection to use
+ * @param session_hash hash of session to query
* @param key_state key state to lookup denomination pubs
* @param denom_pub denomination key for the coin to create
- * @param noreveal_index which index should we use to obtain the
- * envelope for the coin, based on cut-and-choose
+ * @param commit_coin the coin that was committed
* @param coin_off number of the coin
* @return NULL on error, otherwise signature over the coin
*/
-static struct GNUNET_CRYPTO_rsa_Signature *
+static struct TALER_DenominationSignature
refresh_mint_coin (struct MHD_Connection *connection,
- PGconn *db_conn,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session,
+ struct TALER_MINTDB_Session *session,
+ const struct GNUNET_HashCode *session_hash,
struct MintKeyState *key_state,
- const struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub,
- unsigned int noreveal_index,
+ const struct TALER_DenominationPublicKey *denom_pub,
+ const struct RefreshCommitCoin *commit_coin,
unsigned int coin_off)
{
- struct RefreshCommitCoin commit_coin;
struct TALER_MINT_DenomKeyIssuePriv *dki;
- struct GNUNET_CRYPTO_rsa_Signature *ev_sig;
- int res;
+ struct TALER_DenominationSignature ev_sig;
- res = TALER_MINT_DB_get_refresh_commit_coin (db_conn,
- refresh_session,
- noreveal_index,
- coin_off,
- &commit_coin);
- if (GNUNET_OK != res)
- {
- GNUNET_break (0);
- return NULL;
- }
- dki = TALER_MINT_get_denom_key (key_state, denom_pub);
+ dki = TALER_MINT_get_denom_key (key_state,
+ denom_pub);
if (NULL == dki)
{
GNUNET_break (0);
- return NULL;
+ ev_sig.rsa_signature = NULL;
+ return ev_sig;
}
- ev_sig = GNUNET_CRYPTO_rsa_sign (dki->denom_priv,
- commit_coin.coin_ev,
- commit_coin.coin_ev_size);
- if (NULL == ev_sig)
+ ev_sig.rsa_signature
+ = GNUNET_CRYPTO_rsa_sign (dki->denom_priv.rsa_private_key,
+ commit_coin->coin_ev,
+ commit_coin->coin_ev_size);
+ if (NULL == ev_sig.rsa_signature)
{
GNUNET_break (0);
- return NULL;
+ return ev_sig;
}
if (GNUNET_OK !=
- TALER_MINT_DB_insert_refresh_collectable (db_conn,
- refresh_session,
- coin_off,
- ev_sig))
+ plugin->insert_refresh_collectable (plugin->cls,
+ session,
+ session_hash,
+ coin_off,
+ &ev_sig))
{
GNUNET_break (0);
- GNUNET_CRYPTO_rsa_signature_free (ev_sig);
- return NULL;
+ GNUNET_CRYPTO_rsa_signature_free (ev_sig.rsa_signature);
+ ev_sig.rsa_signature = NULL;
}
return ev_sig;
}
@@ -935,48 +1024,50 @@ refresh_mint_coin (struct MHD_Connection *connection,
/**
* Execute a "/refresh/reveal". The client is revealing to us the
- * transfer keys for @a kappa-1 sets of coins. Verify that the
+ * transfer keys for @a #KAPPA-1 sets of coins. Verify that the
* revealed transfer keys would allow linkage to the blinded coins,
* and if so, return the signed coins for corresponding to the set of
* coins that was not chosen.
*
* @param connection the MHD connection to handle
- * @param refresh_session_pub public key of the refresh session
- * @param kappa size of x-dimension of @transfer_privs array plus one (!)
+ * @param session_hash hash identifying the refresh session
* @param num_oldcoins size of y-dimension of @transfer_privs array
- * @param transfer_pubs array with the revealed transfer keys
+ * @param transfer_pubs array with the revealed transfer keys,
+ * x-dimension must be #KAPPA - 1
* @return MHD result code
*/
int
TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- unsigned int kappa,
+ const struct GNUNET_HashCode *session_hash,
unsigned int num_oldcoins,
- struct GNUNET_CRYPTO_EcdsaPrivateKey *const*transfer_privs)
+ struct TALER_TransferPrivateKey **transfer_privs)
{
int res;
- PGconn *db_conn;
+ struct TALER_MINTDB_Session *session;
struct RefreshSession refresh_session;
struct MintKeyState *key_state;
struct RefreshMelt *melts;
- struct GNUNET_CRYPTO_rsa_PublicKey **denom_pubs;
- struct GNUNET_CRYPTO_rsa_Signature **ev_sigs;
+ struct TALER_DenominationPublicKey *denom_pubs;
+ struct TALER_DenominationSignature *ev_sigs;
+ struct RefreshCommitCoin *commit_coins;
unsigned int i;
unsigned int j;
unsigned int off;
- if (NULL == (db_conn = TALER_MINT_DB_get_connection (GNUNET_NO)))
+ if (NULL == (session = plugin->get_session (plugin->cls,
+ GNUNET_NO)))
{
GNUNET_break (0);
return TALER_MINT_reply_internal_db_error (connection);
}
- res = TALER_MINT_DB_get_refresh_session (db_conn,
- refresh_session_pub,
- &refresh_session);
+ res = plugin->get_refresh_session (plugin->cls,
+ session,
+ session_hash,
+ &refresh_session);
if (GNUNET_NO == res)
return TALER_MINT_reply_arg_invalid (connection,
- "session_pub");
+ "session_hash");
if (GNUNET_SYSERR == res)
return TALER_MINT_reply_internal_db_error (connection);
if (0 == refresh_session.num_oldcoins)
@@ -990,10 +1081,11 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection,
for (j=0;j<refresh_session.num_oldcoins;j++)
{
if (GNUNET_OK !=
- TALER_MINT_DB_get_refresh_melt (db_conn,
- refresh_session_pub,
- j,
- &melts[j]))
+ plugin->get_refresh_melt (plugin->cls,
+ session,
+ session_hash,
+ j,
+ &melts[j]))
{
GNUNET_break (0);
GNUNET_free (melts);
@@ -1001,34 +1093,31 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection,
}
}
denom_pubs = GNUNET_malloc (refresh_session.num_newcoins *
- sizeof (struct GNUNET_CRYPTO_rsa_PublicKey *));
- for (j=0;j<refresh_session.num_newcoins;j++)
+ sizeof (struct TALER_DenominationPublicKey));
+ if (GNUNET_OK !=
+ plugin->get_refresh_order (plugin->cls,
+ session,
+ session_hash,
+ refresh_session.num_newcoins,
+ denom_pubs))
{
- denom_pubs[j] = TALER_MINT_DB_get_refresh_order (db_conn,
- refresh_session_pub,
- j);
- if (NULL == denom_pubs[j])
- {
- GNUNET_break (0);
- for (i=0;i<j;i++)
- GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[i]);
- GNUNET_free (denom_pubs);
- GNUNET_free (melts);
- return (MHD_YES == TALER_MINT_reply_internal_db_error (connection))
- ? GNUNET_NO : GNUNET_SYSERR;
- }
+ GNUNET_break (0);
+ GNUNET_free (denom_pubs);
+ GNUNET_free (melts);
+ return (MHD_YES == TALER_MINT_reply_internal_db_error (connection))
+ ? GNUNET_NO : GNUNET_SYSERR;
}
off = 0;
- for (i=0;i<refresh_session.kappa - 1;i++)
+ for (i=0;i<KAPPA - 1;i++)
{
if (i == refresh_session.noreveal_index)
off = 1;
if (GNUNET_OK !=
(res = check_commitment (connection,
- db_conn,
- refresh_session_pub,
+ session,
+ session_hash,
i + off,
refresh_session.num_oldcoins,
transfer_privs[i + off],
@@ -1037,7 +1126,7 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection,
denom_pubs)))
{
for (j=0;j<refresh_session.num_newcoins;j++)
- GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j]);
+ GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key);
GNUNET_free (denom_pubs);
GNUNET_free (melts);
return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
@@ -1047,50 +1136,71 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection,
/* Client request OK, start transaction */
if (GNUNET_OK !=
- TALER_MINT_DB_transaction (db_conn))
+ plugin->start (plugin->cls,
+ session))
{
GNUNET_break (0);
for (j=0;j<refresh_session.num_newcoins;j++)
- GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j]);
+ GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key);
GNUNET_free (denom_pubs);
return TALER_MINT_reply_internal_db_error (connection);
}
+ commit_coins = GNUNET_malloc (refresh_session.num_newcoins *
+ sizeof (struct RefreshCommitCoin));
+ if (GNUNET_OK !=
+ plugin->get_refresh_commit_coins (plugin->cls,
+ session,
+ session_hash,
+ refresh_session.noreveal_index,
+ refresh_session.num_newcoins,
+ commit_coins))
+ {
+ GNUNET_break (0);
+ GNUNET_free (commit_coins);
+ for (j=0;j<refresh_session.num_newcoins;j++)
+ GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key);
+ GNUNET_free (denom_pubs);
+ return TALER_MINT_reply_internal_db_error (connection);
+ }
ev_sigs = GNUNET_malloc (refresh_session.num_newcoins *
- sizeof (struct GNUNET_CRYPTO_rsa_Signature *));
+ sizeof (struct TALER_DenominationSignature));
key_state = TALER_MINT_key_state_acquire ();
for (j=0;j<refresh_session.num_newcoins;j++)
{
ev_sigs[j] = refresh_mint_coin (connection,
- db_conn,
- refresh_session_pub,
+ session,
+ session_hash,
key_state,
- denom_pubs[j],
- refresh_session.noreveal_index,
+ &denom_pubs[j],
+ &commit_coins[j],
j);
- if (NULL == ev_sigs[j])
+ if (NULL == ev_sigs[j].rsa_signature)
{
TALER_MINT_key_state_release (key_state);
for (i=0;i<j;i++)
- GNUNET_CRYPTO_rsa_signature_free (ev_sigs[i]);
+ GNUNET_CRYPTO_rsa_signature_free (ev_sigs[i].rsa_signature);
GNUNET_free (ev_sigs);
for (j=0;j<refresh_session.num_newcoins;j++)
- GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j]);
+ GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key);
GNUNET_free (denom_pubs);
+ GNUNET_free (commit_coins);
return TALER_MINT_reply_internal_db_error (connection);
}
}
TALER_MINT_key_state_release (key_state);
for (j=0;j<refresh_session.num_newcoins;j++)
- GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j]);
+ GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key);
GNUNET_free (denom_pubs);
+ GNUNET_free (commit_coins);
if (GNUNET_OK !=
- TALER_MINT_DB_commit (db_conn))
+ plugin->commit (plugin->cls,
+ session))
{
LOG_WARNING ("/refresh/reveal transaction commit failed\n");
for (i=0;i<refresh_session.num_newcoins;i++)
- GNUNET_CRYPTO_rsa_signature_free (ev_sigs[i]);
+ GNUNET_CRYPTO_rsa_signature_free (ev_sigs[i].rsa_signature);
GNUNET_free (ev_sigs);
return TALER_MINT_reply_commit_error (connection);
}
@@ -1099,7 +1209,7 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection,
refresh_session.num_newcoins,
ev_sigs);
for (i=0;i<refresh_session.num_newcoins;i++)
- GNUNET_CRYPTO_rsa_signature_free (ev_sigs[i]);
+ GNUNET_CRYPTO_rsa_signature_free (ev_sigs[i].rsa_signature);
GNUNET_free (ev_sigs);
return res;
}
@@ -1116,23 +1226,25 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection,
*/
int
TALER_MINT_db_execute_refresh_link (struct MHD_Connection *connection,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub)
+ const struct TALER_CoinSpendPublicKey *coin_pub)
{
int res;
- PGconn *db_conn;
- struct GNUNET_CRYPTO_EcdsaPublicKey transfer_pub;
+ struct TALER_MINTDB_Session *session;
+ struct TALER_TransferPublicKey transfer_pub;
struct TALER_EncryptedLinkSecret shared_secret_enc;
struct LinkDataList *ldl;
- if (NULL == (db_conn = TALER_MINT_DB_get_connection (GNUNET_NO)))
+ if (NULL == (session = plugin->get_session (plugin->cls,
+ GNUNET_NO)))
{
GNUNET_break (0);
return TALER_MINT_reply_internal_db_error (connection);
}
- res = TALER_db_get_transfer (db_conn,
- coin_pub,
- &transfer_pub,
- &shared_secret_enc);
+ res = plugin->get_transfer (plugin->cls,
+ session,
+ coin_pub,
+ &transfer_pub,
+ &shared_secret_enc);
if (GNUNET_SYSERR == res)
{
GNUNET_break (0);
@@ -1148,7 +1260,9 @@ TALER_MINT_db_execute_refresh_link (struct MHD_Connection *connection,
}
GNUNET_assert (GNUNET_OK == res);
- ldl = TALER_db_get_link (db_conn, coin_pub);
+ ldl = plugin->get_link_data_list (plugin->cls,
+ session,
+ coin_pub);
if (NULL == ldl)
{
return TALER_MINT_reply_json_pack (connection,
@@ -1161,7 +1275,8 @@ TALER_MINT_db_execute_refresh_link (struct MHD_Connection *connection,
&transfer_pub,
&shared_secret_enc,
ldl);
- TALER_db_link_data_list_free (ldl);
+ plugin->free_link_data_list (plugin->cls,
+ ldl);
return res;
}
diff --git a/src/mint/taler-mint-httpd_db.h b/src/mint/taler-mint-httpd_db.h
index 84e65eef2..b2061850c 100644
--- a/src/mint/taler-mint-httpd_db.h
+++ b/src/mint/taler-mint-httpd_db.h
@@ -25,8 +25,7 @@
#include <microhttpd.h>
#include <gnunet/gnunet_util_lib.h>
#include "taler_util.h"
-#include "taler-mint-httpd_keys.h"
-#include "mint_db.h"
+#include "taler_mintdb_plugin.h"
/**
@@ -54,7 +53,7 @@ TALER_MINT_db_execute_deposit (struct MHD_Connection *connection,
*/
int
TALER_MINT_db_execute_withdraw_status (struct MHD_Connection *connection,
- const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub);
+ const struct TALER_ReservePublicKey *reserve_pub);
/**
@@ -73,11 +72,11 @@ TALER_MINT_db_execute_withdraw_status (struct MHD_Connection *connection,
*/
int
TALER_MINT_db_execute_withdraw_sign (struct MHD_Connection *connection,
- const struct GNUNET_CRYPTO_EddsaPublicKey *reserve,
- const struct GNUNET_CRYPTO_rsa_PublicKey *denomination_pub,
+ const struct TALER_ReservePublicKey *reserve,
+ const struct TALER_DenominationPublicKey *denomination_pub,
const char *blinded_msg,
size_t blinded_msg_len,
- const struct GNUNET_CRYPTO_EddsaSignature *signature);
+ const struct TALER_ReserveSignature *signature);
/**
@@ -89,14 +88,14 @@ struct MeltDetails
* Signature allowing the melt (using
* a `struct RefreshMeltConfirmSignRequestBody`) to sign over.
*/
- struct GNUNET_CRYPTO_EcdsaSignature melt_sig;
+ struct TALER_CoinSpendSignature melt_sig;
/**
* How much of the coin's value did the client allow to be melted?
* This amount includes the fees, so the final amount contributed
* to the melt is this value minus the fee for melting the coin.
*/
- struct TALER_Amount melt_amount;
+ struct TALER_Amount melt_amount_with_fee;
};
@@ -107,19 +106,13 @@ struct MeltDetails
* required value left and if so, store that they have been
* melted and confirm the melting operation to the client.
*
- * FIXME: some arguments are redundant here...
- *
* @param connection the MHD connection to handle
- * @param melt_hash hash code of the session the coins are melted into
- * @param refresh_session_pub public key of the refresh session
- * @param client_signature signature of the client (matching @a refresh_session_pub)
- * over the melting request
+ * @param session_hash hash code of the session the coins are melted into
* @param num_new_denoms number of entries in @a denom_pubs, size of y-dimension of @commit_coin array
* @param denum_pubs array of public denomination keys for the refresh (?)
* @param coin_count number of entries in @a coin_public_infos and @ a coin_melt_details, size of y-dimension of @commit_link array
* @param coin_public_infos information about the coins to melt
* @param coin_melt_details signatures and (residual) value of the respective coin should be melted
- * @param kappa size of x-dimension of @commit_coin and @commit_link arrays
* @param commit_coin 2d array of coin commitments (what the mint is to sign
* once the "/refres/reveal" of cut and choose is done)
* @param commit_link 2d array of coin link commitments (what the mint is
@@ -127,42 +120,36 @@ struct MeltDetails
* future)
* @return MHD result code
*/
-// FIXME: see #3635.
int
TALER_MINT_db_execute_refresh_melt (struct MHD_Connection *connection,
- const struct GNUNET_HashCode *melt_hash,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- const struct GNUNET_CRYPTO_EddsaSignature *client_signature,
+ const struct GNUNET_HashCode *session_hash,
unsigned int num_new_denoms,
- struct GNUNET_CRYPTO_rsa_PublicKey *const*denom_pubs,
+ const struct TALER_DenominationPublicKey *denom_pubs,
unsigned int coin_count,
const struct TALER_CoinPublicInfo *coin_public_infos,
const struct MeltDetails *coin_melt_details,
- unsigned int kappa,
struct RefreshCommitCoin *const* commit_coin,
struct RefreshCommitLink *const* commit_link);
/**
* Execute a "/refresh/reveal". The client is revealing to us the
- * transfer keys for @a kappa-1 sets of coins. Verify that the
+ * transfer keys for #KAPPA-1 sets of coins. Verify that the
* revealed transfer keys would allow linkage to the blinded coins,
* and if so, return the signed coins for corresponding to the set of
* coins that was not chosen.
*
* @param connection the MHD connection to handle
- * @param refresh_session_pub public key of the refresh session
- * @param kappa size of x-dimension of @transfer_privs array plus one (!)
+ * @param session_hash hash over the refresh session
* @param num_oldcoins size of y-dimension of @transfer_privs array
- * @param transfer_pubs array with the revealed transfer keys
+ * @param transfer_pubs array with the revealed transfer keys, #KAPPA is 1st-dimension
* @return MHD result code
*/
int
TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- unsigned int kappa,
+ const struct GNUNET_HashCode *session_hash,
unsigned int num_oldcoins,
- struct GNUNET_CRYPTO_EcdsaPrivateKey *const*transfer_privs);
+ struct TALER_TransferPrivateKey **transfer_privs);
/**
@@ -176,7 +163,7 @@ TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection,
*/
int
TALER_MINT_db_execute_refresh_link (struct MHD_Connection *connection,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub);
+ const struct TALER_CoinSpendPublicKey *coin_pub);
#endif
diff --git a/src/mint/taler-mint-httpd_deposit.c b/src/mint/taler-mint-httpd_deposit.c
index 915a7389c..7ecf8bfe6 100644
--- a/src/mint/taler-mint-httpd_deposit.c
+++ b/src/mint/taler-mint-httpd_deposit.c
@@ -32,11 +32,10 @@
#include <microhttpd.h>
#include <libpq-fe.h>
#include <pthread.h>
-#include "mint_db.h"
+#include "taler_mintdb_plugin.h"
#include "taler_signatures.h"
#include "taler_util.h"
#include "taler-mint-httpd_parsing.h"
-#include "taler-mint-httpd_keys.h"
#include "taler-mint-httpd_db.h"
#include "taler-mint-httpd_deposit.h"
#include "taler-mint-httpd_responses.h"
@@ -60,19 +59,21 @@ verify_and_execute_deposit (struct MHD_Connection *connection,
struct MintKeyState *key_state;
struct TALER_DepositRequest dr;
struct TALER_MINT_DenomKeyIssuePriv *dki;
+ struct TALER_Amount fee_deposit;
dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_DEPOSIT);
dr.purpose.size = htonl (sizeof (struct TALER_DepositRequest));
dr.h_contract = deposit->h_contract;
dr.h_wire = deposit->h_wire;
dr.transaction_id = GNUNET_htonll (deposit->transaction_id);
- dr.amount = TALER_amount_hton (deposit->amount);
+ TALER_amount_hton (&dr.amount_with_fee,
+ &deposit->amount_with_fee);
dr.coin_pub = deposit->coin.coin_pub;
if (GNUNET_OK !=
GNUNET_CRYPTO_ecdsa_verify (TALER_SIGNATURE_WALLET_DEPOSIT,
&dr.purpose,
- &deposit->csig,
- &deposit->coin.coin_pub))
+ &deposit->csig.ecdsa_signature,
+ &deposit->coin.coin_pub.ecdsa_pub))
{
LOG_WARNING ("Invalid signature on /deposit request\n");
return TALER_MINT_reply_arg_invalid (connection,
@@ -81,7 +82,7 @@ verify_and_execute_deposit (struct MHD_Connection *connection,
/* check denomination exists and is valid */
key_state = TALER_MINT_key_state_acquire ();
dki = TALER_MINT_get_denom_key (key_state,
- deposit->coin.denom_pub);
+ &deposit->coin.denom_pub);
if (NULL == dki)
{
TALER_MINT_key_state_release (key_state);
@@ -97,6 +98,17 @@ verify_and_execute_deposit (struct MHD_Connection *connection,
TALER_MINT_key_state_release (key_state);
return TALER_MINT_reply_coin_invalid (connection);
}
+ TALER_amount_ntoh (&fee_deposit,
+ &dki->issue.fee_deposit);
+ if (TALER_amount_cmp (&fee_deposit,
+ &deposit->amount_with_fee) < 0)
+ {
+ TALER_MINT_key_state_release (key_state);
+ return (MHD_YES ==
+ TALER_MINT_reply_external_error (connection,
+ "deposited amount smaller than depositing fee"))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ }
TALER_MINT_key_state_release (key_state);
return TALER_MINT_db_execute_deposit (connection,
@@ -119,7 +131,7 @@ static int
parse_and_handle_deposit_request (struct MHD_Connection *connection,
const json_t *root,
const struct TALER_Amount *amount,
- const json_t *wire)
+ json_t *wire)
{
int res;
struct Deposit deposit;
@@ -167,7 +179,7 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection,
GNUNET_free (wire_enc);
deposit.wire = wire;
- deposit.amount = *amount;
+ deposit.amount_with_fee = *amount;
res = verify_and_execute_deposit (connection,
&deposit);
TALER_MINT_release_parsed_data (spec);
diff --git a/src/mint/taler-mint-httpd_keys.c b/src/mint/taler-mint-httpd_keys.c
deleted file mode 100644
index c22040d00..000000000
--- a/src/mint/taler-mint-httpd_keys.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero 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 Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd_keys.c
- * @brief Handle /keys requests
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <jansson.h>
-#include <microhttpd.h>
-#include "taler-mint-httpd_keys.h"
-#include "taler-mint-httpd_keystate.h"
-
-
-/**
- * Function to call to handle the request by sending
- * back static data from the @a rh.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[IN|OUT] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TALER_MINT_handler_keys (struct RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size)
-{
- struct MintKeyState *key_state;
- struct MHD_Response *response;
- int ret;
-
- key_state = TALER_MINT_key_state_acquire ();
- response = MHD_create_response_from_buffer (strlen (key_state->keys_json),
- key_state->keys_json,
- MHD_RESPMEM_MUST_COPY);
- TALER_MINT_key_state_release (key_state);
- if (NULL == response)
- {
- GNUNET_break (0);
- return MHD_NO;
- }
- (void) MHD_add_response_header (response,
- "Content-Type",
- rh->mime_type);
- ret = MHD_queue_response (connection,
- rh->response_code,
- response);
- MHD_destroy_response (response);
- return ret;
-}
-
-
-/* end of taler-mint-httpd_keys.c */
diff --git a/src/mint/taler-mint-httpd_keys.h b/src/mint/taler-mint-httpd_keys.h
deleted file mode 100644
index bb1bc7216..000000000
--- a/src/mint/taler-mint-httpd_keys.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero 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 Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler-mint-httpd_keys.h
- * @brief Handle /keys requests and manage key state
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#ifndef TALER_MINT_HTTPD_KEYS_H
-#define TALER_MINT_HTTPD_KEYS_H
-
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-#include <jansson.h>
-#include "taler-mint-httpd.h"
-
-
-/**
- * Handle a "/keys" request
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[IN|OUT] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
- * @return MHD result code
- */
-int
-TALER_MINT_handler_keys (struct RequestHandler *rh,
- struct MHD_Connection *connection,
- void **connection_cls,
- const char *upload_data,
- size_t *upload_data_size);
-
-
-
-#endif
diff --git a/src/mint/taler-mint-httpd_keystate.c b/src/mint/taler-mint-httpd_keystate.c
index 7edae9f7b..c29c5c516 100644
--- a/src/mint/taler-mint-httpd_keystate.c
+++ b/src/mint/taler-mint-httpd_keystate.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014 GNUnet e.V.
+ Copyright (C) 2014, 2015 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
@@ -21,17 +21,73 @@
* @author Christian Grothoff
*/
#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
#include <pthread.h>
-#include "taler_signatures.h"
#include "taler-mint-httpd_keystate.h"
-#include "taler_util.h"
-#include "taler-mint-httpd_parsing.h"
+
+
+/**
+ * Snapshot of the (coin and signing) keys (including private keys) of
+ * the mint. There can be multiple instances of this struct, as it is
+ * reference counted and only destroyed once the last user is done
+ * with it. The current instance is acquired using
+ * #TALER_MINT_key_state_acquire(). Using this function increases the
+ * reference count. The contents of this structure (except for the
+ * reference counter) should be considered READ-ONLY until it is
+ * ultimately destroyed (as there can be many concurrent users).
+ */
+struct MintKeyState
+{
+ /**
+ * JSON array with denomination keys. (Currently not really used
+ * after initialization.)
+ */
+ json_t *denom_keys_array;
+
+ /**
+ * JSON array with signing keys. (Currently not really used
+ * after initialization.)
+ */
+ json_t *sign_keys_array;
+
+ /**
+ * Cached JSON text that the mint will send for a "/keys" request.
+ * Includes our @e master_pub public key, the signing and
+ * denomination keys as well as the @e reload_time.
+ */
+ char *keys_json;
+
+ /**
+ * Mapping from denomination keys to denomination key issue struct.
+ * Used to lookup the key by hash.
+ */
+ struct GNUNET_CONTAINER_MultiHashMap *denomkey_map;
+
+ /**
+ * When did we initiate the key reloading?
+ */
+ struct GNUNET_TIME_Absolute reload_time;
+
+ /**
+ * When is the next key invalid and we have to reload? (We also
+ * reload on SIGUSR1.)
+ */
+ struct GNUNET_TIME_Absolute next_reload;
+
+ /**
+ * Mint signing key that should be used currently.
+ */
+ struct TALER_MINT_SignKeyIssuePriv current_sign_key_issue;
+
+ /**
+ * Reference count. The struct is released when the RC hits zero.
+ */
+ unsigned int refcnt;
+};
/**
* Mint key state. Never use directly, instead access via
- * #TALER_MINT_key_state_acquire and #TALER_MINT_key_state_release.
+ * #TALER_MINT_key_state_acquire() and #TALER_MINT_key_state_release().
*/
static struct MintKeyState *internal_key_state;
@@ -50,79 +106,48 @@ static int reload_pipe[2];
* Convert the public part of a denomination key issue to a JSON
* object.
*
+ * @param pk public key of the denomination key
* @param dki the denomination key issue
* @return a JSON object describing the denomination key isue (public part)
*/
static json_t *
-denom_key_issue_to_json (const struct TALER_MINT_DenomKeyIssue *dki)
-{
- char *buf;
- size_t buf_len;
- json_t *dk_json = json_object ();
-
- json_object_set_new (dk_json,
- "master_sig",
- TALER_JSON_from_data (&dki->signature,
- sizeof (struct GNUNET_CRYPTO_EddsaSignature)));
- json_object_set_new (dk_json,
- "stamp_start",
- TALER_JSON_from_abs (GNUNET_TIME_absolute_ntoh (dki->start)));
- json_object_set_new (dk_json,
- "stamp_expire_withdraw",
- TALER_JSON_from_abs (GNUNET_TIME_absolute_ntoh (dki->expire_withdraw)));
- json_object_set_new (dk_json,
- "stamp_expire_deposit",
- TALER_JSON_from_abs (GNUNET_TIME_absolute_ntoh (dki->expire_spend)));
-
- buf_len = GNUNET_CRYPTO_rsa_public_key_encode (dki->denom_pub,
- &buf);
- json_object_set_new (dk_json,
- "denom_pub",
- TALER_JSON_from_data (buf,
- buf_len));
- GNUNET_free (buf);
- json_object_set_new (dk_json,
- "value",
- TALER_JSON_from_amount (TALER_amount_ntoh (dki->value)));
- json_object_set_new (dk_json,
- "fee_withdraw",
- TALER_JSON_from_amount (TALER_amount_ntoh (dki->fee_withdraw)));
- json_object_set_new (dk_json,
- "fee_deposit",
- TALER_JSON_from_amount (TALER_amount_ntoh (dki->fee_deposit)));
- json_object_set_new (dk_json,
- "fee_refresh",
- TALER_JSON_from_amount (TALER_amount_ntoh (dki->fee_refresh)));
- return dk_json;
-}
-
-
-/**
- * Convert the public part of a sign key issue to a JSON object.
- *
- * @param ski the sign key issue
- * @return a JSON object describing the sign key isue (public part)
- */
-static json_t *
-sign_key_issue_to_json (const struct TALER_MINT_SignKeyIssue *ski)
+denom_key_issue_to_json (const struct TALER_DenominationPublicKey *pk,
+ const struct TALER_MINT_DenomKeyIssue *dki)
{
- json_t *sk_json = json_object ();
-
- json_object_set_new (sk_json,
- "stamp_start",
- TALER_JSON_from_abs (GNUNET_TIME_absolute_ntoh (ski->start)));
- json_object_set_new (sk_json,
- "stamp_expire",
- TALER_JSON_from_abs (GNUNET_TIME_absolute_ntoh (ski->expire)));
- json_object_set_new (sk_json,
- "master_sig",
- TALER_JSON_from_data (&ski->signature,
- sizeof (struct GNUNET_CRYPTO_EddsaSignature)));
- json_object_set_new (sk_json,
- "key",
- TALER_JSON_from_data (&ski->signkey_pub,
- sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)));
- return sk_json;
+ struct TALER_Amount value;
+ struct TALER_Amount fee_withdraw;
+ struct TALER_Amount fee_deposit;
+ struct TALER_Amount fee_refresh;
+
+ TALER_amount_ntoh (&value,
+ &dki->value);
+ TALER_amount_ntoh (&fee_withdraw,
+ &dki->fee_withdraw);
+ TALER_amount_ntoh (&fee_deposit,
+ &dki->fee_deposit);
+ TALER_amount_ntoh (&fee_refresh,
+ &dki->fee_refresh);
+ return
+ json_pack ("{s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}",
+ "master_sig",
+ TALER_JSON_from_data (&dki->signature,
+ sizeof (struct GNUNET_CRYPTO_EddsaSignature)),
+ "stamp_start",
+ TALER_JSON_from_abs (GNUNET_TIME_absolute_ntoh (dki->start)),
+ "stamp_expire_withdraw",
+ TALER_JSON_from_abs (GNUNET_TIME_absolute_ntoh (dki->expire_withdraw)),
+ "stamp_expire_deposit",
+ TALER_JSON_from_abs (GNUNET_TIME_absolute_ntoh (dki->expire_spend)),
+ "denom_pub",
+ TALER_JSON_from_rsa_public_key (pk->rsa_public_key),
+ "value",
+ TALER_JSON_from_amount (&value),
+ "fee_withdraw",
+ TALER_JSON_from_amount (&fee_withdraw),
+ "fee_deposit",
+ TALER_JSON_from_amount (&fee_deposit),
+ "fee_refresh",
+ TALER_JSON_from_amount (&fee_refresh));
}
@@ -152,7 +177,7 @@ TALER_MINT_conf_duration_provide ()
/**
- * Iterator for denomination keys.
+ * Iterator for (re)loading/initializing denomination keys.
*
* @param cls closure
* @param dki the denomination key issue
@@ -167,47 +192,83 @@ reload_keys_denom_iter (void *cls,
const struct TALER_MINT_DenomKeyIssuePriv *dki)
{
struct MintKeyState *ctx = cls;
- struct GNUNET_TIME_Absolute stamp_provide;
+ struct GNUNET_TIME_Absolute now;
+ struct GNUNET_TIME_Absolute horizon;
struct GNUNET_HashCode denom_key_hash;
+ struct TALER_MINT_DenomKeyIssuePriv *d2;
int res;
- stamp_provide = GNUNET_TIME_absolute_add (ctx->reload_time,
- TALER_MINT_conf_duration_provide ());
-
- if (GNUNET_TIME_absolute_ntoh (dki->issue.expire_spend).abs_value_us < ctx->reload_time.abs_value_us)
+ horizon = GNUNET_TIME_relative_to_absolute (TALER_MINT_conf_duration_provide ());
+ if (GNUNET_TIME_absolute_ntoh (dki->issue.expire_spend).abs_value_us >
+ horizon.abs_value_us)
{
- // this key is expired
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Skipping future denomination key `%s'\n",
+ alias);
return GNUNET_OK;
}
- if (GNUNET_TIME_absolute_ntoh (dki->issue.start).abs_value_us > stamp_provide.abs_value_us)
+ now = GNUNET_TIME_absolute_get ();
+ if (GNUNET_TIME_absolute_ntoh (dki->issue.expire_spend).abs_value_us <
+ now.abs_value_us)
{
- // we are to early for this key
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Skipping expired denomination key `%s'\n",
+ alias);
return GNUNET_OK;
}
- GNUNET_CRYPTO_hash (&dki->issue.denom_pub,
- sizeof (struct GNUNET_CRYPTO_EddsaPublicKey),
- &denom_key_hash);
-
+ GNUNET_CRYPTO_rsa_public_key_hash (dki->denom_pub.rsa_public_key,
+ &denom_key_hash);
+ d2 = GNUNET_memdup (dki,
+ sizeof (struct TALER_MINT_DenomKeyIssuePriv));
res = GNUNET_CONTAINER_multihashmap_put (ctx->denomkey_map,
&denom_key_hash,
- GNUNET_memdup (dki, sizeof (struct TALER_MINT_DenomKeyIssuePriv)),
+ d2,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
if (GNUNET_OK != res)
+ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Duplicate denomination key\n");
-
+ "Duplicate denomination key `%s'\n",
+ alias);
+ GNUNET_free (d2);
+ return GNUNET_OK;
+ }
json_array_append_new (ctx->denom_keys_array,
- denom_key_issue_to_json (&dki->issue));
-
+ denom_key_issue_to_json (&dki->denom_pub,
+ &dki->issue));
return GNUNET_OK;
}
/**
+ * Convert the public part of a sign key issue to a JSON object.
+ *
+ * @param ski the sign key issue
+ * @return a JSON object describing the sign key isue (public part)
+ */
+static json_t *
+sign_key_issue_to_json (const struct TALER_MINT_SignKeyIssue *ski)
+{
+ return
+ json_pack ("{s:o, s:o, s:o, s:o}",
+ "stamp_start",
+ TALER_JSON_from_abs (GNUNET_TIME_absolute_ntoh (ski->start)),
+ "stamp_expire",
+ TALER_JSON_from_abs (GNUNET_TIME_absolute_ntoh (ski->expire)),
+ "master_sig",
+ TALER_JSON_from_data (&ski->signature,
+ sizeof (struct GNUNET_CRYPTO_EddsaSignature)),
+ "key",
+ TALER_JSON_from_data (&ski->signkey_pub,
+ sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)));
+}
+
+
+/**
* Iterator for sign keys.
*
* @param cls closure
+ * @param filename name of the file the key came from
* @param ski the sign key issue
* @return #GNUNET_OK to continue to iterate,
* #GNUNET_NO to stop iteration with no error,
@@ -215,36 +276,40 @@ reload_keys_denom_iter (void *cls,
*/
static int
reload_keys_sign_iter (void *cls,
+ const char *filename,
const struct TALER_MINT_SignKeyIssuePriv *ski)
{
struct MintKeyState *ctx = cls;
- struct GNUNET_TIME_Absolute stamp_provide;
-
- stamp_provide = GNUNET_TIME_absolute_add (ctx->reload_time,
- TALER_MINT_conf_duration_provide (cfg));
+ struct GNUNET_TIME_Absolute now;
+ struct GNUNET_TIME_Absolute horizon;
- if (GNUNET_TIME_absolute_ntoh (ski->issue.expire).abs_value_us < ctx->reload_time.abs_value_us)
+ horizon = GNUNET_TIME_relative_to_absolute (TALER_MINT_conf_duration_provide ());
+ if (GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us >
+ horizon.abs_value_us)
{
- // this key is expired
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Skipping future signing key `%s'\n",
+ filename);
return GNUNET_OK;
}
-
- if (GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us > stamp_provide.abs_value_us)
+ now = GNUNET_TIME_absolute_get ();
+ if (GNUNET_TIME_absolute_ntoh (ski->issue.expire).abs_value_us <
+ now.abs_value_us)
{
- // we are to early for this key
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Skipping expired signing key `%s'\n",
+ filename);
return GNUNET_OK;
}
- // the signkey is valid for now, check
- // if it's more recent than the current one!
- if (GNUNET_TIME_absolute_ntoh (ctx->current_sign_key_issue.issue.start).abs_value_us >
+ /* The signkey is valid at this time, check if it's more recent than
+ what we have so far! */
+ if (GNUNET_TIME_absolute_ntoh (ctx->current_sign_key_issue.issue.start).abs_value_us <
GNUNET_TIME_absolute_ntoh (ski->issue.start).abs_value_us)
+ {
+ /* We keep the most recent one around */
ctx->current_sign_key_issue = *ski;
-
-
- ctx->next_reload = GNUNET_TIME_absolute_min (ctx->next_reload,
- GNUNET_TIME_absolute_ntoh (ski->issue.expire));
-
+ }
json_array_append_new (ctx->sign_keys_array,
sign_key_issue_to_json (&ski->issue));
@@ -253,46 +318,24 @@ reload_keys_sign_iter (void *cls,
/**
- * Load the mint's key state from disk.
+ * Iterator for freeing denomination keys.
*
- * @return fresh key state (with reference count 1)
+ * @param cls closure with the `struct MintKeyState`
+ * @param key key for the denomination key
+ * @param alias coin alias
+ * @return #GNUNET_OK to continue to iterate,
+ * #GNUNET_NO to stop iteration with no error,
+ * #GNUNET_SYSERR to abort iteration with error!
*/
-static struct MintKeyState *
-reload_keys ()
+static int
+free_denom_key (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
{
- struct MintKeyState *key_state;
- json_t *keys;
-
- key_state = GNUNET_new (struct MintKeyState);
- key_state->refcnt = 1;
-
- key_state->next_reload = GNUNET_TIME_UNIT_FOREVER_ABS;
-
- key_state->denom_keys_array = json_array ();
- GNUNET_assert (NULL != key_state->denom_keys_array);
-
- key_state->sign_keys_array = json_array ();
- GNUNET_assert (NULL != key_state->sign_keys_array);
-
- key_state->denomkey_map = GNUNET_CONTAINER_multihashmap_create (32,
- GNUNET_NO);
- GNUNET_assert (NULL != key_state->denomkey_map);
+ struct TALER_MINT_DenomKeyIssuePriv *dki = value;
- key_state->reload_time = GNUNET_TIME_absolute_get ();
-
- TALER_MINT_denomkeys_iterate (mintdir, &reload_keys_denom_iter, key_state);
- TALER_MINT_signkeys_iterate (mintdir, &reload_keys_sign_iter, key_state);
-
- keys = json_pack ("{s:o, s:o, s:o, s:o}",
- "master_pub", TALER_JSON_from_data (&master_pub,
- sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)),
- "signkeys", key_state->sign_keys_array,
- "denoms", key_state->denom_keys_array,
- "list_issue_date", TALER_JSON_from_abs (key_state->reload_time));
-
- key_state->keys_json = json_dumps (keys, JSON_INDENT(2));
-
- return key_state;
+ GNUNET_free (dki);
+ return GNUNET_OK;
}
@@ -309,6 +352,13 @@ TALER_MINT_key_state_release (struct MintKeyState *key_state)
key_state->refcnt--;
if (0 == key_state->refcnt)
{
+ json_decref (key_state->denom_keys_array);
+ json_decref (key_state->sign_keys_array);
+ GNUNET_CONTAINER_multihashmap_iterate (key_state->denomkey_map,
+ &free_denom_key,
+ key_state);
+ GNUNET_CONTAINER_multihashmap_destroy (key_state->denomkey_map);
+ GNUNET_free (key_state->keys_json);
GNUNET_free (key_state);
}
GNUNET_assert (0 == pthread_mutex_unlock (&internal_key_state_mutex));
@@ -317,8 +367,8 @@ TALER_MINT_key_state_release (struct MintKeyState *key_state)
/**
* Acquire the key state of the mint. Updates keys if necessary.
- * For every call to #TALER_MINT_key_state_acquire, a matching call
- * to #TALER_MINT_key_state_release must be made.
+ * For every call to #TALER_MINT_key_state_acquire(), a matching call
+ * to #TALER_MINT_key_state_release() must be made.
*
* @return the key state
*/
@@ -327,19 +377,64 @@ TALER_MINT_key_state_acquire (void)
{
struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
struct MintKeyState *key_state;
+ json_t *keys;
+ char *inner;
+ struct TALER_MINT_KeySetSignature ks;
+ struct TALER_MintSignature sig;
GNUNET_assert (0 == pthread_mutex_lock (&internal_key_state_mutex));
- if (NULL == internal_key_state)
+ if (internal_key_state->next_reload.abs_value_us <= now.abs_value_us)
{
- internal_key_state = reload_keys ();
+ TALER_MINT_key_state_release (internal_key_state);
+ internal_key_state = NULL;
}
- else if (internal_key_state->next_reload.abs_value_us <= now.abs_value_us)
+ if (NULL == internal_key_state)
{
- GNUNET_assert (0 < internal_key_state->refcnt);
- internal_key_state->refcnt--;
- if (0 == internal_key_state->refcnt)
- GNUNET_free (internal_key_state);
- internal_key_state = reload_keys ();
+ key_state = GNUNET_new (struct MintKeyState);
+ key_state->denom_keys_array = json_array ();
+ GNUNET_assert (NULL != key_state->denom_keys_array);
+ key_state->sign_keys_array = json_array ();
+ GNUNET_assert (NULL != key_state->sign_keys_array);
+ key_state->denomkey_map = GNUNET_CONTAINER_multihashmap_create (32,
+ GNUNET_NO);
+ key_state->reload_time = GNUNET_TIME_absolute_get ();
+ TALER_MINT_denomkeys_iterate (mintdir,
+ &reload_keys_denom_iter,
+ key_state);
+ TALER_MINT_signkeys_iterate (mintdir,
+ &reload_keys_sign_iter,
+ key_state);
+ key_state->next_reload = GNUNET_TIME_absolute_ntoh (key_state->current_sign_key_issue.issue.expire);
+ if (0 == key_state->next_reload.abs_value_us)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "No valid signing key found!\n");
+
+ keys = json_pack ("{s:o, s:o, s:o, s:o}",
+ "master_pub",
+ TALER_JSON_from_data (&master_pub,
+ sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)),
+ "signkeys", key_state->sign_keys_array,
+ "denoms", key_state->denom_keys_array,
+ "list_issue_date", TALER_JSON_from_abs (key_state->reload_time));
+ inner = json_dumps (keys,
+ JSON_INDENT(2));
+ ks.purpose.size = htonl (sizeof (ks));
+ ks.purpose.purpose = htonl (TALER_SIGNATURE_KEYS_SET);
+ ks.list_issue_date = GNUNET_TIME_absolute_hton (key_state->reload_time);
+ GNUNET_CRYPTO_hash (inner,
+ strlen (inner),
+ &ks.hc);
+ GNUNET_free (inner);
+ TALER_MINT_keys_sign (&ks.purpose,
+ &sig);
+ keys = json_pack ("{s:o, s:o}",
+ "keys", keys,
+ "eddsa-signature", TALER_JSON_from_eddsa_sig (&ks.purpose,
+ &sig.eddsa_signature));
+ key_state->keys_json = json_dumps (keys,
+ JSON_INDENT (2));
+ json_decref (keys);
+ internal_key_state = key_state;
}
key_state = internal_key_state;
key_state->refcnt++;
@@ -359,20 +454,14 @@ TALER_MINT_key_state_acquire (void)
*/
struct TALER_MINT_DenomKeyIssuePriv *
TALER_MINT_get_denom_key (const struct MintKeyState *key_state,
- const struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub)
+ const struct TALER_DenominationPublicKey *denom_pub)
{
- struct GNUNET_HashCode hash;
- char *buf;
- size_t buf_len;
-
- buf_len = GNUNET_CRYPTO_rsa_public_key_encode (denom_pub,
- &buf);
- GNUNET_CRYPTO_hash (buf,
- buf_len,
- &hash);
- GNUNET_free (buf);
+ struct GNUNET_HashCode hc;
+
+ GNUNET_CRYPTO_rsa_public_key_hash (denom_pub->rsa_public_key,
+ &hc);
return GNUNET_CONTAINER_multihashmap_get (key_state->denomkey_map,
- &hash);
+ &hc);
}
@@ -390,9 +479,11 @@ handle_signal (int signal_number)
if (SIGUSR1 == signal_number)
{
- errno = 0;
- res = write (reload_pipe[1], &c, 1);
- if ((res < 0) && (EINTR != errno))
+ res = write (reload_pipe[1],
+ &c,
+ 1);
+ if ( (res < 0) &&
+ (EINTR != errno) )
{
GNUNET_break (0);
return;
@@ -409,11 +500,16 @@ handle_signal (int signal_number)
/**
* Read signals from a pipe in a loop, and reload keys from disk if
* SIGUSR1 is read from the pipe.
+ *
+ * @return #GNUNET_SYSERR on errors, otherwise does not return
+ * (FIXME: #3474)
*/
int
TALER_MINT_key_reload_loop (void)
{
struct sigaction act;
+ struct sigaction rec;
+ int ret;
if (0 != pipe (reload_pipe))
{
@@ -421,16 +517,21 @@ TALER_MINT_key_reload_loop (void)
"Failed to create pipe.\n");
return GNUNET_SYSERR;
}
- memset (&act, 0, sizeof (struct sigaction));
+ memset (&act,
+ 0,
+ sizeof (struct sigaction));
act.sa_handler = &handle_signal;
-
- if (0 != sigaction (SIGUSR1, &act, NULL))
+ if (0 != sigaction (SIGUSR1,
+ &act,
+ &rec))
{
fprintf (stderr,
"Failed to set signal handler.\n");
return GNUNET_SYSERR;
}
+ ret = GNUNET_OK;
+ /* FIXME: allow for 'clean' termination or restart (#3474) */
while (1)
{
char c;
@@ -438,52 +539,105 @@ TALER_MINT_key_reload_loop (void)
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"(re-)loading keys\n");
- GNUNET_assert (0 == pthread_mutex_lock (&internal_key_state_mutex));
if (NULL != internal_key_state)
{
- GNUNET_assert (0 != internal_key_state->refcnt);
- internal_key_state->refcnt -= 1;
- if (0 == internal_key_state->refcnt)
- GNUNET_free (internal_key_state);
+ TALER_MINT_key_state_release (internal_key_state);
+ internal_key_state = NULL;
}
- internal_key_state = reload_keys ();
- GNUNET_assert (0 == pthread_mutex_unlock (&internal_key_state_mutex));
+ /* This will re-initialize 'internal_key_state' with
+ an initial refcnt of 1 */
+ (void) TALER_MINT_key_state_acquire ();
+
read_again:
errno = 0;
- res = read (reload_pipe[0], &c, 1);
+ res = read (reload_pipe[0],
+ &c,
+ 1);
if ((res < 0) && (EINTR != errno))
{
GNUNET_break (0);
- return GNUNET_SYSERR;
+ ret = GNUNET_SYSERR;
+ break;
}
if (EINTR == errno)
goto read_again;
}
- return GNUNET_OK;
+
+ if (0 != sigaction (SIGUSR1,
+ &rec,
+ &act))
+ {
+ fprintf (stderr,
+ "Failed to restore signal handler.\n");
+ return GNUNET_SYSERR;
+ }
+ return ret;
}
/**
- * Sign the message in @a purpose with the mint's signing
- * key.
+ * Sign the message in @a purpose with the mint's signing key.
*
* @param purpose the message to sign
* @param[OUT] sig signature over purpose using current signing key
*/
void
TALER_MINT_keys_sign (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
- struct GNUNET_CRYPTO_EddsaSignature *sig)
+ struct TALER_MintSignature *sig)
{
struct MintKeyState *key_state;
key_state = TALER_MINT_key_state_acquire ();
GNUNET_assert (GNUNET_OK ==
- GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv,
+ GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv.eddsa_priv,
purpose,
- sig));
+ &sig->eddsa_signature));
TALER_MINT_key_state_release (key_state);
}
+/**
+ * Function to call to handle the request by sending
+ * back static data from the @a rh.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[IN|OUT] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TALER_MINT_handler_keys (struct RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size)
+{
+ struct MintKeyState *key_state;
+ struct MHD_Response *response;
+ int ret;
+
+ key_state = TALER_MINT_key_state_acquire ();
+ response = MHD_create_response_from_buffer (strlen (key_state->keys_json),
+ key_state->keys_json,
+ MHD_RESPMEM_MUST_COPY);
+ TALER_MINT_key_state_release (key_state);
+ if (NULL == response)
+ {
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+ (void) MHD_add_response_header (response,
+ "Content-Type",
+ rh->mime_type);
+ ret = MHD_queue_response (connection,
+ rh->response_code,
+ response);
+ MHD_destroy_response (response);
+ return ret;
+}
+
+
/* end of taler-mint-httpd_keystate.c */
diff --git a/src/mint/taler-mint-httpd_keystate.h b/src/mint/taler-mint-httpd_keystate.h
index 4b700d1c1..faccc8f00 100644
--- a/src/mint/taler-mint-httpd_keystate.h
+++ b/src/mint/taler-mint-httpd_keystate.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014 GNUnet e.V.
+ Copyright (C) 2014, 2015 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
@@ -14,7 +14,7 @@
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file taler-mint-httpd_keystate.h
+ * @file mint/taler-mint-httpd_keystate.h
* @brief management of our private signing keys (denomination keys)
* @author Florian Dold
* @author Benedikt Mueller
@@ -23,10 +23,8 @@
#ifndef TALER_MINT_HTTPD_KEYSTATE_H
#define TALER_MINT_HTTPD_KEYSTATE_H
-
#include <gnunet/gnunet_util_lib.h>
#include <microhttpd.h>
-#include <jansson.h>
#include "taler-mint-httpd.h"
#include "key_io.h"
@@ -35,49 +33,7 @@
* Snapshot of the (coin and signing)
* keys (including private keys) of the mint.
*/
-struct MintKeyState
-{
- /**
- * When did we initiate the key reloading?
- */
- struct GNUNET_TIME_Absolute reload_time;
-
- /**
- * JSON array with denomination keys.
- */
- json_t *denom_keys_array;
-
- /**
- * JSON array with signing keys.
- */
- json_t *sign_keys_array;
-
- /**
- * Mapping from denomination keys to denomination key issue struct.
- */
- struct GNUNET_CONTAINER_MultiHashMap *denomkey_map;
-
- /**
- * When is the next key invalid and we have to reload?
- */
- struct GNUNET_TIME_Absolute next_reload;
-
- /**
- * Mint signing key that should be used currently.
- */
- struct TALER_MINT_SignKeyIssuePriv current_sign_key_issue;
-
- /**
- * Cached JSON text that the mint will send for
- * a /keys request.
- */
- char *keys_json;
-
- /**
- * Reference count.
- */
- unsigned int refcnt;
-};
+struct MintKeyState;
/**
@@ -101,7 +57,8 @@ TALER_MINT_key_state_release (struct MintKeyState *key_state);
/**
- * Look up the issue for a denom public key.
+ * Look up the issue for a denom public key. Note that the result
+ * is only valid while the @a key_state is not released!
*
* @param key state to look in
* @param denom_pub denomination public key
@@ -110,14 +67,15 @@ TALER_MINT_key_state_release (struct MintKeyState *key_state);
*/
struct TALER_MINT_DenomKeyIssuePriv *
TALER_MINT_get_denom_key (const struct MintKeyState *key_state,
- const struct GNUNET_CRYPTO_rsa_PublicKey *denom_pub);
+ const struct TALER_DenominationPublicKey *denom_pub);
/**
* Read signals from a pipe in a loop, and reload keys from disk if
* SIGUSR1 is read from the pipe.
*
- * @return #GNUNET_OK if we terminated normally, #GNUNET_SYSERR on error
+ * @return #GNUNET_OK if we terminated normally,
+ * #GNUNET_SYSERR on error
*/
int
TALER_MINT_key_reload_loop (void);
@@ -132,8 +90,25 @@ TALER_MINT_key_reload_loop (void);
*/
void
TALER_MINT_keys_sign (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
- struct GNUNET_CRYPTO_EddsaSignature *sig);
+ struct TALER_MintSignature *sig);
+
+/**
+ * Handle a "/keys" request
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[IN|OUT] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TALER_MINT_handler_keys (struct RequestHandler *rh,
+ struct MHD_Connection *connection,
+ void **connection_cls,
+ const char *upload_data,
+ size_t *upload_data_size);
#endif
diff --git a/src/mint/taler-mint-httpd_parsing.c b/src/mint/taler-mint-httpd_parsing.c
index 6c5f72b32..dedf4af9a 100644
--- a/src/mint/taler-mint-httpd_parsing.c
+++ b/src/mint/taler-mint-httpd_parsing.c
@@ -680,6 +680,16 @@ GNUNET_MINT_parse_navigate_json (struct MHD_Connection *connection,
break;
}
+ case JNAV_RET_AMOUNT:
+ {
+ struct TALER_Amount *where = va_arg (argp, void *);
+
+ ret = TALER_MINT_parse_amount_json (connection,
+ (json_t *) root,
+ where);
+ break;
+ }
+
default:
GNUNET_break (0);
ret = (MHD_YES ==
@@ -721,6 +731,8 @@ TALER_MINT_parse_json_data (struct MHD_Connection *connection,
ret = GNUNET_YES;
for (i=0; NULL != spec[i].field_name; i++)
{
+ if (GNUNET_YES != ret)
+ break;
switch (spec[i].command)
{
case JNAV_FIELD:
@@ -730,8 +742,6 @@ TALER_MINT_parse_json_data (struct MHD_Connection *connection,
GNUNET_break (0);
return GNUNET_SYSERR;
case JNAV_RET_DATA:
- if (GNUNET_YES != ret)
- break;
ret = GNUNET_MINT_parse_navigate_json (connection,
root,
JNAV_FIELD,
@@ -741,8 +751,6 @@ TALER_MINT_parse_json_data (struct MHD_Connection *connection,
spec[i].destination_size_in);
break;
case JNAV_RET_DATA_VAR:
- if (GNUNET_YES != ret)
- break;
ptr = NULL;
ret = GNUNET_MINT_parse_navigate_json (connection,
root,
@@ -754,8 +762,6 @@ TALER_MINT_parse_json_data (struct MHD_Connection *connection,
spec[i].destination = ptr;
break;
case JNAV_RET_TYPED_JSON:
- if (GNUNET_YES != ret)
- break;
ptr = NULL;
ret = GNUNET_MINT_parse_navigate_json (connection,
root,
@@ -767,8 +773,6 @@ TALER_MINT_parse_json_data (struct MHD_Connection *connection,
*((void**)spec[i].destination) = ptr;
break;
case JNAV_RET_RSA_PUBLIC_KEY:
- if (GNUNET_YES != ret)
- break;
ptr = NULL;
ret = GNUNET_MINT_parse_navigate_json (connection,
root,
@@ -779,8 +783,6 @@ TALER_MINT_parse_json_data (struct MHD_Connection *connection,
spec[i].destination = ptr;
break;
case JNAV_RET_RSA_SIGNATURE:
- if (GNUNET_YES != ret)
- break;
ptr = NULL;
ret = GNUNET_MINT_parse_navigate_json (connection,
root,
@@ -790,6 +792,16 @@ TALER_MINT_parse_json_data (struct MHD_Connection *connection,
&ptr);
spec[i].destination = ptr;
break;
+ case JNAV_RET_AMOUNT:
+ GNUNET_assert (sizeof (struct TALER_Amount) ==
+ spec[i].destination_size_in);
+ ret = GNUNET_MINT_parse_navigate_json (connection,
+ root,
+ JNAV_FIELD,
+ spec[i].field_name,
+ JNAV_RET_AMOUNT,
+ &spec[i].destination);
+ break;
}
}
if (GNUNET_YES != ret)
@@ -854,6 +866,11 @@ TALER_MINT_release_parsed_data (struct GNUNET_MINT_ParseFieldSpec *spec)
*(void**) spec[i].destination = NULL;
}
break;
+ case JNAV_RET_AMOUNT:
+ memset (spec[i].destination,
+ 0,
+ sizeof (struct TALER_Amount));
+ break;
}
}
}
@@ -878,8 +895,10 @@ TALER_MINT_parse_amount_json (struct MHD_Connection *connection,
json_int_t value;
json_int_t fraction;
const char *currency;
- struct TALER_Amount a;
+ memset (amount,
+ 0,
+ sizeof (struct TALER_Amount));
if (-1 == json_unpack (f,
"{s:I, s:I, s:s}",
"value", &value,
@@ -897,7 +916,7 @@ TALER_MINT_parse_amount_json (struct MHD_Connection *connection,
}
if ( (value < 0) ||
(fraction < 0) ||
- (value > UINT32_MAX) ||
+ (value > UINT64_MAX) ||
(fraction > UINT32_MAX) )
{
LOG_WARNING ("Amount specified not in allowed range\n");
@@ -922,11 +941,11 @@ TALER_MINT_parse_amount_json (struct MHD_Connection *connection,
return GNUNET_SYSERR;
return GNUNET_NO;
}
- a.value = (uint32_t) value;
- a.fraction = (uint32_t) fraction;
+ amount->value = (uint64_t) value;
+ amount->fraction = (uint32_t) fraction;
GNUNET_assert (strlen (MINT_CURRENCY) < TALER_CURRENCY_LEN);
- strcpy (a.currency, MINT_CURRENCY);
- *amount = TALER_amount_normalize (a);
+ strcpy (amount->currency, MINT_CURRENCY);
+ TALER_amount_normalize (amount);
return GNUNET_OK;
}
diff --git a/src/mint/taler-mint-httpd_parsing.h b/src/mint/taler-mint-httpd_parsing.h
index 94e2927d8..7a322d4d7 100644
--- a/src/mint/taler-mint-httpd_parsing.h
+++ b/src/mint/taler-mint-httpd_parsing.h
@@ -120,7 +120,13 @@ enum TALER_MINT_JsonNavigationCommand
* Return a `struct GNUNET_CRYPTO_rsa_Signature` which was
* encoded as variable-size base32crockford encoded data.
*/
- JNAV_RET_RSA_SIGNATURE
+ JNAV_RET_RSA_SIGNATURE,
+
+ /**
+ * Return a `struct TALER_Amount` which was
+ * encoded within its own json object.
+ */
+ JNAV_RET_AMOUNT
};
@@ -271,6 +277,14 @@ TALER_MINT_release_parsed_data (struct GNUNET_MINT_ParseFieldSpec *spec);
#define TALER_MINT_PARSE_RSA_SIGNATURE(field,ptrsig) { field, ptrsig, 0, 0, JNAV_RET_RSA_SIGNATURE, 0 }
/**
+ * Generate line in parser specification for an amount.
+ *
+ * @param field name of the field
+ * @param amount a `struct TALER_Amount *` to initialize
+ */
+#define TALER_MINT_PARSE_AMOUNT(field,amount) { field, amount, sizeof(*amount), 0, JNAV_RET_AMOUNT, 0 }
+
+/**
* Generate line in parser specification indicating the end of the spec.
*/
#define TALER_MINT_PARSE_END { NULL, NULL, 0, 0, JNAV_FIELD, 0 }
diff --git a/src/mint/taler-mint-httpd_refresh.c b/src/mint/taler-mint-httpd_refresh.c
index a5d609ed8..5fc8fd5b0 100644
--- a/src/mint/taler-mint-httpd_refresh.c
+++ b/src/mint/taler-mint-httpd_refresh.c
@@ -24,11 +24,10 @@
#include <gnunet/gnunet_util_lib.h>
#include <jansson.h>
#include <microhttpd.h>
-#include "mint_db.h"
+#include "taler_mintdb_plugin.h"
#include "taler_signatures.h"
#include "taler_util.h"
#include "taler-mint-httpd_parsing.h"
-#include "taler-mint-httpd_keys.h"
#include "taler-mint-httpd_mhd.h"
#include "taler-mint-httpd_refresh.h"
#include "taler-mint-httpd_responses.h"
@@ -41,15 +40,13 @@
* and then hand things of to execute the melt operation.
*
* @param connection the MHD connection to handle
- * @param refresh_session_pub public key of the melt operation
* @param num_new_denoms number of coins to be created, size of y-dimension of @commit_link array
* @param denom_pubs array of @a num_new_denoms keys
* @param coin_count number of coins to be melted, size of y-dimension of @commit_coin array
* @param coin_public_infos array with @a coin_count entries about the coins
* @param coin_melt_details array with @a coin_count entries with melting details
- * @param commit_hash hash over the data that the client commits to
+ * @param session_hash hash over the data that the client commits to
* @param commit_client_sig signature of the client over this commitment
- * @param kappa size of x-dimension of @commit_coin and @commit_link arrays
* @param commit_coin 2d array of coin commitments (what the mint is to sign
* once the "/refres/reveal" of cut and choose is done)
* @param commit_link 2d array of coin link commitments (what the mint is
@@ -59,101 +56,88 @@
*/
static int
handle_refresh_melt_binary (struct MHD_Connection *connection,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
unsigned int num_new_denoms,
- struct GNUNET_CRYPTO_rsa_PublicKey *const*denom_pubs,
+ const struct TALER_DenominationPublicKey *denom_pubs,
unsigned int coin_count,
struct TALER_CoinPublicInfo *coin_public_infos,
const struct MeltDetails *coin_melt_details,
- const struct GNUNET_HashCode *commit_hash,
- const struct GNUNET_CRYPTO_EddsaSignature *commit_client_sig,
- unsigned int kappa,
+ const struct GNUNET_HashCode *session_hash,
struct RefreshCommitCoin *const* commit_coin,
struct RefreshCommitLink *const* commit_link)
{
unsigned int i;
- struct GNUNET_HashContext *hash_context;
- struct GNUNET_HashCode melt_hash;
- struct RefreshMeltSessionSignature body;
- char *buf;
- size_t buf_size;
struct MintKeyState *key_state;
struct TALER_MINT_DenomKeyIssue *dki;
struct TALER_Amount cost;
struct TALER_Amount total_cost;
struct TALER_Amount melt;
+ struct TALER_Amount value;
+ struct TALER_Amount fee_withdraw;
+ struct TALER_Amount fee_melt;
struct TALER_Amount total_melt;
- /* check that signature from the session public key is ok */
- hash_context = GNUNET_CRYPTO_hash_context_start ();
- /* FIXME: also hash session public key here!? */
- for (i = 0; i < num_new_denoms; i++)
- {
- buf_size = GNUNET_CRYPTO_rsa_public_key_encode (denom_pubs[i],
- &buf);
- GNUNET_CRYPTO_hash_context_read (hash_context,
- buf,
- buf_size);
- GNUNET_free (buf);
- }
- for (i = 0; i < coin_count; i++)
- GNUNET_CRYPTO_hash_context_read (hash_context,
- &coin_public_infos[i].coin_pub,
- sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
- GNUNET_CRYPTO_hash_context_finish (hash_context,
- &melt_hash);
- // FIXME: what about the `commit_hash`?
-
- body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_SESSION);
- body.purpose.size = htonl (sizeof (struct RefreshMeltSessionSignature));
- body.melt_hash = melt_hash;
- body.amount = TALER_amount_hton (coin_melt_details->melt_amount);
-
- if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_REFRESH_MELT_SESSION,
- &body.purpose,
- commit_client_sig,
- refresh_session_pub))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "signature invalid (did not verify)\n");
- return TALER_MINT_reply_json_pack (connection,
- MHD_HTTP_UNAUTHORIZED,
- "{s:s}",
- "error",
- "invalid signature (verification)");
- }
-
- // FIXME: badness, use proper way to set to zero...
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (MINT_CURRENCY,
+ &total_cost));
key_state = TALER_MINT_key_state_acquire ();
- memset (&total_cost, 0, sizeof (struct TALER_Amount));
for (i=0;i<num_new_denoms;i++)
{
dki = &TALER_MINT_get_denom_key (key_state,
- denom_pubs[i])->issue;
- cost = TALER_amount_add (TALER_amount_ntoh (dki->value),
- TALER_amount_ntoh (dki->fee_withdraw));
- // FIXME: #3637
- total_cost = TALER_amount_add (cost,
- total_cost);
+ &denom_pubs[i])->issue;
+ TALER_amount_ntoh (&value,
+ &dki->value);
+ TALER_amount_ntoh (&fee_withdraw,
+ &dki->fee_withdraw);
+ if ( (GNUNET_OK !=
+ TALER_amount_add (&cost,
+ &value,
+ &fee_withdraw)) ||
+ (GNUNET_OK !=
+ TALER_amount_add (&total_cost,
+ &cost,
+ &total_cost)) )
+ {
+ TALER_MINT_key_state_release (key_state);
+ return TALER_MINT_reply_internal_error (connection,
+ "cost calculation failure");
+ }
}
- // FIXME: badness, use proper way to set to zero...
- memset (&total_melt, 0, sizeof (struct TALER_Amount));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (MINT_CURRENCY,
+ &total_melt));
for (i=0;i<coin_count;i++)
{
- memset (&melt, 0, sizeof (struct TALER_Amount));
- // FIXME: reduce coin value by melting fee!
- // melt = coin_values[i]; // FIXME: #3636!
-
- // FIXME: #3637
- total_melt = TALER_amount_add (melt,
- total_melt);
+ /* calculate contribution of the i-th melt by subtracting
+ the fee; add the rest to the total_melt value */
+ dki = &TALER_MINT_get_denom_key (key_state,
+ &coin_public_infos[i].denom_pub)->issue;
+ TALER_amount_ntoh (&fee_melt,
+ &dki->fee_refresh);
+ if (GNUNET_OK !=
+ TALER_amount_subtract (&melt,
+ &coin_melt_details->melt_amount_with_fee,
+ &fee_melt))
+ {
+ TALER_MINT_key_state_release (key_state);
+ return TALER_MINT_reply_external_error (connection,
+ "Melt contribution below melting fee");
+ }
+ if (GNUNET_OK !=
+ TALER_amount_add (&total_melt,
+ &melt,
+ &total_melt))
+ {
+ TALER_MINT_key_state_release (key_state);
+ return TALER_MINT_reply_internal_error (connection,
+ "balance calculation failure");
+ }
}
TALER_MINT_key_state_release (key_state);
if (0 !=
- TALER_amount_cmp (total_cost,
- total_melt) )
+ TALER_amount_cmp (&total_cost,
+ &total_melt))
{
/* We require total value of coins being melted and
total value of coins being generated to match! */
@@ -163,15 +147,12 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,
"error", "value mismatch");
}
return TALER_MINT_db_execute_refresh_melt (connection,
- &melt_hash,
- refresh_session_pub,
- commit_client_sig,
+ session_hash,
num_new_denoms,
denom_pubs,
coin_count,
coin_public_infos,
coin_melt_details,
- kappa,
commit_coin,
commit_link);
}
@@ -195,28 +176,24 @@ get_coin_public_info (struct MHD_Connection *connection,
struct MeltDetails *r_melt_detail)
{
int ret;
- struct GNUNET_CRYPTO_EcdsaSignature melt_sig;
- struct GNUNET_CRYPTO_rsa_Signature *sig;
- struct GNUNET_CRYPTO_rsa_PublicKey *pk;
+ struct TALER_CoinSpendSignature melt_sig;
+ struct TALER_DenominationSignature sig;
+ struct TALER_DenominationPublicKey pk;
struct TALER_Amount amount;
struct GNUNET_MINT_ParseFieldSpec spec[] = {
TALER_MINT_PARSE_FIXED ("coin_pub", &r_public_info->coin_pub),
- TALER_MINT_PARSE_RSA_SIGNATURE ("denom_sig", &sig),
- TALER_MINT_PARSE_RSA_PUBLIC_KEY ("denom_pub", &pk),
+ TALER_MINT_PARSE_RSA_SIGNATURE ("denom_sig", &sig.rsa_signature),
+ TALER_MINT_PARSE_RSA_PUBLIC_KEY ("denom_pub", &pk.rsa_public_key),
TALER_MINT_PARSE_FIXED ("confirm_sig", &melt_sig),
- /* FIXME: #3636! */
+ TALER_MINT_PARSE_AMOUNT ("value_with_fee", &amount),
TALER_MINT_PARSE_END
};
- memset (&amount, 0, sizeof (amount)); // FIXME: #3636!
ret = TALER_MINT_parse_json_data (connection,
coin_info,
spec);
if (GNUNET_OK != ret)
return ret;
- /* FIXME: include amount of coin value to be melted here (#3636!) and
- in what we return!? */
-
/* check mint signature on the coin */
r_public_info->denom_sig = sig;
r_public_info->denom_pub = pk;
@@ -224,8 +201,8 @@ get_coin_public_info (struct MHD_Connection *connection,
TALER_test_coin_valid (r_public_info))
{
TALER_MINT_release_parsed_data (spec);
- r_public_info->denom_sig = NULL;
- r_public_info->denom_pub = NULL;
+ r_public_info->denom_sig.rsa_signature = NULL;
+ r_public_info->denom_pub.rsa_public_key = NULL;
return (MHD_YES ==
TALER_MINT_reply_json_pack (connection,
MHD_HTTP_NOT_FOUND,
@@ -234,7 +211,7 @@ get_coin_public_info (struct MHD_Connection *connection,
? GNUNET_NO : GNUNET_SYSERR;
}
r_melt_detail->melt_sig = melt_sig;
- r_melt_detail->melt_amount = amount;
+ r_melt_detail->melt_amount_with_fee = amount;
TALER_MINT_release_parsed_data (spec);
return GNUNET_OK;
}
@@ -248,7 +225,7 @@ get_coin_public_info (struct MHD_Connection *connection,
* be done before the transaction starts.
*
* @param connection the connection to send error responses to
- * @param melt_hash hash over refresh session the coin is melted into
+ * @param session_hash hash over refresh session the coin is melted into
* @param r_public_info the coin's public information
* @param r_melt_detail details about the coin's melting permission (if valid)
* @return #GNUNET_YES if coin public info in JSON was valid
@@ -257,26 +234,26 @@ get_coin_public_info (struct MHD_Connection *connection,
*/
static int
verify_coin_public_info (struct MHD_Connection *connection,
- const struct GNUNET_HashCode *melt_hash,
+ const struct GNUNET_HashCode *session_hash,
const struct TALER_CoinPublicInfo *r_public_info,
const struct MeltDetails *r_melt_detail)
{
struct RefreshMeltCoinSignature body;
struct MintKeyState *key_state;
struct TALER_MINT_DenomKeyIssuePriv *dki;
+ struct TALER_Amount fee_refresh;
- /* FIXME: include amount of coin value to be melted here (#3636!) and
- in what we return!? */
body.purpose.size = htonl (sizeof (struct RefreshMeltCoinSignature));
body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_COIN);
- body.melt_hash = *melt_hash;
- body.amount = TALER_amount_hton (r_melt_detail->melt_amount);
+ body.session_hash = *session_hash;
+ TALER_amount_hton (&body.amount_with_fee,
+ &r_melt_detail->melt_amount_with_fee);
body.coin_pub = r_public_info->coin_pub;
if (GNUNET_OK !=
GNUNET_CRYPTO_ecdsa_verify (TALER_SIGNATURE_REFRESH_MELT_COIN,
&body.purpose,
- &r_melt_detail->melt_sig,
- &r_public_info->coin_pub))
+ &r_melt_detail->melt_sig.ecdsa_signature,
+ &r_public_info->coin_pub.ecdsa_pub))
{
if (MHD_YES !=
TALER_MINT_reply_json_pack (connection,
@@ -288,9 +265,7 @@ verify_coin_public_info (struct MHD_Connection *connection,
}
key_state = TALER_MINT_key_state_acquire ();
dki = TALER_MINT_get_denom_key (key_state,
- r_public_info->denom_pub);
- /* FIXME: need to check if denomination key is still
- valid for issuing! (#3634) */
+ &r_public_info->denom_pub);
if (NULL == dki)
{
TALER_MINT_key_state_release (key_state);
@@ -298,6 +273,20 @@ verify_coin_public_info (struct MHD_Connection *connection,
return TALER_MINT_reply_arg_invalid (connection,
"denom_pub");
}
+ /* FIXME: need to check if denomination key is still
+ valid for issuing! (#3634) */
+ TALER_amount_ntoh (&fee_refresh,
+ &dki->issue.fee_refresh);
+ if (TALER_amount_cmp (&fee_refresh,
+ &r_melt_detail->melt_amount_with_fee) < 0)
+ {
+ TALER_MINT_key_state_release (key_state);
+ return (MHD_YES ==
+ TALER_MINT_reply_external_error (connection,
+ "melt amount smaller than melting fee"))
+ ? GNUNET_NO : GNUNET_SYSERR;
+ }
+
TALER_MINT_key_state_release (key_state);
return GNUNET_OK;
}
@@ -363,28 +352,24 @@ free_commit_links (struct RefreshCommitLink **commit_link,
* #handle_refresh_melt_binary().
*
* @param connection the MHD connection to handle
- * @param refresh_session_pub public key of the melt operation
* @param new_denoms array of denomination keys
* @param melt_coins array of coins to melt
* @param melt_sig_json signature affirming the melt operation
* @param commit_signature signature over the commit
- * @param kappa security parameter for cut and choose
* @param num_oldcoins number of coins that are being melted
- * @param transfer_pubs @a kappa-dimensional array of @a num_oldcoins transfer keys
- * @param secret_encs @a kappa-dimensional array of @a num_oldcoins secrets
+ * @param transfer_pubs #KAPPA-dimensional array of @a num_oldcoins transfer keys
+ * @param secret_encs #KAPPA-dimensional array of @a num_oldcoins secrets
* @param num_newcoins number of coins that the refresh will generate
- * @param coin_envs @a kappa-dimensional array of @a num_newcoins envelopes to sign
- * @param link_encs @a kappa-dimensional array of @a num_newcoins encrypted links
+ * @param coin_envs #KAPPA-dimensional array of @a num_newcoins envelopes to sign
+ * @param link_encs #KAPPA-dimensional array of @a num_newcoins encrypted links
* @return MHD result code
*/
static int
handle_refresh_melt_json (struct MHD_Connection *connection,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
const json_t *new_denoms,
const json_t *melt_coins,
const json_t *melt_sig_json,
const json_t *commit_signature,
- unsigned int kappa,
unsigned int num_oldcoins,
const json_t *transfer_pubs,
const json_t *secret_encs,
@@ -396,37 +381,50 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
int res;
unsigned int i;
unsigned int j;
- struct GNUNET_CRYPTO_rsa_PublicKey **denom_pubs;
+ struct TALER_DenominationPublicKey *denom_pubs;
unsigned int num_new_denoms;
struct TALER_CoinPublicInfo *coin_public_infos;
struct MeltDetails *coin_melt_details;
unsigned int coin_count;
- struct GNUNET_HashCode commit_hash;
+ struct GNUNET_HashCode session_hash;
struct GNUNET_HashContext *hash_context;
- struct RefreshCommitCoin *commit_coin[kappa];
- struct RefreshCommitLink *commit_link[kappa];
- const struct GNUNET_CRYPTO_EddsaSignature commit_client_sig;
+ struct RefreshCommitCoin *commit_coin[KAPPA];
+ struct RefreshCommitLink *commit_link[KAPPA];
+ /* For the signature check, we hash most of the inputs together
+ (except for the signatures on the coins). */
+ hash_context = GNUNET_CRYPTO_hash_context_start ();
num_new_denoms = json_array_size (new_denoms);
denom_pubs = GNUNET_malloc (num_new_denoms *
- sizeof (struct GNUNET_CRYPTO_rsa_PublicKey *));
+ sizeof (struct TALER_DenominationPublicKey));
for (i=0;i<num_new_denoms;i++)
{
- res = GNUNET_MINT_parse_navigate_json (connection, new_denoms,
+ char *buf;
+ size_t buf_size;
+
+ res = GNUNET_MINT_parse_navigate_json (connection,
+ new_denoms,
JNAV_INDEX, (int) i,
- JNAV_RET_RSA_PUBLIC_KEY, &denom_pubs[i]);
+ JNAV_RET_RSA_PUBLIC_KEY,
+ &denom_pubs[i].rsa_public_key);
if (GNUNET_OK != res)
{
for (j=0;j<i;j++)
- GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j]);
+ GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key);
GNUNET_free (denom_pubs);
return res;
}
- }
+ buf_size = GNUNET_CRYPTO_rsa_public_key_encode (denom_pubs[i].rsa_public_key,
+ &buf);
+ GNUNET_CRYPTO_hash_context_read (hash_context,
+ buf,
+ buf_size);
+ GNUNET_free (buf);
+ }
coin_count = json_array_size (melt_coins);
/* FIXME: make 'struct TALER_CoinPublicInfo' part of `struct MeltDetails`
- and combine these two arrays/arguments! */
+ and combine these two arrays/arguments! (#3726) */
coin_public_infos = GNUNET_malloc (coin_count *
sizeof (struct TALER_CoinPublicInfo));
coin_melt_details = GNUNET_malloc (coin_count *
@@ -434,6 +432,8 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
for (i=0;i<coin_count;i++)
{
/* decode JSON data on coin to melt */
+ struct TALER_AmountNBO melt_amount;
+
res = get_coin_public_info (connection,
json_array_get (melt_coins, i),
&coin_public_infos[i],
@@ -442,25 +442,54 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
{
for (j=0;j<i;j++)
{
- GNUNET_CRYPTO_rsa_public_key_free (coin_public_infos[j].denom_pub);
- GNUNET_CRYPTO_rsa_signature_free (coin_public_infos[j].denom_sig);
+ GNUNET_CRYPTO_rsa_public_key_free (coin_public_infos[j].denom_pub.rsa_public_key);
+ GNUNET_CRYPTO_rsa_signature_free (coin_public_infos[j].denom_sig.rsa_signature);
}
GNUNET_free (coin_public_infos);
for (j=0;j<num_new_denoms;j++)
- GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j]);
+ GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key);
GNUNET_free (coin_melt_details);
GNUNET_free (denom_pubs);
return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
}
- }
+ /* Check that the client does not try to melt the same coin twice
+ into the same session! */
+ for (j=0;j<i;j++)
+ {
+ if (0 == memcmp (&coin_public_infos[i].coin_pub,
+ &coin_public_infos[j].coin_pub,
+ sizeof (struct TALER_CoinSpendPublicKey)))
+ {
+ for (j=0;j<i;j++)
+ {
+ GNUNET_CRYPTO_rsa_public_key_free (coin_public_infos[j].denom_pub.rsa_public_key);
+ GNUNET_CRYPTO_rsa_signature_free (coin_public_infos[j].denom_sig.rsa_signature);
+ }
+ GNUNET_free (coin_public_infos);
+ for (j=0;j<num_new_denoms;j++)
+ GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key);
+ GNUNET_free (coin_melt_details);
+ GNUNET_free (denom_pubs);
+ return TALER_MINT_reply_external_error (connection,
+ "melting same coin twice in same session is not allowed");
+ }
+ }
+ TALER_amount_hton (&melt_amount,
+ &coin_melt_details[i].melt_amount_with_fee);
+ GNUNET_CRYPTO_hash_context_read (hash_context,
+ &coin_public_infos[i].coin_pub,
+ sizeof (struct TALER_CoinSpendPublicKey));
+ GNUNET_CRYPTO_hash_context_read (hash_context,
+ &melt_amount,
+ sizeof (struct TALER_AmountNBO));
+ }
/* parse JSON arrays into 2d binary arrays and hash everything
together for the signature check */
memset (commit_coin, 0, sizeof (commit_coin));
memset (commit_link, 0, sizeof (commit_link));
- hash_context = GNUNET_CRYPTO_hash_context_start ();
- for (i = 0; i < kappa; i++)
+ for (i = 0; i < KAPPA; i++)
{
commit_coin[i] = GNUNET_malloc (num_newcoins *
sizeof (struct RefreshCommitCoin));
@@ -468,24 +497,27 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
{
char *link_enc;
size_t link_enc_size;
+ struct RefreshCommitCoin *rcc = &commit_coin[i][j];
res = GNUNET_MINT_parse_navigate_json (connection,
coin_evs,
JNAV_INDEX, (int) i,
JNAV_INDEX, (int) j,
JNAV_RET_DATA_VAR,
- &commit_coin[i][j].coin_ev,
- &commit_coin[i][j].coin_ev_size);
+ &rcc->coin_ev,
+ &rcc->coin_ev_size);
if (GNUNET_OK != res)
{
GNUNET_CRYPTO_hash_context_abort (hash_context);
- free_commit_coins (commit_coin, kappa, num_newcoins);
+ free_commit_coins (commit_coin,
+ KAPPA,
+ num_newcoins);
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
}
GNUNET_CRYPTO_hash_context_read (hash_context,
- commit_coin[i][j].coin_ev,
- commit_coin[i][j].coin_ev_size);
+ rcc->coin_ev,
+ rcc->coin_ev_size);
res = GNUNET_MINT_parse_navigate_json (connection,
link_encs,
JNAV_INDEX, (int) i,
@@ -496,87 +528,83 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
if (GNUNET_OK != res)
{
GNUNET_CRYPTO_hash_context_abort (hash_context);
- free_commit_coins (commit_coin, kappa, num_newcoins);
+ free_commit_coins (commit_coin,
+ KAPPA,
+ num_newcoins);
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
}
- commit_coin[i][j].refresh_link = TALER_refresh_link_encrypted_decode (link_enc,
- link_enc_size);
-
+ rcc->refresh_link
+ = TALER_refresh_link_encrypted_decode (link_enc,
+ link_enc_size);
GNUNET_CRYPTO_hash_context_read (hash_context,
link_enc,
link_enc_size);
}
}
- for (i = 0; i < kappa; i++)
+ for (i = 0; i < KAPPA; i++)
{
commit_link[i] = GNUNET_malloc (num_oldcoins *
sizeof (struct RefreshCommitLink));
for (j = 0; j < num_oldcoins; j++)
{
+ struct RefreshCommitLink *rcl = &commit_link[i][j];
+
res = GNUNET_MINT_parse_navigate_json (connection,
transfer_pubs,
JNAV_INDEX, (int) i,
JNAV_INDEX, (int) j,
JNAV_RET_DATA,
- &commit_link[i][j].transfer_pub,
- sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+ &rcl->transfer_pub,
+ sizeof (struct TALER_TransferPublicKey));
if (GNUNET_OK != res)
{
GNUNET_break (GNUNET_SYSERR != res);
GNUNET_CRYPTO_hash_context_abort (hash_context);
- free_commit_coins (commit_coin, kappa, num_newcoins);
- free_commit_links (commit_link, kappa, num_oldcoins);
+ free_commit_coins (commit_coin,
+ KAPPA,
+ num_newcoins);
+ free_commit_links (commit_link,
+ KAPPA,
+ num_oldcoins);
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
}
-
- GNUNET_CRYPTO_hash_context_read (hash_context,
- &commit_link[i][j].transfer_pub,
- sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
-
res = GNUNET_MINT_parse_navigate_json (connection,
secret_encs,
JNAV_INDEX, (int) i,
JNAV_INDEX, (int) j,
JNAV_RET_DATA,
- &commit_link[i][j].shared_secret_enc,
+ &rcl->shared_secret_enc,
sizeof (struct GNUNET_HashCode));
if (GNUNET_OK != res)
{
GNUNET_break (GNUNET_SYSERR != res);
GNUNET_CRYPTO_hash_context_abort (hash_context);
- free_commit_coins (commit_coin, kappa, num_newcoins);
- free_commit_links (commit_link, kappa, num_oldcoins);
+ free_commit_coins (commit_coin,
+ KAPPA,
+ num_newcoins);
+ free_commit_links (commit_link,
+ KAPPA,
+ num_oldcoins);
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
}
GNUNET_CRYPTO_hash_context_read (hash_context,
- &commit_link[i][j].shared_secret_enc,
- sizeof (struct GNUNET_HashCode));
+ rcl,
+ sizeof (struct RefreshCommitLink));
}
- }
- GNUNET_CRYPTO_hash_context_finish (hash_context, &commit_hash);
-
-
- res = GNUNET_MINT_parse_navigate_json (connection,
- commit_signature,
- JNAV_FIELD,
- "sig",
- JNAV_RET_DATA,
- &commit_client_sig,
- sizeof (struct GNUNET_CRYPTO_EddsaSignature));
-
- if (GNUNET_OK != res)
- return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+ }
+ GNUNET_CRYPTO_hash_context_finish (hash_context,
+ &session_hash);
for (i=0;i<coin_count;i++)
{
- /* verify signatures ons coin to melt */
+ /* verify signatures on coins to melt */
res = verify_coin_public_info (connection,
- &commit_hash,
+ &session_hash,
&coin_public_infos[i],
&coin_melt_details[i]);
if (GNUNET_OK != res)
@@ -588,30 +616,29 @@ handle_refresh_melt_json (struct MHD_Connection *connection,
/* execute commit */
res = handle_refresh_melt_binary (connection,
- refresh_session_pub,
num_new_denoms,
denom_pubs,
coin_count,
coin_public_infos,
coin_melt_details,
- &commit_hash,
- &commit_client_sig,
- kappa,
+ &session_hash,
commit_coin,
commit_link);
cleanup:
- free_commit_coins (commit_coin, kappa, num_newcoins);
- free_commit_links (commit_link, kappa, num_oldcoins);
+ free_commit_coins (commit_coin,
+ KAPPA,
+ num_newcoins);
+ free_commit_links (commit_link,
+ KAPPA,
+ num_oldcoins);
for (j=0;j<coin_count;j++)
{
- GNUNET_CRYPTO_rsa_public_key_free (coin_public_infos[j].denom_pub);
- GNUNET_CRYPTO_rsa_signature_free (coin_public_infos[j].denom_sig);
+ GNUNET_CRYPTO_rsa_public_key_free (coin_public_infos[j].denom_pub.rsa_public_key);
+ GNUNET_CRYPTO_rsa_signature_free (coin_public_infos[j].denom_sig.rsa_signature);
}
GNUNET_free (coin_public_infos);
for (j=0;j<num_new_denoms;j++)
- {
- GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j]);
- }
+ GNUNET_CRYPTO_rsa_public_key_free (denom_pubs[j].rsa_public_key);
GNUNET_free (coin_melt_details);
GNUNET_free (denom_pubs);
return res;
@@ -647,14 +674,11 @@ TALER_MINT_handler_refresh_melt (struct RequestHandler *rh,
json_t *transfer_pubs;
json_t *secret_encs;
json_t *commit_sig_json;
- unsigned int kappa;
unsigned int num_oldcoins;
unsigned int num_newcoins;
json_t *coin_detail;
- struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub;
int res;
struct GNUNET_MINT_ParseFieldSpec spec[] = {
- TALER_MINT_PARSE_FIXED ("session_pub", &refresh_session_pub),
TALER_MINT_PARSE_ARRAY ("new_denoms", &new_denoms),
TALER_MINT_PARSE_ARRAY ("melt_coins", &melt_coins),
TALER_MINT_PARSE_ARRAY ("melt_signature", &melt_sig_json),
@@ -684,15 +708,14 @@ TALER_MINT_handler_refresh_melt (struct RequestHandler *rh,
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
/* Determine dimensionality of the request (kappa, #old and #new coins) */
- kappa = json_array_size (coin_evs);
- if ( (3 > kappa) || (kappa > 32) )
+ if (KAPPA != json_array_size (coin_evs))
{
GNUNET_break_op (0);
TALER_MINT_release_parsed_data (spec);
return TALER_MINT_reply_arg_invalid (connection,
"coin_evs");
}
- if (json_array_size (transfer_pubs) != kappa)
+ if (KAPPA != json_array_size (transfer_pubs))
{
GNUNET_break_op (0);
TALER_MINT_release_parsed_data (spec);
@@ -722,12 +745,10 @@ TALER_MINT_handler_refresh_melt (struct RequestHandler *rh,
num_oldcoins = json_array_size (coin_detail);
res = handle_refresh_melt_json (connection,
- &refresh_session_pub,
new_denoms,
melt_coins,
melt_sig_json,
commit_sig_json,
- kappa,
num_oldcoins,
transfer_pubs,
secret_encs,
@@ -748,29 +769,27 @@ TALER_MINT_handler_refresh_melt (struct RequestHandler *rh,
* coins.
*
* @param connection the MHD connection to handle
- * @param refresh_session_pub public key of the session
- * @param kappa length of the 1st dimension of @a transfer_privs array PLUS ONE
+ * @param session_hash hash identifying the melting session
* @param num_oldcoins length of the 2nd dimension of @a transfer_privs array
* @param tp_json private transfer keys in JSON format
* @return MHD result code
*/
static int
handle_refresh_reveal_json (struct MHD_Connection *connection,
- const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
- unsigned int kappa,
+ const struct GNUNET_HashCode *session_hash,
unsigned int num_oldcoins,
const json_t *tp_json)
{
- struct GNUNET_CRYPTO_EcdsaPrivateKey *transfer_privs[kappa - 1];
+ struct TALER_TransferPrivateKey *transfer_privs[KAPPA - 1];
unsigned int i;
unsigned int j;
int res;
- for (i = 0; i < kappa - 1; i++)
+ for (i = 0; i < KAPPA - 1; i++)
transfer_privs[i] = GNUNET_malloc (num_oldcoins *
- sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
+ sizeof (struct TALER_TransferPrivateKey));
res = GNUNET_OK;
- for (i = 0; i < kappa - 1; i++)
+ for (i = 0; i < KAPPA - 1; i++)
{
if (GNUNET_OK != res)
break;
@@ -784,18 +803,17 @@ handle_refresh_reveal_json (struct MHD_Connection *connection,
JNAV_INDEX, (int) j,
JNAV_RET_DATA,
&transfer_privs[i][j],
- sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
+ sizeof (struct TALER_TransferPrivateKey));
}
}
if (GNUNET_OK != res)
res = (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
else
res = TALER_MINT_db_execute_refresh_reveal (connection,
- refresh_session_pub,
- kappa,
+ session_hash,
num_oldcoins,
transfer_privs);
- for (i = 0; i < kappa - 1; i++)
+ for (i = 0; i < KAPPA - 1; i++)
GNUNET_free (transfer_privs[i]);
return res;
}
@@ -824,15 +842,14 @@ TALER_MINT_handler_refresh_reveal (struct RequestHandler *rh,
const char *upload_data,
size_t *upload_data_size)
{
- struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub;
+ struct GNUNET_HashCode session_hash;
int res;
- unsigned int kappa;
unsigned int num_oldcoins;
json_t *reveal_detail;
json_t *root;
json_t *transfer_privs;
struct GNUNET_MINT_ParseFieldSpec spec[] = {
- TALER_MINT_PARSE_FIXED ("session_pub", &refresh_session_pub),
+ TALER_MINT_PARSE_FIXED ("session_hash", &session_hash),
TALER_MINT_PARSE_ARRAY ("transfer_privs", &transfer_privs),
TALER_MINT_PARSE_END
};
@@ -855,15 +872,13 @@ TALER_MINT_handler_refresh_reveal (struct RequestHandler *rh,
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
/* Determine dimensionality of the request (kappa and #old coins) */
- kappa = json_array_size (transfer_privs) + 1;
- if ( (2 > kappa) || (kappa > 31) )
+ if (KAPPA != json_array_size (transfer_privs) + 1)
{
TALER_MINT_release_parsed_data (spec);
return TALER_MINT_reply_arg_invalid (connection,
"transfer_privs");
}
/* Note we do +1 as 1 row (cut-and-choose!) is missing! */
- kappa++;
res = GNUNET_MINT_parse_navigate_json (connection,
transfer_privs,
JNAV_INDEX, 0,
@@ -877,8 +892,7 @@ TALER_MINT_handler_refresh_reveal (struct RequestHandler *rh,
}
num_oldcoins = json_array_size (reveal_detail);
res = handle_refresh_reveal_json (connection,
- &refresh_session_pub,
- kappa,
+ &session_hash,
num_oldcoins,
transfer_privs);
TALER_MINT_release_parsed_data (spec);
@@ -903,13 +917,13 @@ TALER_MINT_handler_refresh_link (struct RequestHandler *rh,
const char *upload_data,
size_t *upload_data_size)
{
- struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub;
+ struct TALER_CoinSpendPublicKey coin_pub;
int res;
res = TALER_MINT_mhd_request_arg_data (connection,
"coin_pub",
&coin_pub,
- sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
+ sizeof (struct TALER_CoinSpendPublicKey));
if (GNUNET_SYSERR == res)
return MHD_NO;
if (GNUNET_OK != res)
diff --git a/src/mint/taler-mint-httpd_responses.c b/src/mint/taler-mint-httpd_responses.c
index 9cc92cd6f..667ce7927 100644
--- a/src/mint/taler-mint-httpd_responses.c
+++ b/src/mint/taler-mint-httpd_responses.c
@@ -282,15 +282,15 @@ TALER_MINT_reply_invalid_json (struct MHD_Connection *connection)
*/
int
TALER_MINT_reply_deposit_success (struct MHD_Connection *connection,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
+ const struct TALER_CoinSpendPublicKey *coin_pub,
const struct GNUNET_HashCode *h_wire,
const struct GNUNET_HashCode *h_contract,
uint64_t transaction_id,
- const struct GNUNET_CRYPTO_EddsaPublicKey *merchant,
+ const struct TALER_MerchantPublicKey *merchant,
const struct TALER_Amount *amount)
{
struct TALER_DepositConfirmation dc;
- struct GNUNET_CRYPTO_EddsaSignature sig;
+ struct TALER_MintSignature sig;
json_t *sig_json;
int ret;
@@ -299,12 +299,14 @@ TALER_MINT_reply_deposit_success (struct MHD_Connection *connection,
dc.h_contract = *h_contract;
dc.h_wire = *h_wire;
dc.transaction_id = GNUNET_htonll (transaction_id);
- dc.amount = TALER_amount_hton (*amount);
+ TALER_amount_hton (&dc.amount_with_fee,
+ amount);
dc.coin_pub = *coin_pub;
dc.merchant = *merchant;
TALER_MINT_keys_sign (&dc.purpose,
&sig);
- sig_json = TALER_JSON_from_eddsa_sig (&dc.purpose, &sig);
+ sig_json = TALER_JSON_from_eddsa_sig (&dc.purpose,
+ &sig.eddsa_signature);
ret = TALER_MINT_reply_json_pack (connection,
MHD_HTTP_OK,
"{s:s, s:o}",
@@ -341,16 +343,17 @@ compile_transaction_history (const struct TALER_MINT_DB_TransactionList *tl)
const struct Deposit *deposit = pos->details.deposit;
type = "deposit";
- value = deposit->amount;
+ value = deposit->amount_with_fee;
dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_DEPOSIT);
dr.purpose.size = htonl (sizeof (struct TALER_DepositRequest));
dr.h_contract = deposit->h_contract;
dr.h_wire = deposit->h_wire;
dr.transaction_id = GNUNET_htonll (deposit->transaction_id);
- dr.amount = TALER_amount_hton (deposit->amount);
+ TALER_amount_hton (&dr.amount_with_fee,
+ &deposit->amount_with_fee);
dr.coin_pub = deposit->coin.coin_pub;
transaction = TALER_JSON_from_ecdsa_sig (&dr.purpose,
- &deposit->csig);
+ &deposit->csig.ecdsa_signature);
break;
}
case TALER_MINT_DB_TT_REFRESH_MELT:
@@ -359,14 +362,15 @@ compile_transaction_history (const struct TALER_MINT_DB_TransactionList *tl)
const struct RefreshMelt *melt = pos->details.melt;
type = "melt";
- value = melt->amount;
+ value = melt->amount_with_fee;
ms.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_COIN);
ms.purpose.size = htonl (sizeof (struct RefreshMeltCoinSignature));
- ms.melt_hash = melt->melt_hash;
- ms.amount = TALER_amount_hton (melt->amount);
+ ms.session_hash = melt->session_hash;
+ TALER_amount_hton (&ms.amount_with_fee,
+ &melt->amount_with_fee);
ms.coin_pub = melt->coin.coin_pub;
transaction = TALER_JSON_from_ecdsa_sig (&ms.purpose,
- &melt->coin_sig);
+ &melt->coin_sig.ecdsa_signature);
}
break;
case TALER_MINT_DB_TT_LOCK:
@@ -383,7 +387,7 @@ compile_transaction_history (const struct TALER_MINT_DB_TransactionList *tl)
json_array_append_new (history,
json_pack ("{s:s, s:o}",
"type", type,
- "amount", TALER_JSON_from_amount (value),
+ "amount", TALER_JSON_from_amount (&value),
"signature", transaction));
}
return history;
@@ -420,7 +424,7 @@ TALER_MINT_reply_deposit_insufficient_funds (struct MHD_Connection *connection,
*
* @param rh reserve history to JSON-ify
* @param balance[OUT] set to current reserve balance
- * @return json representation of the @a rh
+ * @return json representation of the @a rh, NULL on error
*/
static json_t *
compile_reserve_history (const struct ReserveHistory *rh,
@@ -447,14 +451,20 @@ compile_reserve_history (const struct ReserveHistory *rh,
if (0 == ret)
deposit_total = pos->details.bank->amount;
else
- deposit_total = TALER_amount_add (deposit_total,
- pos->details.bank->amount);
+ if (GNUNET_OK !=
+ TALER_amount_add (&deposit_total,
+ &deposit_total,
+ &pos->details.bank->amount))
+ {
+ json_decref (json_history);
+ return NULL;
+ }
ret = 1;
json_array_append_new (json_history,
json_pack ("{s:s, s:o, s:o}",
"type", "DEPOSIT",
"wire", pos->details.bank->wire,
- "amount", TALER_JSON_from_amount (pos->details.bank->amount)));
+ "amount", TALER_JSON_from_amount (&pos->details.bank->amount)));
break;
case TALER_MINT_DB_RO_WITHDRAW_COIN:
break;
@@ -472,37 +482,52 @@ compile_reserve_history (const struct ReserveHistory *rh,
case TALER_MINT_DB_RO_WITHDRAW_COIN:
dki = TALER_MINT_get_denom_key (key_state,
- pos->details.withdraw->denom_pub);
- value = TALER_amount_ntoh (dki->issue.value);
+ &pos->details.withdraw->denom_pub);
+ TALER_amount_ntoh (&value,
+ &dki->issue.value);
if (0 == ret)
withdraw_total = value;
else
- withdraw_total = TALER_amount_add (withdraw_total,
- value);
+ if (GNUNET_OK !=
+ TALER_amount_add (&withdraw_total,
+ &withdraw_total,
+ &value))
+ {
+ TALER_MINT_key_state_release (key_state);
+ json_decref (json_history);
+ return NULL;
+ }
ret = 1;
wr.purpose.purpose = htonl (TALER_SIGNATURE_WITHDRAW);
wr.purpose.size = htonl (sizeof (struct TALER_WithdrawRequest));
wr.reserve_pub = pos->details.withdraw->reserve_pub;
- GNUNET_CRYPTO_rsa_public_key_hash (pos->details.withdraw->denom_pub,
+ GNUNET_CRYPTO_rsa_public_key_hash (pos->details.withdraw->denom_pub.rsa_public_key,
&wr.h_denomination_pub);
wr.h_coin_envelope = pos->details.withdraw->h_coin_envelope;
transaction = TALER_JSON_from_eddsa_sig (&wr.purpose,
- &pos->details.withdraw->reserve_sig);
+ &pos->details.withdraw->reserve_sig.eddsa_signature);
json_array_append_new (json_history,
json_pack ("{s:s, s:o, s:o}",
"type", "WITHDRAW",
"signature", transaction,
- "amount", TALER_JSON_from_amount (value)));
+ "amount", TALER_JSON_from_amount (&value)));
break;
}
}
TALER_MINT_key_state_release (key_state);
- *balance = TALER_amount_subtract (deposit_total,
- withdraw_total);
+ if (GNUNET_SYSERR ==
+ TALER_amount_subtract (balance,
+ &deposit_total,
+ &withdraw_total))
+ {
+ GNUNET_break (0);
+ json_decref (json_history);
+ return NULL;
+ }
return json_history;
}
@@ -525,7 +550,10 @@ TALER_MINT_reply_withdraw_status_success (struct MHD_Connection *connection,
json_history = compile_reserve_history (rh,
&balance);
- json_balance = TALER_JSON_from_amount (balance);
+ if (NULL == json_history)
+ return TALER_MINT_reply_internal_error (connection,
+ "balance calculation failure");
+ json_balance = TALER_JSON_from_amount (&balance);
ret = TALER_MINT_reply_json_pack (connection,
MHD_HTTP_OK,
"{s:o, s:o}",
@@ -557,7 +585,10 @@ TALER_MINT_reply_withdraw_sign_insufficient_funds (struct MHD_Connection *connec
json_history = compile_reserve_history (rh,
&balance);
- json_balance = TALER_JSON_from_amount (balance);
+ if (NULL == json_history)
+ return TALER_MINT_reply_internal_error (connection,
+ "balance calculation failure");
+ json_balance = TALER_JSON_from_amount (&balance);
ret = TALER_MINT_reply_json_pack (connection,
MHD_HTTP_PAYMENT_REQUIRED,
"{s:s, s:o, s:o}",
@@ -582,15 +613,9 @@ TALER_MINT_reply_withdraw_sign_success (struct MHD_Connection *connection,
const struct CollectableBlindcoin *collectable)
{
json_t *sig_json;
- size_t sig_buf_size;
- char *sig_buf;
int ret;
- sig_buf_size = GNUNET_CRYPTO_rsa_signature_encode (collectable->sig,
- &sig_buf);
- sig_json = TALER_JSON_from_data (sig_buf,
- sig_buf_size);
- GNUNET_free (sig_buf);
+ sig_json = TALER_JSON_from_rsa_signature (collectable->sig.rsa_signature);
ret = TALER_MINT_reply_json_pack (connection,
MHD_HTTP_OK,
"{s:o}",
@@ -617,7 +642,7 @@ TALER_MINT_reply_withdraw_sign_success (struct MHD_Connection *connection,
*/
int
TALER_MINT_reply_refresh_melt_insufficient_funds (struct MHD_Connection *connection,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
+ const struct TALER_CoinSpendPublicKey *coin_pub,
struct TALER_Amount coin_value,
struct TALER_MINT_DB_TransactionList *tl,
struct TALER_Amount requested,
@@ -631,10 +656,10 @@ TALER_MINT_reply_refresh_melt_insufficient_funds (struct MHD_Connection *connect
"{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 GNUNET_CRYPTO_EcdsaPublicKey)),
- "original-value", TALER_JSON_from_amount (coin_value),
- "residual-value", TALER_JSON_from_amount (residual),
- "requested-value", TALER_JSON_from_amount (requested),
+ sizeof (struct TALER_CoinSpendPublicKey)),
+ "original-value", TALER_JSON_from_amount (&coin_value),
+ "residual-value", TALER_JSON_from_amount (&residual),
+ "requested-value", TALER_JSON_from_amount (&requested),
"history", history);
}
@@ -653,7 +678,7 @@ TALER_MINT_reply_refresh_melt_success (struct MHD_Connection *connection,
uint16_t noreveal_index)
{
struct RefreshMeltResponseSignatureBody body;
- struct GNUNET_CRYPTO_EddsaSignature sig;
+ struct TALER_MintSignature sig;
json_t *sig_json;
int ret;
@@ -664,7 +689,7 @@ TALER_MINT_reply_refresh_melt_success (struct MHD_Connection *connection,
TALER_MINT_keys_sign (&body.purpose,
&sig);
sig_json = TALER_JSON_from_eddsa_sig (&body.purpose,
- &sig);
+ &sig.eddsa_signature);
GNUNET_assert (NULL != sig_json);
ret = TALER_MINT_reply_json_pack (connection,
MHD_HTTP_OK,
@@ -687,27 +712,21 @@ TALER_MINT_reply_refresh_melt_success (struct MHD_Connection *connection,
int
TALER_MINT_reply_refresh_reveal_success (struct MHD_Connection *connection,
unsigned int num_newcoins,
- struct GNUNET_CRYPTO_rsa_Signature **sigs)
+ const struct TALER_DenominationSignature *sigs)
{
int newcoin_index;
json_t *root;
json_t *list;
- char *buf;
- size_t buf_size;
int ret;
root = json_object ();
list = json_array ();
- json_object_set_new (root, "ev_sigs", list);
+ json_object_set_new (root,
+ "ev_sigs",
+ list);
for (newcoin_index = 0; newcoin_index < num_newcoins; newcoin_index++)
- {
- buf_size = GNUNET_CRYPTO_rsa_signature_encode (sigs[newcoin_index],
- &buf);
json_array_append_new (list,
- TALER_JSON_from_data (buf,
- buf_size));
- GNUNET_free (buf);
- }
+ TALER_JSON_from_rsa_signature (sigs[newcoin_index].rsa_signature));
ret = TALER_MINT_reply_json (connection,
root,
MHD_HTTP_OK);
@@ -760,7 +779,7 @@ TALER_MINT_reply_refresh_reveal_missmatch (struct MHD_Connection *connection,
*/
int
TALER_MINT_reply_refresh_link_success (struct MHD_Connection *connection,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *transfer_pub,
+ const struct TALER_TransferPublicKey *transfer_pub,
const struct TALER_EncryptedLinkSecret *shared_secret_enc,
const struct LinkDataList *ldl)
{
@@ -773,26 +792,18 @@ TALER_MINT_reply_refresh_link_success (struct MHD_Connection *connection,
for (pos = ldl; NULL != pos; pos = pos->next)
{
json_t *obj;
- char *buf;
- size_t buf_len;
obj = json_object ();
json_object_set_new (obj, "link_enc",
TALER_JSON_from_data (ldl->link_data_enc->coin_priv_enc,
- sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey) +
+ sizeof (struct TALER_CoinSpendPrivateKey) +
ldl->link_data_enc->blinding_key_enc_size));
- buf_len = GNUNET_CRYPTO_rsa_public_key_encode (ldl->denom_pub,
- &buf);
- json_object_set_new (obj, "denom_pub",
- TALER_JSON_from_data (buf,
- buf_len));
- GNUNET_free (buf);
- buf_len = GNUNET_CRYPTO_rsa_signature_encode (ldl->ev_sig,
- &buf);
- json_object_set_new (obj, "ev_sig",
- TALER_JSON_from_data (buf,
- buf_len));
- GNUNET_free (buf);
+ json_object_set_new (obj,
+ "denom_pub",
+ TALER_JSON_from_rsa_public_key (ldl->denom_pub.rsa_public_key));
+ json_object_set_new (obj,
+ "ev_sig",
+ TALER_JSON_from_rsa_signature (ldl->ev_sig.rsa_signature));
json_array_append_new (list, obj);
}
@@ -803,7 +814,7 @@ TALER_MINT_reply_refresh_link_success (struct MHD_Connection *connection,
json_object_set_new (root,
"transfer_pub",
TALER_JSON_from_data (transfer_pub,
- sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)));
+ sizeof (struct TALER_TransferPublicKey)));
json_object_set_new (root,
"secret_enc",
TALER_JSON_from_data (shared_secret_enc,
diff --git a/src/mint/taler-mint-httpd_responses.h b/src/mint/taler-mint-httpd_responses.h
index d42aa29b6..d7e563505 100644
--- a/src/mint/taler-mint-httpd_responses.h
+++ b/src/mint/taler-mint-httpd_responses.h
@@ -185,11 +185,11 @@ TALER_MINT_reply_invalid_json (struct MHD_Connection *connection);
*/
int
TALER_MINT_reply_deposit_success (struct MHD_Connection *connection,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
+ const struct TALER_CoinSpendPublicKey *coin_pub,
const struct GNUNET_HashCode *h_wire,
const struct GNUNET_HashCode *h_contract,
uint64_t transaction_id,
- const struct GNUNET_CRYPTO_EddsaPublicKey *merchant,
+ const struct TALER_MerchantPublicKey *merchant,
const struct TALER_Amount *amount);
@@ -276,7 +276,7 @@ TALER_MINT_reply_refresh_melt_success (struct MHD_Connection *connection,
*/
int
TALER_MINT_reply_refresh_melt_insufficient_funds (struct MHD_Connection *connection,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
+ const struct TALER_CoinSpendPublicKey *coin_pub,
struct TALER_Amount coin_value,
struct TALER_MINT_DB_TransactionList *tl,
struct TALER_Amount requested,
@@ -294,7 +294,7 @@ TALER_MINT_reply_refresh_melt_insufficient_funds (struct MHD_Connection *connect
int
TALER_MINT_reply_refresh_reveal_success (struct MHD_Connection *connection,
unsigned int num_newcoins,
- struct GNUNET_CRYPTO_rsa_Signature **sigs);
+ const struct TALER_DenominationSignature *sigs);
/**
@@ -332,7 +332,7 @@ TALER_MINT_reply_refresh_reveal_missmatch (struct MHD_Connection *connection,
*/
int
TALER_MINT_reply_refresh_link_success (struct MHD_Connection *connection,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *transfer_pub,
+ const struct TALER_TransferPublicKey *transfer_pub,
const struct TALER_EncryptedLinkSecret *shared_secret_enc,
const struct LinkDataList *ldl);
diff --git a/src/mint/taler-mint-httpd_withdraw.c b/src/mint/taler-mint-httpd_withdraw.c
index b796af946..7d7ca8060 100644
--- a/src/mint/taler-mint-httpd_withdraw.c
+++ b/src/mint/taler-mint-httpd_withdraw.c
@@ -49,13 +49,13 @@ TALER_MINT_handler_withdraw_status (struct RequestHandler *rh,
const char *upload_data,
size_t *upload_data_size)
{
- struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
+ struct TALER_ReservePublicKey reserve_pub;
int res;
res = TALER_MINT_mhd_request_arg_data (connection,
"reserve_pub",
&reserve_pub,
- sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
+ sizeof (struct TALER_ReservePublicKey));
if (GNUNET_SYSERR == res)
return MHD_NO; /* internal error */
if (GNUNET_NO == res)
@@ -90,17 +90,17 @@ TALER_MINT_handler_withdraw_sign (struct RequestHandler *rh,
{
struct TALER_WithdrawRequest wsrd;
int res;
- struct GNUNET_CRYPTO_rsa_PublicKey *denomination_pub;
+ struct TALER_DenominationPublicKey denomination_pub;
char *denomination_pub_data;
size_t denomination_pub_data_size;
char *blinded_msg;
size_t blinded_msg_len;
- struct GNUNET_CRYPTO_EddsaSignature signature;
+ struct TALER_ReserveSignature signature;
res = TALER_MINT_mhd_request_arg_data (connection,
"reserve_pub",
&wsrd.reserve_pub,
- sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
+ sizeof (struct TALER_ReservePublicKey));
if (GNUNET_SYSERR == res)
return MHD_NO; /* internal error */
if (GNUNET_NO == res)
@@ -108,7 +108,7 @@ TALER_MINT_handler_withdraw_sign (struct RequestHandler *rh,
res = TALER_MINT_mhd_request_arg_data (connection,
"reserve_sig",
&signature,
- sizeof (struct GNUNET_CRYPTO_EddsaSignature));
+ sizeof (struct TALER_ReserveSignature));
if (GNUNET_SYSERR == res)
return MHD_NO; /* internal error */
if (GNUNET_NO == res)
@@ -148,8 +148,8 @@ TALER_MINT_handler_withdraw_sign (struct RequestHandler *rh,
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WITHDRAW,
&wsrd.purpose,
- &signature,
- &wsrd.reserve_pub))
+ &signature.eddsa_signature,
+ &wsrd.reserve_pub.eddsa_pub))
{
LOG_WARNING ("Client supplied invalid signature for /withdraw/sign request\n");
GNUNET_free (denomination_pub_data);
@@ -157,10 +157,11 @@ TALER_MINT_handler_withdraw_sign (struct RequestHandler *rh,
return TALER_MINT_reply_arg_invalid (connection,
"reserve_sig");
}
- denomination_pub = GNUNET_CRYPTO_rsa_public_key_decode (denomination_pub_data,
- denomination_pub_data_size);
+ denomination_pub.rsa_public_key
+ = GNUNET_CRYPTO_rsa_public_key_decode (denomination_pub_data,
+ denomination_pub_data_size);
GNUNET_free (denomination_pub_data);
- if (NULL == denomination_pub)
+ if (NULL == denomination_pub.rsa_public_key)
{
LOG_WARNING ("Client supplied ill-formed denomination public key for /withdraw/sign request\n");
GNUNET_free (blinded_msg);
@@ -169,12 +170,12 @@ TALER_MINT_handler_withdraw_sign (struct RequestHandler *rh,
}
res = TALER_MINT_db_execute_withdraw_sign (connection,
&wsrd.reserve_pub,
- denomination_pub,
+ &denomination_pub,
blinded_msg,
blinded_msg_len,
&signature);
GNUNET_free (blinded_msg);
- GNUNET_CRYPTO_rsa_public_key_free (denomination_pub);
+ GNUNET_CRYPTO_rsa_public_key_free (denomination_pub.rsa_public_key);
return res;
}
diff --git a/src/mint/taler-mint-keycheck.c b/src/mint/taler-mint-keycheck.c
index c934d08fa..370b1c51a 100644
--- a/src/mint/taler-mint-keycheck.c
+++ b/src/mint/taler-mint-keycheck.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2014, 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
@@ -13,127 +13,166 @@
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 taler-mint-keycheck.c
- * @brief Check mint keys for validity.
+ * @brief Check mint keys for validity. Reads the signing and denomination
+ * keys from the mint directory and checks to make sure they are
+ * well-formed. This is purely a diagnostic tool.
* @author Florian Dold
* @author Benedikt Mueller
+ * @author Christian Grothoff
*/
-
#include <platform.h>
#include <gnunet/gnunet_util_lib.h>
-#include "taler_signatures.h"
#include "key_io.h"
-
+/**
+ * Mint directory with the keys.
+ */
static char *mintdir;
+
+/**
+ * Our configuration.
+ */
static struct GNUNET_CONFIGURATION_Handle *kcfg;
+/**
+ * Function called on each signing key.
+ *
+ * @param cls closure (NULL)
+ * @param filename name of the file the key came from
+ * @param ski the sign key
+ * @return #GNUNET_OK to continue to iterate,
+ * #GNUNET_NO to stop iteration with no error,
+ * #GNUNET_SYSERR to abort iteration with error!
+ */
static int
-signkeys_iter (void *cls, const struct TALER_MINT_SignKeyIssuePriv *ski)
+signkeys_iter (void *cls,
+ const char *filename,
+ const struct TALER_MINT_SignKeyIssuePriv *ski)
{
- struct GNUNET_TIME_Absolute start;
-
- printf ("iterating over key for start time %s\n",
- GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (ski->issue.start)));
-
- start = GNUNET_TIME_absolute_ntoh (ski->issue.start);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Iterating over key `%s' for start time %s\n",
+ filename,
+ GNUNET_STRINGS_absolute_time_to_string
+ (GNUNET_TIME_absolute_ntoh (ski->issue.start)));
if (ntohl (ski->issue.purpose.size) !=
- (sizeof (struct TALER_MINT_SignKeyIssue) - offsetof (struct TALER_MINT_SignKeyIssue, purpose)))
+ (sizeof (struct TALER_MINT_SignKeyIssue) -
+ offsetof (struct TALER_MINT_SignKeyIssue, purpose)))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Signkey with start %s has invalid purpose field (timestamp: %llu)\n",
- GNUNET_STRINGS_absolute_time_to_string (start),
- (long long) start.abs_value_us);
+ fprintf (stderr,
+ "Signing key `%s' has invalid purpose size\n",
+ filename);
return GNUNET_SYSERR;
}
-
-
- if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SIGNKEY,
- &ski->issue.purpose,
- &ski->issue.signature,
- &ski->issue.master_pub))
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SIGNKEY,
+ &ski->issue.purpose,
+ &ski->issue.signature.eddsa_signature,
+ &ski->issue.master_pub.eddsa_pub))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Signkey with start %s has invalid signature (timestamp: %llu)\n",
- GNUNET_STRINGS_absolute_time_to_string (start),
- (long long) start.abs_value_us);
+ fprintf (stderr,
+ "Signing key `%s' has invalid signature\n",
+ filename);
return GNUNET_SYSERR;
}
- /* FIXME: what about private key matching the public key? */
- printf ("key valid\n");
+ printf ("Signing key `%s' valid\n",
+ filename);
return GNUNET_OK;
}
+/**
+ * Check signing keys.
+ *
+ * @return #GNUNET_OK if the keys are OK
+ * #GNUNET_NO if not
+ */
static int
mint_signkeys_check ()
{
- if (0 > TALER_MINT_signkeys_iterate (mintdir, signkeys_iter, NULL))
+ if (0 > TALER_MINT_signkeys_iterate (mintdir,
+ &signkeys_iter,
+ NULL))
return GNUNET_NO;
return GNUNET_OK;
}
+/**
+ * Function called on each denomination key.
+ *
+ * @param cls closure (NULL)
+ * @param dki the denomination key
+ * @param alias coin alias
+ * @return #GNUNET_OK to continue to iterate,
+ * #GNUNET_NO to stop iteration with no error,
+ * #GNUNET_SYSERR to abort iteration with error!
+ */
static int
denomkeys_iter (void *cls,
const char *alias,
const struct TALER_MINT_DenomKeyIssuePriv *dki)
{
- struct GNUNET_TIME_Absolute start;
-
- start = GNUNET_TIME_absolute_ntoh (dki->issue.start);
+ struct GNUNET_HashCode hc;
if (ntohl (dki->issue.purpose.size) !=
- (sizeof (struct TALER_MINT_DenomKeyIssuePriv) - offsetof (struct TALER_MINT_DenomKeyIssuePriv, issue.purpose)))
+ sizeof (struct TALER_MINT_DenomKeyIssue))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Denomkey for '%s' with start %s has invalid purpose field (timestamp: %llu)\n",
- alias,
- GNUNET_STRINGS_absolute_time_to_string (start),
- (long long) start.abs_value_us);
+ fprintf (stderr,
+ "Denomination key for `%s' has invalid purpose size\n",
+ alias);
return GNUNET_SYSERR;
}
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOM,
&dki->issue.purpose,
- &dki->issue.signature,
- &dki->issue.master))
+ &dki->issue.signature.eddsa_signature,
+ &dki->issue.master.eddsa_pub))
+ {
+ fprintf (stderr,
+ "Denomination key for `%s' has invalid signature\n",
+ alias);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_CRYPTO_rsa_public_key_hash (dki->denom_pub.rsa_public_key,
+ &hc);
+ if (0 != memcmp (&hc,
+ &dki->issue.denom_hash,
+ sizeof (struct GNUNET_HashCode)))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Denomkey for '%s'with start %s has invalid signature (timestamp: %llu)\n",
- alias,
- GNUNET_STRINGS_absolute_time_to_string (start),
- (long long) start.abs_value_us);
+ fprintf (stderr,
+ "Public key for `%s' does not match signature\n",
+ alias);
return GNUNET_SYSERR;
}
- printf ("denom key valid\n");
+ printf ("Denomination key `%s' is valid\n",
+ alias);
return GNUNET_OK;
}
+/**
+ * Check denomination keys.
+ *
+ * @return #GNUNET_OK if the keys are OK
+ * #GNUNET_NO if not
+ */
static int
mint_denomkeys_check ()
{
if (0 > TALER_MINT_denomkeys_iterate (mintdir,
- &denomkeys_iter, NULL))
+ &denomkeys_iter,
+ NULL))
return GNUNET_NO;
return GNUNET_OK;
}
-static int
-mint_keys_check (void)
-{
- if (GNUNET_OK != mint_signkeys_check ())
- return GNUNET_NO;
- return mint_denomkeys_check ();
-}
-
-
/**
* The main function of the keyup tool
*
@@ -145,30 +184,44 @@ int
main (int argc, char *const *argv)
{
static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- GNUNET_GETOPT_OPTION_HELP ("gnunet-mint-keyup OPTIONS"),
- {'d', "mint-dir", "DIR",
- "mint directory with keys to update", 1,
+ GNUNET_GETOPT_OPTION_HELP ("gnunet-mint-keycheck OPTIONS"),
+ {'d', "directory", "DIRECTORY",
+ "mint directory with keys to check", 1,
&GNUNET_GETOPT_set_filename, &mintdir},
GNUNET_GETOPT_OPTION_END
};
- GNUNET_assert (GNUNET_OK == GNUNET_log_setup ("taler-mint-keycheck", "WARNING", NULL));
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_log_setup ("taler-mint-keycheck",
+ "WARNING",
+ NULL));
- if (GNUNET_GETOPT_run ("taler-mint-keyup", options, argc, argv) < 0)
+ if (GNUNET_GETOPT_run ("taler-mint-keycheck",
+ options,
+ argc, argv) < 0)
return 1;
if (NULL == mintdir)
{
- fprintf (stderr, "mint directory not given\n");
+ fprintf (stderr,
+ "Mint directory not given\n");
return 1;
}
kcfg = TALER_config_load (mintdir);
if (NULL == kcfg)
{
- fprintf (stderr, "can't load mint configuration\n");
+ fprintf (stderr,
+ "Failed to load mint configuration\n");
return 1;
}
- if (GNUNET_OK != mint_keys_check ())
+ if ( (GNUNET_OK != mint_signkeys_check ()) ||
+ (GNUNET_OK != mint_denomkeys_check ()) )
+ {
+ GNUNET_CONFIGURATION_destroy (kcfg);
return 1;
+ }
+ GNUNET_CONFIGURATION_destroy (kcfg);
return 0;
}
+
+/* end of taler-mint-keycheck.c */
diff --git a/src/mint/taler-mint-keyup.c b/src/mint/taler-mint-keyup.c
index c4e153476..603154f65 100644
--- a/src/mint/taler-mint-keyup.c
+++ b/src/mint/taler-mint-keyup.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2014, 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
@@ -13,58 +13,140 @@
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 taler-mint-keyup.c
* @brief Update the mint's keys for coins and signatures,
* using the mint's offline master key.
* @author Florian Dold
* @author Benedikt Mueller
+ * @author Christian Grothoff
*/
-
#include <platform.h>
#include <gnunet/gnunet_util_lib.h>
#include "taler_util.h"
-#include "taler_signatures.h"
#include "key_io.h"
/**
- * FIXME: allow user to specify (within reason).
+ * When generating filenames from a cryptographic hash, we do not use
+ * all 512 bits but cut off after this number of characters (in
+ * base32-encoding). Base32 is 5 bit per character, and given that we
+ * have very few coin types we hash, at 100 bits the chance of
+ * collision (by accident over tiny set -- birthday paradox does not
+ * apply here!) is negligible.
*/
-#define RSA_KEYSIZE 2048
-
#define HASH_CUTOFF 20
/**
* Macro to round microseconds to seconds in GNUNET_TIME_* structs.
+ *
+ * @param name value to round
+ * @param field rel_value_us or abs_value_us
*/
#define ROUND_TO_SECS(name,us_field) name.us_field -= name.us_field % (1000 * 1000);
GNUNET_NETWORK_STRUCT_BEGIN
+/**
+ * Struct with all of the key information for a kind of coin. Hashed
+ * to generate a unique directory name per coin type.
+ */
struct CoinTypeNBO
{
+ /**
+ * How long can the coin be spend?
+ */
struct GNUNET_TIME_RelativeNBO duration_spend;
+
+ /**
+ * How long can the coin be withdrawn (generated)?
+ */
struct GNUNET_TIME_RelativeNBO duration_withdraw;
+
+ /**
+ * What is the value of the coin?
+ */
struct TALER_AmountNBO value;
+
+ /**
+ * What is the fee charged for withdrawl?
+ */
struct TALER_AmountNBO fee_withdraw;
+
+ /**
+ * What is the fee charged for deposits?
+ */
struct TALER_AmountNBO fee_deposit;
+
+ /**
+ * What is the fee charged for melting?
+ */
struct TALER_AmountNBO fee_refresh;
+
+ /**
+ * Key size in NBO.
+ */
+ uint32_t rsa_keysize;
};
GNUNET_NETWORK_STRUCT_END
+/**
+ * Set of all of the parameters that chracterize a coin.
+ */
struct CoinTypeParams
{
+
+ /**
+ * How long can the coin be spend? Should be significantly
+ * larger than @e duration_withdraw (i.e. years).
+ */
struct GNUNET_TIME_Relative duration_spend;
+
+ /**
+ * How long can the coin be withdrawn (generated)? Should be small
+ * enough to limit how many coins will be signed into existence with
+ * the same key, but large enough to still provide a reasonable
+ * anonymity set.
+ */
struct GNUNET_TIME_Relative duration_withdraw;
+
+ /**
+ * How much should coin creation (@e duration_withdraw) duration
+ * overlap with the next coin? Basically, the starting time of two
+ * coins is always @e duration_withdraw - @e duration_overlap apart.
+ */
struct GNUNET_TIME_Relative duration_overlap;
+
+ /**
+ * What is the value of the coin?
+ */
struct TALER_Amount value;
+
+ /**
+ * What is the fee charged for withdrawl?
+ */
struct TALER_Amount fee_withdraw;
+
+ /**
+ * What is the fee charged for deposits?
+ */
struct TALER_Amount fee_deposit;
+
+ /**
+ * What is the fee charged for melting?
+ */
struct TALER_Amount fee_refresh;
+
+ /**
+ * Time at which this coin is supposed to become valid.
+ */
struct GNUNET_TIME_Absolute anchor;
+
+ /**
+ * Length of the RSA key in bits.
+ */
+ uint32_t rsa_keysize;
};
@@ -97,12 +179,12 @@ static struct GNUNET_TIME_Absolute now;
/**
* Master private key of the mint.
*/
-static struct GNUNET_CRYPTO_EddsaPrivateKey *master_priv;
+static struct TALER_MasterPrivateKey master_priv;
/**
* Master public key of the mint.
*/
-static struct GNUNET_CRYPTO_EddsaPublicKey *master_pub;
+static struct TALER_MasterPublicKey master_pub;
/**
* Until what time do we provide keys?
@@ -110,152 +192,183 @@ static struct GNUNET_CRYPTO_EddsaPublicKey *master_pub;
static struct GNUNET_TIME_Absolute lookahead_sign_stamp;
-static int
-config_get_denom (const char *section, const char *option, struct TALER_Amount *denom)
-{
- char *str;
- if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (kcfg, section, option, &str))
- return GNUNET_NO;
- if (GNUNET_OK != TALER_string_to_amount (str, denom))
- return GNUNET_SYSERR;
- return GNUNET_OK;
-}
-
-
-static char *
-get_signkey_dir ()
-{
- char *dir;
- size_t len;
- len = GNUNET_asprintf (&dir, ("%s" DIR_SEPARATOR_STR DIR_SIGNKEYS), mintdir);
- GNUNET_assert (len > 0);
- return dir;
-}
-
-
-static char *
+/**
+ * Obtain the name of the directory we use to store signing
+ * keys created at time @a start.
+ *
+ * @param start time at which we create the signing key
+ * @return name of the directory we should use, basically "$MINTDIR/$TIME/";
+ * (valid until next call to this function)
+ */
+static const char *
get_signkey_file (struct GNUNET_TIME_Absolute start)
{
- char *dir;
- size_t len;
- len = GNUNET_asprintf (&dir, ("%s" DIR_SEPARATOR_STR DIR_SIGNKEYS DIR_SEPARATOR_STR "%llu"),
- mintdir, (long long) start.abs_value_us);
- GNUNET_assert (len > 0);
+ static char dir[4096];
+
+ GNUNET_snprintf (dir,
+ sizeof (dir),
+ "%s" DIR_SEPARATOR_STR DIR_SIGNKEYS DIR_SEPARATOR_STR "%llu",
+ mintdir,
+ (unsigned long long) start.abs_value_us);
return dir;
}
/**
- * Hash the data defining the coin type.
- * Exclude information that may not be the same for all
- * instances of the coin type (i.e. the anchor, overlap).
+ * Hash the data defining the coin type. Exclude information that may
+ * not be the same for all instances of the coin type (i.e. the
+ * anchor, overlap).
+ *
+ * @param p coin parameters to convert to a hash
+ * @param hash[OUT] set to the hash matching @a p
*/
static void
-hash_coin_type (const struct CoinTypeParams *p, struct GNUNET_HashCode *hash)
+hash_coin_type (const struct CoinTypeParams *p,
+ struct GNUNET_HashCode *hash)
{
struct CoinTypeNBO p_nbo;
- memset (&p_nbo, 0, sizeof (struct CoinTypeNBO));
-
+ memset (&p_nbo,
+ 0,
+ sizeof (struct CoinTypeNBO));
p_nbo.duration_spend = GNUNET_TIME_relative_hton (p->duration_spend);
p_nbo.duration_withdraw = GNUNET_TIME_relative_hton (p->duration_withdraw);
- p_nbo.value = TALER_amount_hton (p->value);
- p_nbo.fee_withdraw = TALER_amount_hton (p->fee_withdraw);
- p_nbo.fee_deposit = TALER_amount_hton (p->fee_deposit);
- p_nbo.fee_refresh = TALER_amount_hton (p->fee_refresh);
-
- GNUNET_CRYPTO_hash (&p_nbo, sizeof (struct CoinTypeNBO), hash);
+ TALER_amount_hton (&p_nbo.value,
+ &p->value);
+ TALER_amount_hton (&p_nbo.fee_withdraw,
+ &p->fee_withdraw);
+ TALER_amount_hton (&p_nbo.fee_deposit,
+ &p->fee_deposit);
+ TALER_amount_hton (&p_nbo.fee_refresh,
+ &p->fee_refresh);
+ p_nbo.rsa_keysize = htonl (p->rsa_keysize);
+ GNUNET_CRYPTO_hash (&p_nbo,
+ sizeof (struct CoinTypeNBO),
+ hash);
}
+/**
+ * Obtain the name of the directory we should use to store coins of
+ * the given type. The directory name has the format
+ * "$MINTDIR/$VALUE/$HASH/" where "$VALUE" represents the value of the
+ * coin and "$HASH" encodes all of the coin's parameters, generating a
+ * unique string for each type of coin. Note that the "$HASH"
+ * includes neither the absolute creation time nor the key of the
+ * coin, thus the files in the subdirectory really just refer to the
+ * same type of coins, not the same coin.
+ *
+ * @param p coin parameters to convert to a directory name
+ * @return directory name (valid until next call to this function)
+ */
static const char *
get_cointype_dir (const struct CoinTypeParams *p)
{
static char dir[4096];
- size_t len;
struct GNUNET_HashCode hash;
char *hash_str;
char *val_str;
- unsigned int i;
+ size_t i;
hash_coin_type (p, &hash);
hash_str = GNUNET_STRINGS_data_to_string_alloc (&hash,
sizeof (struct GNUNET_HashCode));
- GNUNET_assert (HASH_CUTOFF <= strlen (hash_str) + 1);
GNUNET_assert (NULL != hash_str);
+ GNUNET_assert (HASH_CUTOFF <= strlen (hash_str) + 1);
hash_str[HASH_CUTOFF] = 0;
- val_str = TALER_amount_to_string (p->value);
+ val_str = TALER_amount_to_string (&p->value);
for (i = 0; i < strlen (val_str); i++)
- if (':' == val_str[i] || '.' == val_str[i])
+ if ( (':' == val_str[i]) ||
+ ('.' == val_str[i]) )
val_str[i] = '_';
- len = GNUNET_snprintf (dir, sizeof (dir),
- ("%s" DIR_SEPARATOR_STR DIR_DENOMKEYS DIR_SEPARATOR_STR "%s-%s"),
- mintdir, val_str, hash_str);
- GNUNET_assert (len > 0);
+ GNUNET_snprintf (dir,
+ sizeof (dir),
+ "%s" DIR_SEPARATOR_STR DIR_DENOMKEYS DIR_SEPARATOR_STR "%s-%s",
+ mintdir,
+ val_str,
+ hash_str);
GNUNET_free (hash_str);
+ GNUNET_free (val_str);
return dir;
}
+/**
+ * Obtain the name of the file we would use to store the key
+ * information for a coin of the given type @a p and validity
+ * start time @a start
+ *
+ * @param p parameters for the coin
+ * @param start when would the coin begin to be issued
+ * @return name of the file to use for this coin
+ * (valid until next call to this function)
+ */
static const char *
-get_cointype_file (struct CoinTypeParams *p,
+get_cointype_file (const struct CoinTypeParams *p,
struct GNUNET_TIME_Absolute start)
{
- const char *dir;
static char filename[4096];
- size_t len;
+ const char *dir;
+
dir = get_cointype_dir (p);
- len = GNUNET_snprintf (filename, sizeof (filename), ("%s" DIR_SEPARATOR_STR "%llu"),
- dir, (unsigned long long) start.abs_value_us);
- GNUNET_assert (len > 0);
+ GNUNET_snprintf (filename,
+ sizeof (filename),
+ "%s" DIR_SEPARATOR_STR "%llu",
+ dir,
+ (unsigned long long) start.abs_value_us);
return filename;
}
/**
- * Get the latest key file from the past.
+ * Get the latest key file from a past run of the key generation
+ * tool. Used to calculate the starting time for the keys we
+ * generate during this invocation. This function is used to
+ * handle both signing keys and coin keys, as in both cases
+ * the filenames correspond to the timestamps we need.
*
- * @param cls closure
+ * @param cls closure, a `struct GNUNET_TIME_Absolute *`, updated
+ * to contain the highest timestamp (below #now)
+ * that was found
* @param filename complete filename (absolute path)
- * @return #GNUNET_OK to continue to iterate,
- * #GNUNET_NO to stop iteration with no error,
- * #GNUNET_SYSERR to abort iteration with error!
+ * @return #GNUNET_OK (to continue to iterate)
*/
static int
get_anchor_iter (void *cls,
const char *filename)
{
- struct GNUNET_TIME_Absolute stamp;
struct GNUNET_TIME_Absolute *anchor = cls;
+ struct GNUNET_TIME_Absolute stamp;
const char *base;
char *end = NULL;
base = GNUNET_STRINGS_get_short_name (filename);
- stamp.abs_value_us = strtol (base, &end, 10);
-
+ stamp.abs_value_us = strtol (base,
+ &end,
+ 10);
if ((NULL == end) || (0 != *end))
{
- fprintf(stderr, "Ignoring unexpected file '%s'.\n", filename);
+ fprintf(stderr,
+ "Ignoring unexpected file `%s'.\n",
+ filename);
return GNUNET_OK;
}
-
- // TODO: check if it's actually a valid key file
-
- if ((stamp.abs_value_us <= now.abs_value_us) && (stamp.abs_value_us > anchor->abs_value_us))
- *anchor = stamp;
-
+ if (stamp.abs_value_us <= now.abs_value_us)
+ *anchor = GNUNET_TIME_absolute_max (stamp,
+ *anchor);
return GNUNET_OK;
}
/**
* Get the timestamp where the first new key should be generated.
- * Relies on correctly named key files.
+ * Relies on correctly named key files (as we do not parse them,
+ * but just look at the filenames to "guess" at their contents).
*
- * @param dir directory with the signed stuff
- * @param duration how long is one key valid?
+ * @param dir directory that should contain the existing keys
+ * @param duration how long is one key valid (for signing)?
* @param overlap what's the overlap between the keys validity period?
* @param[out] anchor the timestamp where the first new key should be generated
*/
@@ -267,36 +380,57 @@ get_anchor (const char *dir,
{
GNUNET_assert (0 == duration.rel_value_us % 1000000);
GNUNET_assert (0 == overlap.rel_value_us % 1000000);
- if (GNUNET_YES != GNUNET_DISK_directory_test (dir, GNUNET_YES))
+ if (GNUNET_YES !=
+ GNUNET_DISK_directory_test (dir,
+ GNUNET_YES))
{
*anchor = now;
- printf ("Can't look for anchor (%s)\n", dir);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "No existing keys found, starting with fresh key set.\n");
return;
}
-
*anchor = GNUNET_TIME_UNIT_ZERO_ABS;
- if (-1 == GNUNET_DISK_directory_scan (dir, &get_anchor_iter, anchor))
+ if (-1 ==
+ GNUNET_DISK_directory_scan (dir,
+ &get_anchor_iter,
+ anchor))
{
*anchor = now;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "No existing keys found, starting with fresh key set.\n");
return;
}
- if ((GNUNET_TIME_absolute_add (*anchor, duration)).abs_value_us < now.abs_value_us)
+ /* FIXME: this check is a bit dubious, as 'now'
+ may be way into the future if we want to generate
+ many keys... #3727*/
+ if ((GNUNET_TIME_absolute_add (*anchor,
+ duration)).abs_value_us < now.abs_value_us)
{
- // there's no good anchor, start from now
- // (existing keys are too old)
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Existing keys are way too old, starting with fresh key set.\n");
*anchor = now;
}
- else if (anchor->abs_value_us != now.abs_value_us)
+ else if (anchor->abs_value_us != now.abs_value_us) // Also odd...
{
- // we have a good anchor
- *anchor = GNUNET_TIME_absolute_add (*anchor, duration);
- *anchor = GNUNET_TIME_absolute_subtract (*anchor, overlap);
+ /* Real starting time is the last start time + duration - overlap */
+ *anchor = GNUNET_TIME_absolute_add (*anchor,
+ duration);
+ *anchor = GNUNET_TIME_absolute_subtract (*anchor,
+ overlap);
}
- // anchor is now the stamp where we need to create a new key
+ /* anchor is now the stamp where we need to create a new key */
}
+/**
+ * Create a mint signing key (for signing mint messages, not for coins)
+ * and assert its correctness by signing it with the master key.
+ *
+ * @param start start time of the validity period for the key
+ * @param duration how long should the key be valid
+ * @param pi[OUT] set to the signing key information
+ */
static void
create_signkey_issue_priv (struct GNUNET_TIME_Absolute start,
struct GNUNET_TIME_Relative duration,
@@ -306,33 +440,32 @@ create_signkey_issue_priv (struct GNUNET_TIME_Absolute start,
struct TALER_MINT_SignKeyIssue *issue = &pi->issue;
priv = GNUNET_CRYPTO_eddsa_key_create ();
- GNUNET_assert (NULL != priv);
- pi->signkey_priv = *priv;
+ pi->signkey_priv.eddsa_priv = *priv;
GNUNET_free (priv);
- issue->master_pub = *master_pub;
+ issue->master_pub = master_pub;
issue->start = GNUNET_TIME_absolute_hton (start);
- issue->expire = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (start, duration));
-
- GNUNET_CRYPTO_eddsa_key_get_public (&pi->signkey_priv, &issue->signkey_pub);
-
+ issue->expire = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (start,
+ duration));
+ GNUNET_CRYPTO_eddsa_key_get_public (&pi->signkey_priv.eddsa_priv,
+ &issue->signkey_pub.eddsa_pub);
issue->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNKEY);
- issue->purpose.size = htonl (sizeof (struct TALER_MINT_SignKeyIssue) - offsetof (struct TALER_MINT_SignKeyIssue, purpose));
+ issue->purpose.size = htonl (sizeof (struct TALER_MINT_SignKeyIssue) -
+ offsetof (struct TALER_MINT_SignKeyIssue,
+ purpose));
GNUNET_assert (GNUNET_OK ==
- GNUNET_CRYPTO_eddsa_sign (master_priv,
+ GNUNET_CRYPTO_eddsa_sign (&master_priv.eddsa_priv,
&issue->purpose,
- &issue->signature));
-}
-
-
-static int
-check_signkey_valid (const char *signkey_filename)
-{
- // FIXME: do real checks
- return GNUNET_OK;
+ &issue->signature.eddsa_signature));
}
+/**
+ * Generate signing keys starting from the last key found to
+ * the lookahead time.
+ *
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
static int
mint_keys_update_signkeys ()
{
@@ -340,110 +473,219 @@ mint_keys_update_signkeys ()
struct GNUNET_TIME_Absolute anchor;
char *signkey_dir;
- if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (kcfg, "mint_keys", "signkey_duration", &signkey_duration))
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (kcfg,
+ "mint_keys",
+ "signkey_duration",
+ &signkey_duration))
{
- fprintf (stderr, "Can't read config value mint_keys.signkey_duration\n");
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "mint_keys",
+ "signkey_duration");
return GNUNET_SYSERR;
}
- ROUND_TO_SECS (signkey_duration, rel_value_us);
- signkey_dir = get_signkey_dir ();
- // make sure the directory exists
- if (GNUNET_OK != GNUNET_DISK_directory_create (signkey_dir))
+ ROUND_TO_SECS (signkey_duration,
+ rel_value_us);
+ GNUNET_asprintf (&signkey_dir,
+ "%s" DIR_SEPARATOR_STR DIR_SIGNKEYS,
+ mintdir);
+ /* make sure the directory exists */
+ if (GNUNET_OK !=
+ GNUNET_DISK_directory_create (signkey_dir))
{
- fprintf (stderr, "Cant create signkey dir\n");
+ fprintf (stderr,
+ "Failed to create signing key directory\n");
return GNUNET_SYSERR;
}
- get_anchor (signkey_dir, signkey_duration, GNUNET_TIME_UNIT_ZERO, &anchor);
+ get_anchor (signkey_dir,
+ signkey_duration,
+ GNUNET_TIME_UNIT_ZERO /* no overlap for signing keys */,
+ &anchor);
+
+ while (anchor.abs_value_us < lookahead_sign_stamp.abs_value_us)
+ {
+ const char *skf;
+ struct TALER_MINT_SignKeyIssuePriv signkey_issue;
+ ssize_t nwrite;
- while (anchor.abs_value_us < lookahead_sign_stamp.abs_value_us) {
- char *skf;
skf = get_signkey_file (anchor);
- if (GNUNET_YES != GNUNET_DISK_file_test (skf))
- {
- struct TALER_MINT_SignKeyIssuePriv signkey_issue;
- ssize_t nwrite;
- printf ("Generating signing key for %s.\n",
- GNUNET_STRINGS_absolute_time_to_string (anchor));
- create_signkey_issue_priv (anchor, signkey_duration, &signkey_issue);
- nwrite = GNUNET_DISK_fn_write (skf, &signkey_issue, sizeof (struct TALER_MINT_SignKeyIssue),
- (GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_USER_READ));
- if (nwrite != sizeof (struct TALER_MINT_SignKeyIssue))
- {
- fprintf (stderr, "Can't write to file '%s'\n", skf);
- return GNUNET_SYSERR;
- }
- }
- else if (GNUNET_OK != check_signkey_valid (skf))
+ GNUNET_break (GNUNET_YES !=
+ GNUNET_DISK_file_test (skf));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Generating signing key for %s.\n",
+ GNUNET_STRINGS_absolute_time_to_string (anchor));
+ create_signkey_issue_priv (anchor,
+ signkey_duration,
+ &signkey_issue);
+ nwrite = GNUNET_DISK_fn_write (skf,
+ &signkey_issue,
+ sizeof (struct TALER_MINT_SignKeyIssue),
+ GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_USER_READ);
+ if (nwrite != sizeof (struct TALER_MINT_SignKeyIssue))
{
+ fprintf (stderr,
+ "Failed to write to file `%s': %s\n",
+ skf,
+ STRERROR (errno));
return GNUNET_SYSERR;
}
- anchor = GNUNET_TIME_absolute_add (anchor, signkey_duration);
+ anchor = GNUNET_TIME_absolute_add (anchor,
+ signkey_duration);
}
return GNUNET_OK;
}
+/**
+ * Parse configuration for coin type parameters. Also determines
+ * our anchor by looking at the existing coins of the same type.
+ *
+ * @param ct section in the configuration file giving the coin type parameters
+ * @param params[OUT] set to the coin parameters from the configuration
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR if the configuration is invalid
+ */
static int
-get_cointype_params (const char *ct, struct CoinTypeParams *params)
+get_cointype_params (const char *ct,
+ struct CoinTypeParams *params)
{
const char *dir;
- if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (kcfg, "mint_denom_duration_withdraw", ct, &params->duration_withdraw))
+ unsigned long long rsa_keysize;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (kcfg,
+ ct,
+ "duration_withdraw",
+ &params->duration_withdraw))
{
- fprintf (stderr, "Withdraw duration not given for coin type '%s'\n", ct);
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ ct,
+ "duration_withdraw");
return GNUNET_SYSERR;
}
- ROUND_TO_SECS (params->duration_withdraw, rel_value_us);
- if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (kcfg, "mint_denom_duration_spend", ct, &params->duration_spend))
+ ROUND_TO_SECS (params->duration_withdraw,
+ rel_value_us);
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (kcfg,
+ ct,
+ "duration_spend",
+ &params->duration_spend))
{
- fprintf (stderr, "Spend duration not given for coin type '%s'\n", ct);
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ ct,
+ "duration_spend");
return GNUNET_SYSERR;
}
- ROUND_TO_SECS (params->duration_spend, rel_value_us);
- if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (kcfg, "mint_denom_duration_overlap", ct, &params->duration_overlap))
+ ROUND_TO_SECS (params->duration_spend,
+ rel_value_us);
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (kcfg,
+ ct,
+ "duration_overlap",
+ &params->duration_overlap))
{
- fprintf (stderr, "Overlap duration not given for coin type '%s'\n", ct);
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ ct,
+ "mint_denom_duration_overlap");
return GNUNET_SYSERR;
}
- ROUND_TO_SECS (params->duration_overlap, rel_value_us);
-
- if (GNUNET_OK != config_get_denom ("mint_denom_value", ct, &params->value))
+ ROUND_TO_SECS (params->duration_overlap,
+ rel_value_us);
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (kcfg,
+ ct,
+ "rsa_keysize",
+ &rsa_keysize))
{
- fprintf (stderr, "Value not given for coin type '%s'\n", ct);
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ ct,
+ "rsa_keysize");
return GNUNET_SYSERR;
}
-
- if (GNUNET_OK != config_get_denom ("mint_denom_fee_withdraw", ct, &params->fee_withdraw))
+ if ( (rsa_keysize > 4 * 2048) ||
+ (rsa_keysize < 1024) )
{
- fprintf (stderr, "Withdraw fee not given for coin type '%s'\n", ct);
+ fprintf (stderr,
+ "Given RSA keysize %llu outside of permitted range\n",
+ rsa_keysize);
return GNUNET_SYSERR;
}
-
- if (GNUNET_OK != config_get_denom ("mint_denom_fee_deposit", ct, &params->fee_deposit))
+ params->rsa_keysize = (unsigned int) rsa_keysize;
+ if (GNUNET_OK !=
+ TALER_config_get_denom (kcfg,
+ ct,
+ "value",
+ &params->value))
{
- fprintf (stderr, "Deposit fee not given for coin type '%s'\n", ct);
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ ct,
+ "value");
return GNUNET_SYSERR;
}
-
- if (GNUNET_OK != config_get_denom ("mint_denom_fee_refresh", ct, &params->fee_refresh))
+ if (GNUNET_OK !=
+ TALER_config_get_denom (kcfg,
+ ct,
+ "fee_withdraw",
+ &params->fee_withdraw))
{
- fprintf (stderr, "Deposit fee not given for coin type '%s'\n", ct);
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ ct,
+ "fee_withdraw");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_config_get_denom (kcfg,
+ ct,
+ "fee_deposit",
+ &params->fee_deposit))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ ct,
+ "fee_deposit");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_config_get_denom (kcfg,
+ ct,
+ "fee_refresh",
+ &params->fee_refresh))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ ct,
+ "fee_refresh");
return GNUNET_SYSERR;
}
dir = get_cointype_dir (params);
- get_anchor (dir, params->duration_spend, params->duration_overlap, &params->anchor);
+ get_anchor (dir,
+ params->duration_spend,
+ params->duration_overlap,
+ &params->anchor);
return GNUNET_OK;
}
+/**
+ * Initialize the private and public key information structure for
+ * signing coins into existence. Generates the private signing key
+ * and signes it together with the coin's meta data using the master
+ * signing key.
+ *
+ * @param params parameters used to initialize the @a dki
+ * @param dki[OUT] initialized according to @a params
+ */
static void
-create_denomkey_issue (struct CoinTypeParams *params,
+create_denomkey_issue (const struct CoinTypeParams *params,
struct TALER_MINT_DenomKeyIssuePriv *dki)
{
- GNUNET_assert (NULL != (dki->denom_priv = GNUNET_CRYPTO_rsa_private_key_create (RSA_KEYSIZE)));
- dki->issue.denom_pub = GNUNET_CRYPTO_rsa_private_key_get_public (dki->denom_priv);
- dki->issue.master = *master_pub;
+ dki->denom_priv.rsa_private_key
+ = GNUNET_CRYPTO_rsa_private_key_create (params->rsa_keysize);
+ GNUNET_assert (NULL != dki->denom_priv.rsa_private_key);
+ dki->denom_pub.rsa_public_key
+ = GNUNET_CRYPTO_rsa_private_key_get_public (dki->denom_priv.rsa_private_key);
+ GNUNET_CRYPTO_rsa_public_key_hash (dki->denom_pub.rsa_public_key,
+ &dki->issue.denom_hash);
+ dki->issue.master = master_pub;
dki->issue.start = GNUNET_TIME_absolute_hton (params->anchor);
dki->issue.expire_withdraw =
GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor,
@@ -451,137 +693,125 @@ create_denomkey_issue (struct CoinTypeParams *params,
dki->issue.expire_spend =
GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor,
params->duration_spend));
- dki->issue.value = TALER_amount_hton (params->value);
- dki->issue.fee_withdraw = TALER_amount_hton (params->fee_withdraw);
- dki->issue.fee_deposit = TALER_amount_hton (params->fee_deposit);
- dki->issue.fee_refresh = TALER_amount_hton (params->fee_refresh);
-
+ TALER_amount_hton (&dki->issue.value,
+ &params->value);
+ TALER_amount_hton (&dki->issue.fee_withdraw,
+ &params->fee_withdraw);
+ TALER_amount_hton (&dki->issue.fee_deposit,
+ &params->fee_deposit);
+ TALER_amount_hton (&dki->issue.fee_refresh,
+ &params->fee_refresh);
dki->issue.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOM);
- dki->issue.purpose.size = htonl (sizeof (struct TALER_MINT_DenomKeyIssuePriv) - offsetof (struct TALER_MINT_DenomKeyIssuePriv, issue.purpose));
-
+ dki->issue.purpose.size = htonl (sizeof (struct TALER_MINT_DenomKeyIssuePriv) -
+ offsetof (struct TALER_MINT_DenomKeyIssuePriv,
+ issue.purpose));
GNUNET_assert (GNUNET_OK ==
- GNUNET_CRYPTO_eddsa_sign (master_priv,
+ GNUNET_CRYPTO_eddsa_sign (&master_priv.eddsa_priv,
&dki->issue.purpose,
- &dki->issue.signature));
-}
-
-
-static int
-check_cointype_valid (const char *filename, struct CoinTypeParams *params)
-{
- // FIXME: add real checks
- return GNUNET_OK;
+ &dki->issue.signature.eddsa_signature));
}
-static int
-mint_keys_update_cointype (const char *coin_alias)
+/**
+ * Generate new coin signing keys for the coin type of the given @a
+ * coin_alias.
+ *
+ * @param cls a `int *`, to be set to #GNUNET_SYSERR on failure
+ * @param coin_alias name of the coin's section in the configuration
+ */
+static void
+mint_keys_update_cointype (void *cls,
+ const char *coin_alias)
{
+ int *ret = cls;
struct CoinTypeParams p;
- const char *cointype_dir;
-
- if (GNUNET_OK != get_cointype_params (coin_alias, &p))
- return GNUNET_SYSERR;
-
- cointype_dir = get_cointype_dir (&p);
- if (GNUNET_OK != GNUNET_DISK_directory_create (cointype_dir))
- return GNUNET_SYSERR;
-
- while (p.anchor.abs_value_us < lookahead_sign_stamp.abs_value_us) {
- const char *dkf;
- dkf = get_cointype_file (&p, p.anchor);
-
- if (GNUNET_YES != GNUNET_DISK_file_test (dkf))
- {
- struct TALER_MINT_DenomKeyIssuePriv denomkey_issue;
- int ret;
- printf ("Generating denomination key for type '%s', start %s.\n",
- coin_alias,
- GNUNET_STRINGS_absolute_time_to_string (p.anchor));
- printf ("Target path: %s\n", dkf);
- create_denomkey_issue (&p, &denomkey_issue);
- ret = TALER_MINT_write_denom_key (dkf, &denomkey_issue);
- GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv);
- if (GNUNET_OK != ret)
- {
- fprintf (stderr, "Can't write to file '%s'\n", dkf);
- return GNUNET_SYSERR;
- }
- }
- else if (GNUNET_OK != check_cointype_valid (dkf, &p))
- {
- return GNUNET_SYSERR;
- }
- p.anchor = GNUNET_TIME_absolute_add (p.anchor, p.duration_spend);
- p.anchor = GNUNET_TIME_absolute_subtract (p.anchor, p.duration_overlap);
+ const char *dkf;
+ struct TALER_MINT_DenomKeyIssuePriv denomkey_issue;
+
+ if (0 != strncasecmp (coin_alias,
+ "coin_",
+ strlen ("coin_")))
+ return; /* not a coin definition */
+ if (GNUNET_OK !=
+ get_cointype_params (coin_alias,
+ &p))
+ {
+ *ret = GNUNET_SYSERR;
+ return;
}
- return GNUNET_OK;
-}
-
-
-static int
-mint_keys_update_denomkeys ()
-{
- char *coin_types;
- char *ct;
- char *tok_ctx;
-
- if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (kcfg, "mint_keys", "coin_types", &coin_types))
+ if (GNUNET_OK !=
+ GNUNET_DISK_directory_create (get_cointype_dir (&p)))
{
- fprintf (stderr, "mint_keys.coin_types not in configuration\n");
- return GNUNET_SYSERR;
+ *ret = GNUNET_SYSERR;
+ return;
}
- for (ct = strtok_r (coin_types, " ", &tok_ctx);
- ct != NULL;
- ct = strtok_r (NULL, " ", &tok_ctx))
+ while (p.anchor.abs_value_us < lookahead_sign_stamp.abs_value_us)
{
- if (GNUNET_OK != mint_keys_update_cointype (ct))
+ dkf = get_cointype_file (&p,
+ p.anchor);
+ GNUNET_break (GNUNET_YES != GNUNET_DISK_file_test (dkf));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Generating denomination key for type `%s', start %s at %s\n",
+ coin_alias,
+ GNUNET_STRINGS_absolute_time_to_string (p.anchor),
+ dkf);
+ create_denomkey_issue (&p,
+ &denomkey_issue);
+ if (GNUNET_OK !=
+ TALER_MINT_write_denom_key (dkf,
+ &denomkey_issue))
{
- GNUNET_free (coin_types);
- return GNUNET_SYSERR;
+ fprintf (stderr,
+ "Failed to write denomination key information to file `%s'.\n",
+ dkf);
+ *ret = GNUNET_SYSERR;
+ GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key);
+ return;
}
+ GNUNET_CRYPTO_rsa_private_key_free (denomkey_issue.denom_priv.rsa_private_key);
+ p.anchor = GNUNET_TIME_absolute_add (p.anchor,
+ p.duration_spend);
+ p.anchor = GNUNET_TIME_absolute_subtract (p.anchor,
+ p.duration_overlap);
}
- GNUNET_free (coin_types);
- return GNUNET_OK;
}
+/**
+ * Update all of the denomination keys of the mint.
+ *
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
static int
-mint_keys_update ()
+mint_keys_update_denomkeys ()
{
- int ret;
- struct GNUNET_TIME_Relative lookahead_sign;
- if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (kcfg, "mint_keys", "lookahead_sign", &lookahead_sign))
- {
- fprintf (stderr, "mint_keys.lookahead_sign not found\n");
- return GNUNET_SYSERR;
- }
- if (lookahead_sign.rel_value_us == 0)
- {
- fprintf (stderr, "mint_keys.lookahead_sign must not be zero\n");
- return GNUNET_SYSERR;
- }
- ROUND_TO_SECS (lookahead_sign, rel_value_us);
- lookahead_sign_stamp = GNUNET_TIME_absolute_add (now, lookahead_sign);
+ int ok;
- ret = mint_keys_update_signkeys ();
- if (GNUNET_OK != ret)
- return GNUNET_SYSERR;
-
- return mint_keys_update_denomkeys ();
+ ok = GNUNET_OK;
+ GNUNET_CONFIGURATION_iterate_sections (kcfg,
+ &mint_keys_update_cointype,
+ &ok);
+ return ok;
}
/**
- * The main function of the keyup tool
+ * The main function of the taler-mint-keyup tool. This tool is used
+ * to create the signing and denomination keys for the mint. It uses
+ * the long-term offline private key and writes the (additional) key
+ * files to the respective mint directory (from where they can then be
+ * copied to the online server). Note that we need (at least) the
+ * most recent generated previous keys so as to align the validity
+ * periods.
*
* @param argc number of arguments from the command line
* @param argv command line arguments
* @return 0 ok, 1 on error
*/
int
-main (int argc, char *const *argv)
+main (int argc,
+ char *const *argv)
{
static const struct GNUNET_GETOPT_CommandLineOption options[] = {
GNUNET_GETOPT_OPTION_HELP ("gnunet-mint-keyup OPTIONS"),
@@ -596,22 +826,33 @@ main (int argc, char *const *argv)
&GNUNET_GETOPT_set_string, &pretend_time_str},
GNUNET_GETOPT_OPTION_END
};
+ struct GNUNET_TIME_Relative lookahead_sign;
+ struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv;
- GNUNET_assert (GNUNET_OK == GNUNET_log_setup ("taler-mint-keyup", "WARNING", NULL));
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_log_setup ("taler-mint-keyup",
+ "WARNING",
+ NULL));
- if (GNUNET_GETOPT_run ("taler-mint-keyup", options, argc, argv) < 0)
+ if (GNUNET_GETOPT_run ("taler-mint-keyup",
+ options,
+ argc, argv) < 0)
return 1;
if (NULL == mintdir)
{
- fprintf (stderr, "mint directory not given\n");
+ fprintf (stderr,
+ "Mint directory not given\n");
return 1;
}
-
if (NULL != pretend_time_str)
{
- if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_absolute (pretend_time_str, &now))
+ if (GNUNET_OK !=
+ GNUNET_STRINGS_fancy_time_to_absolute (pretend_time_str,
+ &now))
{
- fprintf (stderr, "timestamp invalid\n");
+ fprintf (stderr,
+ "timestamp `%s' invalid\n",
+ pretend_time_str);
return 1;
}
}
@@ -624,44 +865,90 @@ main (int argc, char *const *argv)
kcfg = TALER_config_load (mintdir);
if (NULL == kcfg)
{
- fprintf (stderr, "can't load mint configuration\n");
+ fprintf (stderr,
+ "Failed to load mint configuration\n");
return 1;
}
-
if (NULL == masterkeyfile)
{
- fprintf (stderr, "master key file not given\n");
+ fprintf (stderr,
+ "Master key file not given\n");
return 1;
}
- master_priv = GNUNET_CRYPTO_eddsa_key_create_from_file (masterkeyfile);
- if (NULL == master_priv)
+ eddsa_priv = GNUNET_CRYPTO_eddsa_key_create_from_file (masterkeyfile);
+ if (NULL == eddsa_priv)
{
- fprintf (stderr, "master key invalid\n");
+ fprintf (stderr,
+ "Failed to initialize master key from file `%s'\n",
+ masterkeyfile);
return 1;
}
+ master_priv.eddsa_priv = *eddsa_priv;
+ GNUNET_free (eddsa_priv);
+ GNUNET_CRYPTO_eddsa_key_get_public (&master_priv.eddsa_priv,
+ &master_pub.eddsa_pub);
- master_pub = GNUNET_new (struct GNUNET_CRYPTO_EddsaPublicKey);
- GNUNET_CRYPTO_eddsa_key_get_public (master_priv, master_pub);
-
- // check if key from file matches the one from the configuration
+ /* check if key from file matches the one from the configuration */
{
struct GNUNET_CRYPTO_EddsaPublicKey master_pub_from_cfg;
+
if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_data (kcfg, "mint", "master_pub",
+ GNUNET_CONFIGURATION_get_data (kcfg,
+ "mint",
+ "master_pub",
&master_pub_from_cfg,
sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
{
- fprintf (stderr, "master key missing in configuration (mint.master_pub)\n");
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "mint",
+ "master_pub");
return 1;
}
- if (0 != memcmp (master_pub, &master_pub_from_cfg, sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
+ if (0 !=
+ memcmp (&master_pub,
+ &master_pub_from_cfg,
+ sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
{
- fprintf (stderr, "Mismatch between key from mint configuration and master private key file from command line.\n");
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "mint",
+ "master_pub",
+ _("does not match with private key"));
return 1;
}
}
- if (GNUNET_OK != mint_keys_update ())
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (kcfg,
+ "mint_keys",
+ "lookahead_sign",
+ &lookahead_sign))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "mint_keys",
+ "lookahead_sign");
+ return GNUNET_SYSERR;
+ }
+ if (0 == lookahead_sign.rel_value_us)
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "mint_keys",
+ "lookahead_sign",
+ _("must not be zero"));
+ return GNUNET_SYSERR;
+ }
+ ROUND_TO_SECS (lookahead_sign,
+ rel_value_us);
+ lookahead_sign_stamp = GNUNET_TIME_absolute_add (now,
+ lookahead_sign);
+
+
+ /* finally, do actual work */
+ if (GNUNET_OK != mint_keys_update_signkeys ())
+ return 1;
+
+ if (GNUNET_OK != mint_keys_update_denomkeys ())
return 1;
return 0;
}
+
+/* end of taler-mint-keyup.c */
diff --git a/src/mint/taler-mint-reservemod.c b/src/mint/taler-mint-reservemod.c
index e7795e67e..68f736ffb 100644
--- a/src/mint/taler-mint-reservemod.c
+++ b/src/mint/taler-mint-reservemod.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2014, 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
@@ -13,63 +13,93 @@
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 taler-mint-reservemod.c
- * @brief Modify reserves.
+ * @brief Modify reserves. Allows manipulation of reserve balances.
* @author Florian Dold
* @author Benedikt Mueller
*/
-
#include "platform.h"
#include <gnunet/gnunet_util_lib.h>
#include <libpq-fe.h>
#include "taler_util.h"
#include "taler_signatures.h"
-#include "mint_db.h"
+#include "taler_mintdb_plugin.h"
#include "db_pq.h"
-char *mintdir;
+/**
+ * Director of the mint, containing the keys.
+ */
+static char *mintdir;
+
+/**
+ * Public key of the reserve to manipulate.
+ */
static struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub;
-struct GNUNET_CONFIGURATION_Handle *cfg;
+/**
+ * Handle to the mint's configuration
+ */
+static struct GNUNET_CONFIGURATION_Handle *cfg;
+/**
+ * Database connection handle.
+ */
static PGconn *db_conn;
-
/**
- * Create a new or add to existing reserve.
- * Fails if currencies do not match.
+ * Create a new or add to existing reserve. Fails if currencies do
+ * not match.
*
* @param denom denomination to add
- *
- * @return ...
+ * @return #GNUNET_OK on success,
+ * #GNUNET_SYSERR on error
*/
+// FIXME: this should use the DB abstraction layer. (#3717)
+// FIXME: this should be done by adding an inbound transaction
+// to the table with the transactions for this reserve,
+// not by modifying some 'total' value for the reserve!
+// (we should in fact probably never modify, always just append!) (#3633)
static int
reservemod_add (struct TALER_Amount denom)
{
PGresult *result;
- {
- const void *param_values[] = { reserve_pub };
- int param_lengths[] = {sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)};
- int param_formats[] = {1};
- result = PQexecParams (db_conn,
- "select balance_value, balance_fraction, balance_currency from reserves where reserve_pub=$1 limit 1;",
- 1, NULL, (const char * const *) param_values, param_lengths, param_formats, 1);
- }
+ const void *param_values[] = {
+ reserve_pub
+ };
+ int param_lengths[] = {
+ sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)
+ };
+ int param_formats[] = {
+ 1
+ };
+ struct TALER_Amount old_denom;
+ struct TALER_Amount new_denom;
+ struct TALER_AmountNBO new_denom_nbo;
+ result = PQexecParams (db_conn,
+ "SELECT balance_value, balance_fraction, balance_currency"
+ " FROM reserves"
+ " WHERE reserve_pub=$1"
+ " LIMIT 1;",
+ 1,
+ NULL,
+ (const char * const *) param_values,
+ param_lengths,
+ param_formats,
+ 1);
if (PGRES_TUPLES_OK != PQresultStatus (result))
{
- fprintf (stderr, "Select failed: %s\n", PQresultErrorMessage (result));
+ fprintf (stderr,
+ "Select failed: %s\n",
+ PQresultErrorMessage (result));
return GNUNET_SYSERR;
}
if (0 == PQntuples (result))
{
struct GNUNET_TIME_AbsoluteNBO exnbo;
- exnbo = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add ( GNUNET_TIME_absolute_get (), GNUNET_TIME_UNIT_YEARS));
-
uint32_t value = htonl (denom.value);
uint32_t fraction = htonl (denom.fraction);
const void *param_values[] = {
@@ -77,33 +107,53 @@ reservemod_add (struct TALER_Amount denom)
&value,
&fraction,
denom.currency,
- &exnbo};
- int param_lengths[] = {32, 4, 4, strlen(denom.currency), 8};
- int param_formats[] = {1, 1, 1, 1, 1};
+ &exnbo
+ };
+ int param_lengths[] = {
+ sizeof (struct GNUNET_CRYPTO_EddsaPublicKey),
+ sizeof (uint32_t),
+ sizeof (uint32_t),
+ strlen (denom.currency),
+ sizeof (struct GNUNET_TIME_AbsoluteNBO)
+ };
+ int param_formats[] = {
+ 1, 1, 1, 1, 1
+ };
+
+ exnbo = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_YEARS));
result = PQexecParams (db_conn,
- "insert into reserves (reserve_pub, balance_value, balance_fraction, balance_currency, "
- " expiration_date )"
- "values ($1,$2,$3,$4,$5);",
- 5, NULL, (const char **) param_values, param_lengths, param_formats, 1);
+ "INSERT INTO reserves (reserve_pub, balance_value, balance_fraction, balance_currency, expiration_date)"
+ " VALUES ($1,$2,$3,$4,$5);",
+ 5,
+ NULL,
+ (const char **) param_values,
+ param_lengths,
+ param_formats,
+ 1);
if (PGRES_COMMAND_OK != PQresultStatus (result))
{
- fprintf (stderr, "Insert failed: %s\n", PQresultErrorMessage (result));
+ fprintf (stderr,
+ "Insert failed: %s\n",
+ PQresultErrorMessage (result));
return GNUNET_SYSERR;
}
}
else
{
- struct TALER_Amount old_denom;
- struct TALER_Amount new_denom;
- struct TALER_AmountNBO new_denom_nbo;
- int param_lengths[] = {4, 4, 32};
- int param_formats[] = {1, 1, 1};
const void *param_values[] = {
&new_denom_nbo.value,
&new_denom_nbo.fraction,
reserve_pub
};
+ int param_lengths[] = {
+ sizeof (new_denom_nbo.value),
+ sizeof (new_denom_nbo.fraction),
+ sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)
+ };
+ int param_formats[] = {
+ 1, 1, 1
+ };
GNUNET_assert (GNUNET_OK ==
TALER_DB_extract_amount (result, 0,
@@ -111,28 +161,38 @@ reservemod_add (struct TALER_Amount denom)
"balance_fraction",
"balance_currency",
&old_denom));
- new_denom = TALER_amount_add (old_denom, denom);
- new_denom_nbo = TALER_amount_hton (new_denom);
+ TALER_amount_add (&new_denom,
+ &old_denom,
+ &denom);
+ TALER_amount_hton (&new_denom_nbo,
+ &new_denom);
result = PQexecParams (db_conn,
- "UPDATE reserves "
- "SET balance_value = $1, balance_fraction = $2, "
- " status_sig = NULL, status_sign_pub = NULL "
- "WHERE reserve_pub = $3 ",
- 3, NULL, (const char **) param_values, param_lengths, param_formats, 1);
+ "UPDATE reserves"
+ " SET balance_value = $1, balance_fraction = $2, status_sig = NULL, status_sign_pub = NULL"
+ " WHERE reserve_pub = $3;",
+ 3,
+ NULL,
+ (const char **) param_values,
+ param_lengths,
+ param_formats,
+ 1);
if (PGRES_COMMAND_OK != PQresultStatus (result))
{
- fprintf (stderr, "Update failed: %s\n", PQresultErrorMessage (result));
+ fprintf (stderr,
+ "Update failed: %s\n",
+ PQresultErrorMessage (result));
return GNUNET_SYSERR;
}
-
- if (0 != strcmp ("1", PQcmdTuples (result)))
+ /* Yes, for historic reasons libpq returns a 'const char *'... */
+ if (0 != strcmp ("1",
+ PQcmdTuples (result)))
{
- fprintf (stderr, "Update failed (updated '%s' tupes instead of '1')\n",
+ fprintf (stderr,
+ "Update failed (updated `%s' tupes instead of '1')\n",
PQcmdTuples (result));
return GNUNET_SYSERR;
}
-
}
return GNUNET_OK;
}
@@ -151,7 +211,7 @@ main (int argc, char *const *argv)
static char *reserve_pub_str;
static char *add_str;
static const struct GNUNET_GETOPT_CommandLineOption options[] = {
- GNUNET_GETOPT_OPTION_HELP ("gnunet-mint-keyup OPTIONS"),
+ GNUNET_GETOPT_OPTION_HELP ("gnunet-mint-reservemod OPTIONS"),
{'d', "mint-dir", "DIR",
"mint directory with keys to update", 1,
&GNUNET_GETOPT_set_filename, &mintdir},
@@ -165,13 +225,19 @@ main (int argc, char *const *argv)
};
char *TALER_MINT_db_connection_cfg_str;
- GNUNET_assert (GNUNET_OK == GNUNET_log_setup ("taler-mint-keycheck", "WARNING", NULL));
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_log_setup ("taler-mint-reservemod",
+ "WARNING",
+ NULL));
- if (GNUNET_GETOPT_run ("taler-mint-keyup", options, argc, argv) < 0)
+ if (GNUNET_GETOPT_run ("taler-mint-reservemod",
+ options,
+ argc, argv) < 0)
return 1;
if (NULL == mintdir)
{
- fprintf (stderr, "mint directory not given\n");
+ fprintf (stderr,
+ "Mint directory not given\n");
return 1;
}
@@ -183,14 +249,15 @@ main (int argc, char *const *argv)
reserve_pub,
sizeof (struct GNUNET_CRYPTO_EddsaPublicKey))))
{
- fprintf (stderr, "reserve key invalid\n");
+ fprintf (stderr,
+ "Parsing reserve key invalid\n");
return 1;
}
-
cfg = TALER_config_load (mintdir);
if (NULL == cfg)
{
- fprintf (stderr, "can't load mint configuration\n");
+ fprintf (stderr,
+ "Failed to load mint configuration\n");
return 1;
}
if (GNUNET_OK !=
@@ -199,29 +266,40 @@ main (int argc, char *const *argv)
"db",
&TALER_MINT_db_connection_cfg_str))
{
- fprintf (stderr, "db configuration string not found\n");
- return 42;
+ fprintf (stderr,
+ "Database configuration string not found\n");
+ return 1;
}
db_conn = PQconnectdb (TALER_MINT_db_connection_cfg_str);
if (CONNECTION_OK != PQstatus (db_conn))
{
- fprintf (stderr, "db connection failed: %s\n", PQerrorMessage (db_conn));
+ fprintf (stderr,
+ "Database connection failed: %s\n",
+ PQerrorMessage (db_conn));
return 1;
}
-
if (NULL != add_str)
{
struct TALER_Amount add_value;
- if (GNUNET_OK != TALER_string_to_amount (add_str, &add_value))
+
+ if (GNUNET_OK !=
+ TALER_string_to_amount (add_str,
+ &add_value))
{
- fprintf (stderr, "could not read value\n");
+ fprintf (stderr,
+ "Failed to parse currency amount `%s'\n",
+ add_str);
return 1;
}
- if (GNUNET_OK != reservemod_add (add_value))
+ if (GNUNET_OK !=
+ reservemod_add (add_value))
{
- fprintf (stderr, "adding value failed\n");
+ fprintf (stderr,
+ "Failed to update reserve.\n");
return 1;
}
}
return 0;
}
+
+/* end taler-mint-reservemod.c */
diff --git a/src/mint/taler_mintdb_plugin.h b/src/mint/taler_mintdb_plugin.h
new file mode 100644
index 000000000..08a73479d
--- /dev/null
+++ b/src/mint/taler_mintdb_plugin.h
@@ -0,0 +1,1024 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014, 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/taler_mintdb_plugin.h
+ * @brief Low-level (statement-level) database access for the mint
+ * @author Florian Dold
+ * @author Christian Grothoff
+ */
+#ifndef TALER_MINTDB_PLUGIN_H
+#define TALER_MINTDB_PLUGIN_H
+
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_util.h"
+
+
+/**
+ * Information we keep on bank transfer(s) that established a reserve.
+ */
+struct BankTransfer
+{
+
+ /**
+ * Public key of the reserve that was filled.
+ */
+ struct TALER_ReservePublicKey reserve_pub;
+
+ /**
+ * Amount that was transferred to the mint.
+ */
+ struct TALER_Amount amount;
+
+ /**
+ * Detailed wire information about the transaction.
+ */
+ json_t *wire;
+
+};
+
+
+/**
+ * A summary of a Reserve
+ */
+struct Reserve
+{
+ /**
+ * The reserve's public key. This uniquely identifies the reserve
+ */
+ struct TALER_ReservePublicKey pub;
+
+ /**
+ * The balance amount existing in the reserve
+ */
+ struct TALER_Amount balance;
+
+ /**
+ * The expiration date of this reserve
+ */
+ struct GNUNET_TIME_Absolute expiry;
+};
+
+
+/**
+ * Information we keep for a withdrawn coin to reproduce
+ * the /withdraw operation if needed, and to have proof
+ * that a reserve was drained by this amount.
+ */
+struct CollectableBlindcoin
+{
+
+ /**
+ * Our signature over the (blinded) coin.
+ */
+ struct TALER_DenominationSignature sig;
+
+ /**
+ * Denomination key (which coin was generated).
+ * FIXME: we should probably instead have the
+ * AMOUNT *including* fee in what is being signed
+ * as well!
+ */
+ struct TALER_DenominationPublicKey denom_pub;
+
+ /**
+ * Public key of the reserve that was drained.
+ */
+ struct TALER_ReservePublicKey reserve_pub;
+
+ /**
+ * Hash over the blinded message, needed to verify
+ * the @e reserve_sig.
+ */
+ struct GNUNET_HashCode h_coin_envelope;
+
+ /**
+ * Signature confirming the withdrawl, matching @e reserve_pub,
+ * @e denom_pub and @e h_coin_envelope.
+ */
+ struct TALER_ReserveSignature reserve_sig;
+};
+
+
+
+/**
+ * Types of operations on a reserved.
+ */
+enum TALER_MINT_DB_ReserveOperation
+{
+ /**
+ * Money was deposited into the reserve via a bank transfer.
+ */
+ TALER_MINT_DB_RO_BANK_TO_MINT = 0,
+
+ /**
+ * A Coin was withdrawn from the reserve using /withdraw.
+ */
+ TALER_MINT_DB_RO_WITHDRAW_COIN = 1
+};
+
+
+/**
+ * Reserve history as a linked list. Lists all of the transactions
+ * associated with this reserve (such as the bank transfers that
+ * established the reserve and all /withdraw operations we have done
+ * since).
+ */
+struct ReserveHistory
+{
+
+ /**
+ * Next entry in the reserve history.
+ */
+ struct ReserveHistory *next;
+
+ /**
+ * Type of the event, determins @e details.
+ */
+ enum TALER_MINT_DB_ReserveOperation type;
+
+ /**
+ * Details of the operation, depending on @e type.
+ */
+ union
+ {
+
+ /**
+ * Details about a bank transfer to the mint.
+ */
+ struct BankTransfer *bank;
+
+ /**
+ * Details about a /withdraw operation.
+ */
+ struct CollectableBlindcoin *withdraw;
+
+ } details;
+
+};
+
+
+/**
+ * Specification for a /deposit operation.
+ */
+struct Deposit
+{
+ /**
+ * Information about the coin that is being deposited.
+ */
+ struct TALER_CoinPublicInfo coin;
+
+ /**
+ * ECDSA signature affirming that the customer intends
+ * this coin to be deposited at the merchant identified
+ * by @e h_wire in relation to the contract identified
+ * by @e h_contract.
+ */
+ struct TALER_CoinSpendSignature csig;
+
+ /**
+ * Public key of the merchant. Enables later identification
+ * of the merchant in case of a need to rollback transactions.
+ */
+ struct TALER_MerchantPublicKey merchant_pub;
+
+ /**
+ * Hash over the contract between merchant and customer
+ * (remains unknown to the Mint).
+ */
+ struct GNUNET_HashCode h_contract;
+
+ /**
+ * Hash of the (canonical) representation of @e wire, used
+ * to check the signature on the request. Generated by
+ * the mint from the detailed wire data provided by the
+ * merchant.
+ */
+ struct GNUNET_HashCode h_wire;
+
+ /**
+ * Detailed wire information for executing the transaction.
+ */
+ json_t *wire;
+
+ /**
+ * Merchant-generated transaction ID to detect duplicate
+ * transactions.
+ */
+ uint64_t transaction_id;
+
+ /**
+ * Fraction of the coin's remaining value to be deposited, including
+ * depositing fee (if any). The coin is identified by @e coin_pub.
+ */
+ struct TALER_Amount amount_with_fee;
+
+};
+
+
+/**
+ * Global information for a refreshing session. Includes
+ * dimensions of the operation, security parameters and
+ * client signatures from "/refresh/melt" and "/refresh/commit".
+ */
+struct RefreshSession
+{
+
+ /**
+ * Number of coins we are melting.
+ */
+ uint16_t num_oldcoins;
+
+ /**
+ * Number of new coins we are creating.
+ */
+ uint16_t num_newcoins;
+
+ /**
+ * Index (smaller #KAPPA) which the mint has chosen to not
+ * have revealed during cut and choose.
+ */
+ uint16_t noreveal_index;
+
+};
+
+
+/**
+ * Specification for coin in a /refresh/melt operation.
+ */
+struct RefreshMelt
+{
+ /**
+ * Information about the coin that is being melted.
+ */
+ struct TALER_CoinPublicInfo coin;
+
+ /**
+ * Signature over the melting operation.
+ */
+ struct TALER_CoinSpendSignature coin_sig;
+
+ /**
+ * Hash of the refresh session this coin is melted into.
+ */
+ struct GNUNET_HashCode session_hash;
+
+ /**
+ * How much value is being melted? This amount includes the fees,
+ * so the final amount contributed to the melt is this value minus
+ * the fee for melting the coin. We include the fee in what is
+ * being signed so that we can verify a reserve's remaining total
+ * balance without needing to access the respective denomination key
+ * information each time.
+ */
+ struct TALER_Amount amount_with_fee;
+
+};
+
+
+/**
+ * We have as many `struct RefreshCommitCoin` as there are new
+ * coins being created by the refresh (for each of the #KAPPA
+ * sets). These are the coins we ask the mint to sign if the
+ * respective set is selected.
+ */
+struct RefreshCommitCoin
+{
+
+ /**
+ * Encrypted data allowing those able to decrypt it to derive
+ * the private keys of the new coins created by the refresh.
+ */
+ struct TALER_RefreshLinkEncrypted *refresh_link;
+
+ /**
+ * Blinded message to be signed (in envelope), with @e coin_env_size bytes.
+ */
+ char *coin_ev;
+
+ /**
+ * Number of bytes in @e coin_ev.
+ */
+ size_t coin_ev_size;
+
+};
+
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * For each (old) coin being melted, we have a `struct
+ * RefreshCommitLink` that allows the user to find the shared secret
+ * to decrypt the respective refresh links for the new coins in the
+ * `struct RefreshCommitCoin`.
+ */
+struct RefreshCommitLink
+{
+ /**
+ * Transfer public key, used to decrypt the @e shared_secret_enc
+ * in combintation with the corresponding private key of the
+ * coin.
+ */
+ struct TALER_TransferPublicKey transfer_pub;
+
+ /**
+ * Encrypted shared secret to decrypt the link.
+ */
+ struct TALER_EncryptedLinkSecret shared_secret_enc;
+};
+
+GNUNET_NETWORK_STRUCT_END
+
+
+
+/**
+ * Linked list of refresh information linked to a coin.
+ */
+struct LinkDataList
+{
+ /**
+ * Information is stored in a NULL-terminated linked list.
+ */
+ struct LinkDataList *next;
+
+ /**
+ * Link data, used to recover the private key of the coin
+ * by the owner of the old coin.
+ */
+ struct TALER_RefreshLinkEncrypted *link_data_enc;
+
+ /**
+ * Denomination public key, determines the value of the coin.
+ */
+ struct TALER_DenominationPublicKey denom_pub;
+
+ /**
+ * Signature over the blinded envelope.
+ */
+ struct TALER_DenominationSignature ev_sig;
+};
+
+
+/**
+ * Specification for a /lock operation.
+ */
+struct Lock
+{
+ /**
+ * Information about the coin that is being locked.
+ */
+ struct TALER_CoinPublicInfo coin;
+
+ /**
+ * Signature over the locking operation.
+ */
+ struct TALER_CoinSpendSignature coin_sig;
+
+ /**
+ * How much value is being locked?
+ */
+ struct TALER_Amount amount;
+
+ // FIXME: more needed...
+};
+
+
+/**
+ * Enumeration to classify the different types of transactions
+ * that can be done with a coin.
+ */
+enum TALER_MINT_DB_TransactionType
+{
+ /**
+ * /deposit operation.
+ */
+ TALER_MINT_DB_TT_DEPOSIT = 0,
+
+ /**
+ * /refresh/melt operation.
+ */
+ TALER_MINT_DB_TT_REFRESH_MELT = 1,
+
+ /**
+ * /lock operation.
+ */
+ TALER_MINT_DB_TT_LOCK = 2
+};
+
+
+/**
+ * List of transactions we performed for a particular coin.
+ */
+struct TALER_MINT_DB_TransactionList
+{
+
+ /**
+ * Next pointer in the NULL-terminated linked list.
+ */
+ struct TALER_MINT_DB_TransactionList *next;
+
+ /**
+ * Type of the transaction, determines what is stored in @e details.
+ */
+ enum TALER_MINT_DB_TransactionType type;
+
+ /**
+ * Details about the transaction, depending on @e type.
+ */
+ union
+ {
+
+ /**
+ * Details if transaction was a /deposit operation.
+ */
+ struct Deposit *deposit;
+
+ /**
+ * Details if transaction was a /refresh/melt operation.
+ */
+ struct RefreshMelt *melt;
+
+ /**
+ * Details if transaction was a /lock operation.
+ */
+ struct Lock *lock;
+
+ } details;
+
+};
+
+
+/**
+ * Handle for a database session (per-thread, for transactions).
+ */
+struct TALER_MINTDB_Session;
+
+
+/**
+ * The plugin API, returned from the plugin's "init" function.
+ * The argument given to "init" is simply a configuration handle.
+ */
+struct TALER_MINTDB_Plugin
+{
+
+ /**
+ * Closure for all callbacks.
+ */
+ void *cls;
+
+ /**
+ * Get the thread-local database-handle.
+ * Connect to the db if the connection does not exist yet.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param temporary #GNUNET_YES to use a temporary schema; #GNUNET_NO to use the
+ * database default one
+ * @param the database connection, or NULL on error
+ */
+ struct TALER_MINTDB_Session *
+ (*get_session) (void *cls,
+ int temporary);
+
+
+ /**
+ * Drop the temporary taler schema. This is only useful for testcases.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
+ */
+ int
+ (*drop_temporary) (void *cls,
+ struct TALER_MINTDB_Session *db);
+
+
+ /**
+ * Create the necessary tables if they are not present
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param temporary should we use a temporary schema
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
+ */
+ int
+ (*create_tables) (void *cls,
+ int temporary);
+
+
+ /**
+ * Start a transaction.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion connection to use
+ * @return #GNUNET_OK on success
+ */
+ int
+ (*start) (void *cls,
+ struct TALER_MINTDB_Session *sesssion);
+
+
+ /**
+ * Commit a transaction.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion connection to use
+ * @return #GNUNET_OK on success
+ */
+ int
+ (*commit) (void *cls,
+ struct TALER_MINTDB_Session *sesssion);
+
+
+ /**
+ * Abort/rollback a transaction.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion connection to use
+ */
+ void
+ (*rollback) (void *cls,
+ struct TALER_MINTDB_Session *sesssion);
+
+
+ /**
+ * Get the summary of a reserve.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db the database connection handle
+ * @param reserve the reserve data. The public key of the reserve should be set
+ * in this structure; it is used to query the database. The balance
+ * and expiration are then filled accordingly.
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
+ */
+ int
+ (*reserve_get) (void *cls,
+ struct TALER_MINTDB_Session *db,
+ struct Reserve *reserve);
+
+ /* FIXME: add functions to add bank transfers to our DB
+ (and to test if we already did add one) (#3633/#3717) */
+
+
+ /**
+ * Insert a incoming transaction into reserves. New reserves are also created
+ * through this function.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param db the database connection handle
+ * @param reserve the reserve structure. The public key of the reserve should
+ * be set here. Upon successful execution of this function, the
+ * balance and expiration of the reserve will be updated.
+ * @param balance the amount that has to be added to the reserve
+ * @param expiry the new expiration time for the reserve
+ * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failures
+ */
+ int
+ (*reserves_in_insert) (void *cls,
+ struct TALER_MINTDB_Session *db,
+ struct Reserve *reserve,
+ const struct TALER_Amount *balance,
+ const struct GNUNET_TIME_Absolute expiry);
+
+
+ /**
+ * Locate the response for a /withdraw request under the
+ * key of the hash of the blinded message.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion database connection to use
+ * @param h_blind hash of the blinded message
+ * @param collectable corresponding collectable coin (blind signature)
+ * if a coin is found
+ * @return #GNUNET_SYSERR on internal error
+ * #GNUNET_NO if the collectable was not found
+ * #GNUNET_YES on success
+ */
+ int
+ (*get_collectable_blindcoin) (void *cls,
+ struct TALER_MINTDB_Session *sesssion,
+ const struct GNUNET_HashCode *h_blind,
+ struct CollectableBlindcoin *collectable);
+
+
+ /**
+ * Store collectable bit coin under the corresponding
+ * hash of the blinded message.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion database connection to use
+ * @param h_blind hash of the blinded message
+ * @param withdraw amount by which the reserve will be withdrawn with this
+ * transaction
+ * @param collectable corresponding collectable coin (blind signature)
+ * if a coin is found
+ * @return #GNUNET_SYSERR on internal error
+ * #GNUNET_NO if the collectable was not found
+ * #GNUNET_YES on success
+ */
+ int
+ (*insert_collectable_blindcoin) (void *cls,
+ struct TALER_MINTDB_Session *sesssion,
+ const struct GNUNET_HashCode *h_blind,
+ struct TALER_Amount withdraw,
+ const struct CollectableBlindcoin *collectable);
+
+
+ /**
+ * Get all of the transaction history associated with the specified
+ * reserve.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion connection to use
+ * @param reserve_pub public key of the reserve
+ * @return known transaction history (NULL if reserve is unknown)
+ */
+ struct ReserveHistory *
+ (*get_reserve_history) (void *cls,
+ struct TALER_MINTDB_Session *sesssion,
+ const struct TALER_ReservePublicKey *reserve_pub);
+
+
+ /**
+ * Free memory associated with the given reserve history.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param rh history to free.
+ */
+ void
+ (*free_reserve_history) (void *cls,
+ struct ReserveHistory *rh);
+
+
+ /**
+ * Check if we have the specified deposit already in the database.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @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 internal error
+ */
+ int
+ (*have_deposit) (void *cls,
+ struct TALER_MINTDB_Session *sesssion,
+ const struct Deposit *deposit);
+
+
+ /**
+ * Insert information about deposited coin into the
+ * database.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion connection to the database
+ * @param deposit deposit information to store
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+ int
+ (*insert_deposit) (void *cls,
+ struct TALER_MINTDB_Session *sesssion,
+ const struct Deposit *deposit);
+
+
+ /**
+ * Lookup refresh session data under the given @a session_hash.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion database handle to use
+ * @param session_hash hash over the melt to use for the lookup
+ * @param refresh_session[OUT] where to store the result
+ * @return #GNUNET_YES on success,
+ * #GNUNET_NO if not found,
+ * #GNUNET_SYSERR on DB failure
+ */
+ int
+ (*get_refresh_session) (void *cls,
+ struct TALER_MINTDB_Session *sesssion,
+ const struct GNUNET_HashCode *session_hash,
+ struct RefreshSession *refresh_session);
+
+
+ /**
+ * Store new refresh session data under the given @a session_hash.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion database handle to use
+ * @param session_hash hash over the melt to use to locate the session
+ * @param refresh_session session data to store
+ * @return #GNUNET_YES on success,
+ * #GNUNET_SYSERR on DB failure
+ */
+ int
+ (*create_refresh_session) (void *cls,
+ struct TALER_MINTDB_Session *sesssion,
+ const struct GNUNET_HashCode *session_hash,
+ const struct RefreshSession *refresh_session);
+
+
+ /**
+ * Store the given /refresh/melt request in the database.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion database connection
+ * @param oldcoin_index index of the coin to store
+ * @param melt coin melt operation details to store; includes
+ * the session hash of the melt
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on internal error
+ */
+ int
+ (*insert_refresh_melt) (void *cls,
+ struct TALER_MINTDB_Session *sesssion,
+ uint16_t oldcoin_index,
+ const struct RefreshMelt *melt);
+
+
+ /**
+ * Get information about melted coin details from the database.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion database connection
+ * @param session_hash hash to identify refresh session
+ * @param oldcoin_index index of the coin to retrieve
+ * @param melt melt data to fill in
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on internal error
+ */
+ int
+ (*get_refresh_melt) (void *cls,
+ struct TALER_MINTDB_Session *sesssion,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t oldcoin_index,
+ struct RefreshMelt *melt);
+
+
+ /**
+ * Store in the database which coin(s) we want to create
+ * in a given refresh operation.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion database connection
+ * @param session_hash hash to identify refresh session
+ * @param num_newcoins number of coins to generate, size of the @a denom_pubs array
+ * @param denom_pubs array denominations of the coins to create
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on internal error
+ */
+ int
+ (*insert_refresh_order) (void *cls,
+ struct TALER_MINTDB_Session *sesssion,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t num_newcoins,
+ const struct TALER_DenominationPublicKey *denom_pubs);
+
+
+ /**
+ * Lookup in the database for the @a num_newcoins coins that we want to
+ * create in the given refresh operation.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion database connection
+ * @param session_hash hash to identify refresh session
+ * @param num_newcoins size of the @a denom_pubs array
+ * @param denom_pubs[OUT] where to write @a num_newcoins denomination keys
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on internal error
+ */
+ int
+ (*get_refresh_order) (void *cls,
+ struct TALER_MINTDB_Session *sesssion,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t num_newcoins,
+ struct TALER_DenominationPublicKey *denom_pubs);
+
+
+ /**
+ * Store information about the commitments of the given index @a i
+ * for the given refresh session in the database.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion database connection to use
+ * @param session_hash hash to identify refresh session
+ * @param i set index (1st dimension), relating to #KAPPA
+ * @param num_newcoins coin index size of the @a commit_coins array
+ * @param commit_coin array of coin commitments to store
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on error
+ */
+ int
+ (*insert_refresh_commit_coins) (void *cls,
+ struct TALER_MINTDB_Session *sesssion,
+ const struct GNUNET_HashCode *session_hash,
+ unsigned int i,
+ unsigned int num_newcoins,
+ const struct RefreshCommitCoin *commit_coins);
+
+
+ /**
+ * Obtain information about the commitment of the
+ * given coin of the given refresh session from the database.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion database connection to use
+ * @param session_hash hash to identify refresh session
+ * @param i set index (1st dimension)
+ * @param num_coins size of the @a commit_coins array
+ * @param commit_coin[OUT] array of coin commitments to return
+ * @return #GNUNET_OK on success
+ * #GNUNET_NO if not found
+ * #GNUNET_SYSERR on error
+ */
+ int
+ (*get_refresh_commit_coins) (void *cls,
+ struct TALER_MINTDB_Session *sesssion,
+ const struct GNUNET_HashCode *session_hash,
+ unsigned int i,
+ unsigned int num_coins,
+ struct RefreshCommitCoin *commit_coins);
+
+
+ /**
+ * Store the commitment to the given (encrypted) refresh link data
+ * for the given refresh session.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion database connection to use
+ * @param session_hash hash to identify refresh session
+ * @param i set index (1st dimension), relating to #KAPPA
+ * @param num_links size of the @a commit_link array
+ * @param commit_links array of link information to store
+ * @return #GNUNET_SYSERR on internal error, #GNUNET_OK on success
+ */
+ int
+ (*insert_refresh_commit_links) (void *cls,
+ struct TALER_MINTDB_Session *sesssion,
+ const struct GNUNET_HashCode *session_hash,
+ unsigned int i,
+ unsigned int num_links,
+ const struct RefreshCommitLink *commit_links);
+
+ /**
+ * Obtain the commited (encrypted) refresh link data
+ * for the given refresh session.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion database connection to use
+ * @param session_hash hash to identify refresh session
+ * @param i set index (1st dimension)
+ * @param num_links size of the @links array to return
+ * @param links[OUT] array link information to return
+ * @return #GNUNET_SYSERR on internal error,
+ * #GNUNET_NO if commitment was not found
+ * #GNUNET_OK on success
+ */
+ int
+ (*get_refresh_commit_links) (void *cls,
+ struct TALER_MINTDB_Session *sesssion,
+ const struct GNUNET_HashCode *session_hash,
+ unsigned int i,
+ unsigned int num_links,
+ struct RefreshCommitLink *links);
+
+
+ /**
+ * Insert signature of a new coin generated during refresh into
+ * the database indexed by the refresh session and the index
+ * of the coin. This data is later used should an old coin
+ * be used to try to obtain the private keys during "/refresh/link".
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion database connection
+ * @param session_hash hash to identify refresh session
+ * @param newcoin_index coin index
+ * @param ev_sig coin signature
+ * @return #GNUNET_OK on success
+ */
+ int
+ (*insert_refresh_collectable) (void *cls,
+ struct TALER_MINTDB_Session *sesssion,
+ const struct GNUNET_HashCode *session_hash,
+ uint16_t newcoin_index,
+ const struct TALER_DenominationSignature *ev_sig);
+
+
+ /**
+ * Obtain the link data of a coin, that is the encrypted link
+ * information, the denomination keys and the signatures.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion database connection
+ * @param coin_pub public key to use to retrieve linkage data
+ * @return all known link data for the coin
+ */
+ struct LinkDataList *
+ (*get_link_data_list) (void *cls,
+ struct TALER_MINTDB_Session *sesssion,
+ const struct TALER_CoinSpendPublicKey *coin_pub);
+
+
+ /**
+ * Free memory of the link data list.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param ldl link data list to release
+ */
+ void
+ (*free_link_data_list) (void *cls,
+ struct LinkDataList *ldl);
+
+
+ /**
+ * Obtain shared secret and transfer public key from the public key of
+ * the coin. This information and the link information returned by
+ * #TALER_db_get_link() enable the owner of an old coin to determine
+ * the private keys of the new coins after the melt.
+ *
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion database connection
+ * @param coin_pub public key of the coin
+ * @param transfer_pub[OUT] public transfer key
+ * @param shared_secret_enc[OUT] set to shared secret
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO on failure (not found)
+ * #GNUNET_SYSERR on internal failure (database issue)
+ */
+ int
+ (*get_transfer) (void *cls,
+ struct TALER_MINTDB_Session *sesssion,
+ const struct TALER_CoinSpendPublicKey *coin_pub,
+ struct TALER_TransferPublicKey *transfer_pub,
+ struct TALER_EncryptedLinkSecret *shared_secret_enc);
+
+
+ /**
+ * Test if the given /lock request is known to us.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion database connection
+ * @param lock lock operation
+ * @return #GNUNET_YES if known,
+ * #GNUENT_NO if not,
+ * #GNUNET_SYSERR on internal error
+ */
+ int
+ (*have_lock) (void *cls,
+ struct TALER_MINTDB_Session *sesssion,
+ const struct Lock *lock);
+
+
+ /**
+ * Store the given /lock request in the database.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion database connection
+ * @param lock lock operation
+ * @return #GNUNET_OK on success
+ * #GNUNET_SYSERR on internal error
+ */
+ int
+ (*insert_lock) (void *cls,
+ struct TALER_MINTDB_Session *sesssion,
+ const struct Lock *lock);
+
+
+ /**
+ * Compile a list of all (historic) transactions performed
+ * with the given coin (/refresh/melt and /deposit operations).
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param sesssion database connection
+ * @param coin_pub coin to investigate
+ * @return list of transactions, NULL if coin is fresh
+ */
+ struct TALER_MINT_DB_TransactionList *
+ (*get_coin_transactions) (void *cls,
+ struct TALER_MINTDB_Session *sesssion,
+ const struct TALER_CoinSpendPublicKey *coin_pub);
+
+
+ /**
+ * Free linked list of transactions.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param list list to free
+ */
+ void
+ (*free_coin_transaction_list) (void *cls,
+ struct TALER_MINT_DB_TransactionList *list);
+
+
+};
+
+
+#endif /* _NEURO_MINT_DB_H */
diff --git a/src/mint/test_mint_common.c b/src/mint/test_mint_common.c
index aa72dfdcd..f6771474c 100644
--- a/src/mint/test_mint_common.c
+++ b/src/mint/test_mint_common.c
@@ -31,8 +31,10 @@
if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
} while (0)
+
int
-main (int argc, const char *const argv[])
+main (int argc,
+ const char *const argv[])
{
struct TALER_MINT_DenomKeyIssuePriv dki;
char *enc;
@@ -41,25 +43,26 @@ main (int argc, const char *const argv[])
char *enc_read;
size_t enc_read_size;
char *tmpfile;
-
int ret;
ret = 1;
enc = NULL;
enc_read = NULL;
tmpfile = NULL;
- dki.denom_priv = NULL;
- dki_read.denom_priv = NULL;
+ dki.denom_priv.rsa_private_key = NULL;
+ dki_read.denom_priv.rsa_private_key = NULL;
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
&dki.issue.signature,
sizeof (dki) - offsetof (struct TALER_MINT_DenomKeyIssue,
signature));
- dki.denom_priv = GNUNET_CRYPTO_rsa_private_key_create (RSA_KEY_SIZE);
- enc_size = GNUNET_CRYPTO_rsa_private_key_encode (dki.denom_priv, &enc);
+ dki.denom_priv.rsa_private_key
+ = GNUNET_CRYPTO_rsa_private_key_create (RSA_KEY_SIZE);
+ enc_size = GNUNET_CRYPTO_rsa_private_key_encode (dki.denom_priv.rsa_private_key,
+ &enc);
EXITIF (NULL == (tmpfile = GNUNET_DISK_mktemp ("test_mint_common")));
EXITIF (GNUNET_OK != TALER_MINT_write_denom_key (tmpfile, &dki));
EXITIF (GNUNET_OK != TALER_MINT_read_denom_key (tmpfile, &dki_read));
- enc_read_size = GNUNET_CRYPTO_rsa_private_key_encode (dki_read.denom_priv,
+ enc_read_size = GNUNET_CRYPTO_rsa_private_key_encode (dki_read.denom_priv.rsa_private_key,
&enc_read);
EXITIF (enc_size != enc_read_size);
EXITIF (0 != memcmp (enc,
@@ -75,9 +78,9 @@ main (int argc, const char *const argv[])
GNUNET_free (tmpfile);
}
GNUNET_free_non_null (enc_read);
- if (NULL != dki.denom_priv)
- GNUNET_CRYPTO_rsa_private_key_free (dki.denom_priv);
- if (NULL != dki_read.denom_priv)
- GNUNET_CRYPTO_rsa_private_key_free (dki_read.denom_priv);
+ if (NULL != dki.denom_priv.rsa_private_key)
+ GNUNET_CRYPTO_rsa_private_key_free (dki.denom_priv.rsa_private_key);
+ if (NULL != dki_read.denom_priv.rsa_private_key)
+ GNUNET_CRYPTO_rsa_private_key_free (dki_read.denom_priv.rsa_private_key);
return ret;
}
diff --git a/src/mint/test_mint_db.c b/src/mint/test_mint_db.c
index c18ad2e8e..0b61818f1 100644
--- a/src/mint/test_mint_db.c
+++ b/src/mint/test_mint_db.c
@@ -13,15 +13,13 @@
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/test_mint_db.c
* @brief test cases for DB interaction functions
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
*/
-
#include "platform.h"
-#include "mint_db.h"
+#include "plugin.h"
static int result;
@@ -45,7 +43,7 @@ static int result;
/**
* Checks if the given reserve has the given amount of balance and expiry
*
- * @param db the database connection
+ * @param session the database connection
* @param pub the public key of the reserve
* @param value balance value
* @param fraction balance fraction
@@ -54,16 +52,22 @@ static int result;
* @return #GNUNET_OK if the given reserve has the same balance and expiration
* as the given parameters; #GNUNET_SYSERR if not
*/
-int
-check_reserve (PGconn *db,
- struct GNUNET_CRYPTO_EddsaPublicKey *pub,
- uint32_t value, uint32_t fraction, const char *currency,
+static int
+check_reserve (struct TALER_MINTDB_Session *session,
+ const struct TALER_ReservePublicKey *pub,
+ uint32_t value,
+ uint32_t fraction,
+ const char *currency,
uint64_t expiry)
{
struct Reserve reserve;
- reserve.pub = pub;
- FAILIF (GNUNET_OK != TALER_MINT_DB_reserve_get (db, &reserve));
+ reserve.pub = *pub;
+
+ FAILIF (GNUNET_OK !=
+ plugin->reserve_get (plugin->cls,
+ session,
+ &reserve));
FAILIF (value != reserve.balance.value);
FAILIF (fraction != reserve.balance.fraction);
FAILIF (0 != strcmp (currency, reserve.balance.currency));
@@ -77,27 +81,30 @@ check_reserve (PGconn *db,
struct DenomKeyPair
{
- struct GNUNET_CRYPTO_rsa_PrivateKey *priv;
- struct GNUNET_CRYPTO_rsa_PublicKey *pub;
+ struct TALER_DenominationPrivateKey priv;
+ struct TALER_DenominationPublicKey pub;
};
-struct DenomKeyPair *
+
+static struct DenomKeyPair *
create_denom_key_pair (unsigned int size)
{
struct DenomKeyPair *dkp;
dkp = GNUNET_new (struct DenomKeyPair);
- dkp->priv = GNUNET_CRYPTO_rsa_private_key_create (size);
- GNUNET_assert (NULL != dkp->priv);
- dkp->pub = GNUNET_CRYPTO_rsa_private_key_get_public (dkp->priv);
+ dkp->priv.rsa_private_key = GNUNET_CRYPTO_rsa_private_key_create (size);
+ GNUNET_assert (NULL != dkp->priv.rsa_private_key);
+ dkp->pub.rsa_public_key
+ = GNUNET_CRYPTO_rsa_private_key_get_public (dkp->priv.rsa_private_key);
return dkp;
}
+
static void
destroy_denon_key_pair (struct DenomKeyPair *dkp)
{
- GNUNET_CRYPTO_rsa_public_key_free (dkp->pub);
- GNUNET_CRYPTO_rsa_private_key_free (dkp->priv);
+ GNUNET_CRYPTO_rsa_public_key_free (dkp->pub.rsa_public_key);
+ GNUNET_CRYPTO_rsa_private_key_free (dkp->priv.rsa_private_key);
GNUNET_free (dkp);
}
@@ -107,14 +114,16 @@ destroy_denon_key_pair (struct DenomKeyPair *dkp)
* @param cls closure
* @param args remaining command-line arguments
* @param cfgfile name of the configuration file used (for saving, can be NULL!)
- * @param config configuration
+ * @param cfg configuration
*/
static void
-run (void *cls, char *const *args, const char *cfgfile,
- const struct GNUNET_CONFIGURATION_Handle *config)
+run (void *cls,
+ char *const *args,
+ const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
{
- PGconn *db;
- struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
+ struct TALER_MINTDB_Session *session;
+ struct TALER_ReservePublicKey reserve_pub;
struct Reserve reserve;
struct GNUNET_TIME_Absolute expiry;
struct TALER_Amount amount;
@@ -126,81 +135,134 @@ run (void *cls, char *const *args, const char *cfgfile,
struct ReserveHistory *rh_head;
struct BankTransfer *bt;
struct CollectableBlindcoin *withdraw;
+ struct Deposit deposit;
+ struct Deposit deposit2;
+ struct json_t *wire;
+ const char * const json_wire_str =
+ "{ \"type\":\"SEPA\", \
+\"IBAN\":\"DE67830654080004822650\", \
+\"name\":\"GNUnet e.V.\", \
+\"bic\":\"GENODEF1SLR\", \
+\"edate\":\"1449930207000\", \
+\"r\":123456789, \
+\"address\": \"foobar\"}";
unsigned int cnt;
- db = NULL;
dkp = NULL;
rh = NULL;
+ wire = NULL;
ZR_BLK (&cbc);
ZR_BLK (&cbc2);
- if (GNUNET_OK != TALER_MINT_DB_init ("postgres:///taler"))
+ if (GNUNET_OK !=
+ TALER_MINT_plugin_load (cfg))
{
result = 1;
return;
}
- if (GNUNET_OK != TALER_MINT_DB_create_tables (GNUNET_YES))
+ if (GNUNET_OK !=
+ plugin->create_tables (plugin->cls,
+ GNUNET_YES))
{
result = 2;
goto drop;
}
- if (NULL == (db = TALER_MINT_DB_get_connection(GNUNET_YES)))
+ if (NULL ==
+ (session = plugin->get_session (plugin->cls,
+ GNUNET_YES)))
{
result = 3;
goto drop;
}
RND_BLK (&reserve_pub);
- reserve.pub = &reserve_pub;
+ reserve.pub = reserve_pub;
amount.value = 1;
amount.fraction = 1;
strcpy (amount.currency, CURRENCY);
expiry = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
GNUNET_TIME_UNIT_HOURS);
result = 4;
- FAILIF (GNUNET_OK != TALER_MINT_DB_reserves_in_insert (db,
- &reserve,
- amount,
- expiry));
- FAILIF (GNUNET_OK != check_reserve (db,
- &reserve_pub,
- amount.value,
- amount.fraction,
- amount.currency,
- expiry.abs_value_us));
- FAILIF (GNUNET_OK != TALER_MINT_DB_reserves_in_insert (db,
- &reserve,
- amount,
- expiry));
- FAILIF (GNUNET_OK != check_reserve (db,
- &reserve_pub,
- ++amount.value,
- ++amount.fraction,
- amount.currency,
- expiry.abs_value_us));
+ FAILIF (GNUNET_OK !=
+ plugin->reserves_in_insert (plugin->cls,
+ session,
+ &reserve,
+ &amount,
+ expiry));
+ FAILIF (GNUNET_OK !=
+ check_reserve (session,
+ &reserve_pub,
+ amount.value,
+ amount.fraction,
+ amount.currency,
+ expiry.abs_value_us));
+ FAILIF (GNUNET_OK !=
+ plugin->reserves_in_insert (plugin->cls,
+ session,
+ &reserve,
+ &amount,
+ expiry));
+ FAILIF (GNUNET_OK !=
+ check_reserve (session,
+ &reserve_pub,
+ ++amount.value,
+ ++amount.fraction,
+ amount.currency,
+ expiry.abs_value_us));
dkp = create_denom_key_pair (1024);
RND_BLK(&h_blind);
RND_BLK(&cbc.reserve_sig);
cbc.denom_pub = dkp->pub;
- cbc.sig = GNUNET_CRYPTO_rsa_sign (dkp->priv, &h_blind, sizeof (h_blind));
- (void) memcpy (&cbc.reserve_pub, &reserve_pub, sizeof (reserve_pub));
- FAILIF (GNUNET_OK != TALER_MINT_DB_insert_collectable_blindcoin (db,
- &h_blind,
- &cbc));
- FAILIF (GNUNET_YES != TALER_MINT_DB_get_collectable_blindcoin (db,
- &h_blind,
- &cbc2));
- FAILIF (NULL == cbc2.denom_pub);
- FAILIF (0 != memcmp (&cbc2.reserve_sig, &cbc.reserve_sig, sizeof (cbc2.reserve_sig)));
- FAILIF (0 != memcmp (&cbc2.reserve_pub, &cbc.reserve_pub, sizeof (cbc2.reserve_pub)));
- FAILIF (GNUNET_OK != GNUNET_CRYPTO_rsa_verify (&h_blind, cbc2.sig, dkp->pub));
- rh_head = rh = TALER_MINT_DB_get_reserve_history (db, &reserve_pub);
+ cbc.sig.rsa_signature
+ = GNUNET_CRYPTO_rsa_sign (dkp->priv.rsa_private_key,
+ &h_blind,
+ sizeof (h_blind));
+ (void) memcpy (&cbc.reserve_pub,
+ &reserve_pub,
+ sizeof (reserve_pub));
+ amount.value--;
+ amount.fraction--;
+ FAILIF (GNUNET_OK !=
+ plugin->insert_collectable_blindcoin (plugin->cls,
+ session,
+ &h_blind,
+ amount,
+ &cbc));
+ FAILIF (GNUNET_OK !=
+ check_reserve (session,
+ &reserve_pub,
+ amount.value,
+ amount.fraction,
+ amount.currency,
+ expiry.abs_value_us));
+ FAILIF (GNUNET_YES !=
+ plugin->get_collectable_blindcoin (plugin->cls,
+ session,
+ &h_blind,
+ &cbc2));
+ FAILIF (NULL == cbc2.denom_pub.rsa_public_key);
+ FAILIF (0 != memcmp (&cbc2.reserve_sig,
+ &cbc.reserve_sig,
+ sizeof (cbc2.reserve_sig)));
+ FAILIF (0 != memcmp (&cbc2.reserve_pub,
+ &cbc.reserve_pub,
+ sizeof (cbc2.reserve_pub)));
+ FAILIF (GNUNET_OK !=
+ GNUNET_CRYPTO_rsa_verify (&h_blind,
+ cbc2.sig.rsa_signature,
+ dkp->pub.rsa_public_key));
+ rh = plugin->get_reserve_history (plugin->cls,
+ session,
+ &reserve_pub);
FAILIF (NULL == rh);
+ rh_head = rh;
for (cnt=0; NULL != rh_head; rh_head=rh_head->next, cnt++)
{
switch (rh_head->type)
{
case TALER_MINT_DB_RO_BANK_TO_MINT:
bt = rh_head->details.bank;
- FAILIF (0 != memcmp (&bt->reserve_pub, &reserve_pub, sizeof (reserve_pub)));
+ FAILIF (0 != memcmp (&bt->reserve_pub,
+ &reserve_pub,
+ sizeof (reserve_pub)));
FAILIF (1 != bt->amount.value);
FAILIF (1 != bt->amount.fraction);
FAILIF (0 != strcmp (CURRENCY, bt->amount.currency));
@@ -217,28 +279,76 @@ run (void *cls, char *const *args, const char *cfgfile,
}
}
FAILIF (3 != cnt);
+ /* Tests for deposits */
+ RND_BLK (&deposit.coin.coin_pub);
+ deposit.coin.denom_pub = dkp->pub;
+ deposit.coin.denom_sig = cbc.sig;
+ RND_BLK (&deposit.csig);
+ RND_BLK (&deposit.merchant_pub);
+ RND_BLK (&deposit.h_contract);
+ RND_BLK (&deposit.h_wire);
+ wire = json_loads (json_wire_str, 0, NULL);
+ deposit.wire = wire;
+ deposit.transaction_id =
+ GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
+ deposit.amount_with_fee = amount;
+ FAILIF (GNUNET_OK !=
+ plugin->insert_deposit (plugin->cls,
+ session, &deposit));
+ FAILIF (GNUNET_YES !=
+ plugin->have_deposit (plugin->cls,
+ session,
+ &deposit));
+ (void) memcpy (&deposit2,
+ &deposit,
+ sizeof (deposit));
+ deposit2.transaction_id++; /* should fail if transaction id is different */
+ FAILIF (GNUNET_NO !=
+ plugin->have_deposit (plugin->cls,
+ session,
+ &deposit2));
+ deposit2.transaction_id = deposit.transaction_id;
+ RND_BLK (&deposit2.merchant_pub); /* should fail if merchant is different */
+ FAILIF (GNUNET_NO !=
+ plugin->have_deposit (plugin->cls,
+ session,
+ &deposit2));
+ (void) memcpy (&deposit2.merchant_pub,
+ &deposit.merchant_pub,
+ sizeof (deposit.merchant_pub));
+ RND_BLK (&deposit2.coin.coin_pub); /* should fail if coin is different */
+ FAILIF (GNUNET_NO !=
+ plugin->have_deposit (plugin->cls,
+ session,
+ &deposit2));
result = 0;
drop:
+ if (NULL != wire)
+ json_decref (wire);
if (NULL != rh)
- TALER_MINT_DB_free_reserve_history (rh);
+ plugin->free_reserve_history (plugin->cls,
+ rh);
rh = NULL;
- if (NULL != db)
- GNUNET_break (GNUNET_OK == TALER_MINT_DB_drop_temporary (db));
+ if (NULL != session)
+ GNUNET_break (GNUNET_OK ==
+ plugin->drop_temporary (plugin->cls,
+ session));
if (NULL != dkp)
destroy_denon_key_pair (dkp);
- if (NULL != cbc.sig)
- GNUNET_CRYPTO_rsa_signature_free (cbc.sig);
- if (NULL != cbc2.denom_pub)
- GNUNET_CRYPTO_rsa_public_key_free (cbc2.denom_pub);
- if (NULL != cbc2.sig)
- GNUNET_CRYPTO_rsa_signature_free (cbc2.sig);
+ if (NULL != cbc.sig.rsa_signature)
+ GNUNET_CRYPTO_rsa_signature_free (cbc.sig.rsa_signature);
+ if (NULL != cbc2.denom_pub.rsa_public_key)
+ GNUNET_CRYPTO_rsa_public_key_free (cbc2.denom_pub.rsa_public_key);
+ if (NULL != cbc2.sig.rsa_signature)
+ GNUNET_CRYPTO_rsa_signature_free (cbc2.sig.rsa_signature);
dkp = NULL;
}
int
-main (int argc, char *const argv[])
+main (int argc,
+ char *const argv[])
{
static const struct GNUNET_GETOPT_CommandLineOption options[] = {
GNUNET_GETOPT_OPTION_END
diff --git a/src/mint/test_mint_deposits.c b/src/mint/test_mint_deposits.c
index 5ad8006e8..4107c1aee 100644
--- a/src/mint/test_mint_deposits.c
+++ b/src/mint/test_mint_deposits.c
@@ -13,17 +13,15 @@
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/test_mint_deposits.c
* @brief testcase for mint deposits
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
*/
-
#include "platform.h"
#include <libpq-fe.h>
#include <gnunet/gnunet_util_lib.h>
-#include "mint_db.h"
+#include "plugin.h"
#include "db_pq.h"
#include "taler-mint-httpd.h"
@@ -44,11 +42,6 @@
/**
- * DB connection handle
- */
-static PGconn *conn;
-
-/**
* Should we not interact with a temporary table?
*/
static int persistent;
@@ -59,64 +52,19 @@ static int persistent;
static int result;
-int
-TALER_MINT_DB_init_deposits (PGconn *conn, int tmp)
-{
- const char *tmp_str = (1 == tmp) ? "TEMPORARY" : "";
- char *sql;
- PGresult *res;
- int ret;
-
- res = NULL;
- (void) GNUNET_asprintf (&sql,
- "CREATE %1$s TABLE IF NOT EXISTS deposits ("
- " coin_pub BYTEA NOT NULL PRIMARY KEY CHECK (length(coin_pub)=32)"
- ",denom_pub BYTEA NOT NULL CHECK (length(denom_pub)=32)"
- ",transaction_id INT8 NOT NULL"
- ",amount_value INT4 NOT NULL"
- ",amount_fraction INT4 NOT NULL"
- ",amount_currency VARCHAR(4) NOT NULL"
- ",merchant_pub BYTEA NOT NULL"
- ",h_contract BYTEA NOT NULL CHECK (length(h_contract)=64)"
- ",h_wire BYTEA NOT NULL CHECK (length(h_wire)=64)"
- ",coin_sig BYTEA NOT NULL CHECK (length(coin_sig)=64)"
- ",wire TEXT NOT NULL"
- ")",
- tmp_str);
- res = PQexec (conn, sql);
- GNUNET_free (sql);
- if (PGRES_COMMAND_OK != PQresultStatus (res))
- {
- break_db_err (res);
- ret = GNUNET_SYSERR;
- }
- else
- ret = GNUNET_OK;
- PQclear (res);
- return ret;
-}
-
-
-static void
-do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- if (NULL != conn)
- PQfinish (conn);
- conn = NULL;
-}
-
-
/**
* Main function that will be run by the scheduler.
*
* @param cls closure
* @param args remaining command-line arguments
* @param cfgfile name of the configuration file used (for saving, can be NULL!)
- * @param config configuration
+ * @param cfg configuration
*/
static void
-run (void *cls, char *const *args, const char *cfgfile,
- const struct GNUNET_CONFIGURATION_Handle *config)
+run (void *cls,
+ char *const *args,
+ const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
{
static const char wire[] = "{"
"\"type\":\"SEPA\","
@@ -126,13 +74,16 @@ run (void *cls, char *const *args, const char *cfgfile,
"}";
struct Deposit *deposit;
uint64_t transaction_id;
+ struct TALER_MINTDB_Session *session;
deposit = NULL;
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
- &do_shutdown, NULL);
- EXITIF (NULL == (conn = PQconnectdb(DB_URI)));
- EXITIF (GNUNET_OK != TALER_MINT_DB_init_deposits (conn, !persistent));
- EXITIF (GNUNET_OK != TALER_MINT_DB_prepare (conn));
+ EXITIF (GNUNET_OK != TALER_MINT_plugin_load (cfg));
+ EXITIF (GNUNET_OK !=
+ plugin->create_tables (plugin->cls,
+ ! persistent));
+ session = plugin->get_session (plugin->cls,
+ ! persistent);
+ EXITIF (NULL == session);
deposit = GNUNET_malloc (sizeof (struct Deposit) + sizeof (wire));
/* Makeup a random coin public key */
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
@@ -143,28 +94,33 @@ run (void *cls, char *const *args, const char *cfgfile,
UINT64_MAX);
deposit->transaction_id = GNUNET_htonll (transaction_id);
/* Random amount */
- deposit->amount.value =
+ deposit->amount_with_fee.value =
htonl (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX));
- deposit->amount.fraction =
+ deposit->amount_with_fee.fraction =
htonl (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX));
- GNUNET_assert (strlen (MINT_CURRENCY) < sizeof (deposit->amount.currency));
- strcpy (deposit->amount.currency, MINT_CURRENCY);
+ GNUNET_assert (strlen (MINT_CURRENCY) < sizeof (deposit->amount_with_fee.currency));
+ strcpy (deposit->amount_with_fee.currency, MINT_CURRENCY);
/* Copy wireformat */
deposit->wire = json_loads (wire, 0, NULL);
- EXITIF (GNUNET_OK != TALER_MINT_DB_insert_deposit (conn,
- deposit));
- EXITIF (GNUNET_OK != TALER_MINT_DB_have_deposit (conn,
- deposit));
+ EXITIF (GNUNET_OK !=
+ plugin->insert_deposit (plugin->cls,
+ session,
+ deposit));
+ EXITIF (GNUNET_OK !=
+ plugin->have_deposit (plugin->cls,
+ session,
+ deposit));
result = GNUNET_OK;
EXITIF_exit:
GNUNET_free_non_null (deposit);
- GNUNET_SCHEDULER_shutdown ();
return;
}
-int main(int argc, char *const argv[])
+int
+main (int argc,
+ char *const argv[])
{
static const struct GNUNET_GETOPT_CommandLineOption options[] = {
{'T', "persist", NULL,
diff --git a/src/pq/db_pq.c b/src/pq/db_pq.c
index bfa929c4e..bbcf002ee 100644
--- a/src/pq/db_pq.c
+++ b/src/pq/db_pq.c
@@ -181,13 +181,16 @@ TALER_DB_extract_amount_nbo (PGresult *result,
r_amount_nbo->value = *(uint32_t *) PQgetvalue (result, row, val_num);
r_amount_nbo->fraction = *(uint32_t *) PQgetvalue (result, row, frac_num);
- memset (r_amount_nbo->currency, 0, TALER_CURRENCY_LEN);
- // FIXME: overflow?
- len = PQgetlength (result, row, curr_num);
- len = GNUNET_MIN (TALER_CURRENCY_LEN, len);
- memcpy (r_amount_nbo->currency, PQgetvalue (result, row, curr_num), len);
- r_amount_nbo->currency[TALER_CURRENCY_LEN - 1] = '\0';
-
+ memset (r_amount_nbo->currency,
+ 0,
+ TALER_CURRENCY_LEN);
+ len = GNUNET_MIN (TALER_CURRENCY_LEN - 1,
+ PQgetlength (result, row, curr_num));
+ memcpy (r_amount_nbo->currency,
+ PQgetvalue (result,
+ row,
+ curr_num),
+ len);
return GNUNET_OK;
}
diff --git a/src/pq/db_pq.h b/src/pq/db_pq.h
index cb2020b96..720dad5c5 100644
--- a/src/pq/db_pq.h
+++ b/src/pq/db_pq.h
@@ -14,7 +14,7 @@
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file include/taler_db_lib.h
+ * @file pq/db_pq.h
* @brief helper functions for DB interactions
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
* @author Florian Dold
@@ -186,4 +186,4 @@ TALER_DB_extract_amount (PGresult *result,
#endif /* TALER_DB_LIB_H_ */
-/* end of include/taler_db_lib.h */
+/* end of db/db_pq.h */
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index a15d42ad8..07c120c50 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -8,7 +8,8 @@ libtalerutil_la_SOURCES = \
amount.c \
crypto.c \
util.c \
- json.c
+ json.c \
+ os_installation.c
libtalerutil_la_LIBADD = \
-lgnunetutil \
diff --git a/src/util/amount.c b/src/util/amount.c
index 9bdc0fd93..5e7f69fd9 100644
--- a/src/util/amount.c
+++ b/src/util/amount.c
@@ -30,10 +30,6 @@
#include "taler_util.h"
#include <gcrypt.h>
-#define AMOUNT_FRAC_BASE 1000000
-
-#define AMOUNT_FRAC_LEN 6
-
/**
* Parse money amount description, in the format "A:B.C".
@@ -47,148 +43,260 @@ int
TALER_string_to_amount (const char *str,
struct TALER_Amount *denom)
{
- unsigned int i; // pos in str
- int n; // number tmp
- unsigned int c; // currency pos
- uint32_t b; // base for suffix
-
- memset (denom, 0, sizeof (struct TALER_Amount));
-
- i = n = c = 0;
-
- while (isspace(str[i]))
- i++;
-
- if (0 == str[i])
+ size_t i;
+ int n;
+ uint32_t b;
+ const char *colon;
+ const char *value;
+
+ memset (denom,
+ 0,
+ sizeof (struct TALER_Amount));
+ /* skip leading whitespace */
+ while (isspace(str[0]))
+ str++;
+ if ('\0' == str[0])
{
- printf("null before currency\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Null before currency\n");
return GNUNET_SYSERR;
}
-
- while (str[i] != ':')
+ /* parse currency */
+ colon = strchr (str, (int) ':');
+ if ( (NULL == colon) ||
+ ((colon - str) >= TALER_CURRENCY_LEN) )
{
- if (0 == str[i])
- {
- printf("null before colon");
- return GNUNET_SYSERR;
- }
- if (c > 3)
- {
- printf("currency too long\n");
- return GNUNET_SYSERR;
- }
- denom->currency[c] = str[i];
- c++;
- i++;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Invalid currency specified before colon: `%s'",
+ str);
+ goto fail;
}
-
- // skip colon
- i++;
-
- if (0 == str[i])
+ memcpy (denom->currency,
+ str,
+ colon - str);
+ /* skip colon */
+ value = colon + 1;
+ if ('\0' == value[0])
{
- printf("null before value\n");
- return GNUNET_SYSERR;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Null before value\n");
+ goto fail;
}
- while (str[i] != '.')
+ /* parse value */
+ i = 0;
+ while ('.' != value[i])
{
- if (0 == str[i])
+ if ('\0' == value[i])
{
return GNUNET_OK;
}
+ if ( (str[i] < '0') || (str[i] > '9') )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Invalid character `%c'\n",
+ str[i]);
+ goto fail;
+ }
n = str[i] - '0';
- if (n < 0 || n > 9)
+ if (denom->value * 10 + n < denom->value)
{
- printf("invalid character '%c' before comma at %u\n", (char) n, i);
- return GNUNET_SYSERR;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Value too large\n");
+ goto fail;
}
denom->value = (denom->value * 10) + n;
i++;
}
- // skip the dot
+ /* skip the dot */
i++;
- if (0 == str[i])
+ /* parse fraction */
+ if ('\0' == str[i])
{
- printf("null after dot");
- return GNUNET_SYSERR;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Null after dot");
+ goto fail;
}
-
- b = 100000;
-
- while (0 != str[i])
+ b = TALER_AMOUNT_FRAC_BASE / 10;
+ while ('\0' != str[i])
{
- n = str[i] - '0';
- if (b == 0 || n < 0 || n > 9)
+ if (0 == b)
{
- printf("error after comma");
- return GNUNET_SYSERR;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Fractional value too small (only %u digits supported)",
+ (unsigned int) TALER_AMOUNT_FRAC_LEN);
+ goto fail;
+ }
+ if ( (str[i] < '0') || (str[i] > '9') )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Error after comma");
+ goto fail;
}
+ n = str[i] - '0';
denom->fraction += n * b;
b /= 10;
i++;
}
-
return GNUNET_OK;
+
+ fail:
+ /* set currency to 'invalid' to prevent accidental use */
+ memset (denom->currency,
+ 0,
+ TALER_CURRENCY_LEN);
+ return GNUNET_SYSERR;
}
/**
- * FIXME
+ * Convert amount from host to network representation.
+ *
+ * @param res where to store amount in network representation
+ * @param d amount in host representation
*/
-struct TALER_AmountNBO
-TALER_amount_hton (const struct TALER_Amount d)
+void
+TALER_amount_hton (struct TALER_AmountNBO *res,
+ const struct TALER_Amount *d)
{
- struct TALER_AmountNBO dn;
- dn.value = htonl (d.value);
- dn.fraction = htonl (d.fraction);
- memcpy (dn.currency, d.currency, TALER_CURRENCY_LEN);
+ res->value = GNUNET_htonll (d->value);
+ res->fraction = htonl (d->fraction);
+ memcpy (res->currency,
+ d->currency,
+ TALER_CURRENCY_LEN);
+}
+
- return dn;
+/**
+ * Convert amount from network to host representation.
+ *
+ * @param res where to store amount in host representation
+ * @param d amount in network representation
+ */
+void
+TALER_amount_ntoh (struct TALER_Amount *res,
+ const struct TALER_AmountNBO *dn)
+{
+ res->value = GNUNET_ntohll (dn->value);
+ res->fraction = ntohl (dn->fraction);
+ memcpy (res->currency,
+ dn->currency,
+ TALER_CURRENCY_LEN);
}
/**
- * FIXME
+ * Get the value of "zero" in a particular currency.
+ *
+ * @param cur currency description
+ * @param denom denomination to write the result to
+ * @return #GNUNET_OK if @a cur is a valid currency specification,
+ * #GNUNET_SYSERR if it is invalid.
*/
-struct TALER_Amount
-TALER_amount_ntoh (const struct TALER_AmountNBO dn)
+int
+TALER_amount_get_zero (const char *cur,
+ struct TALER_Amount *denom)
{
- struct TALER_Amount d;
- d.value = ntohl (dn.value);
- d.fraction = ntohl (dn.fraction);
- memcpy (d.currency, dn.currency, sizeof(dn.currency));
+ size_t slen;
- return d;
+ slen = strlen (cur);
+ if (slen >= TALER_CURRENCY_LEN)
+ return GNUNET_SYSERR;
+ memset (denom,
+ 0,
+ sizeof (struct TALER_Amount));
+ memcpy (denom->currency,
+ cur,
+ slen);
+ return GNUNET_OK;
}
/**
- * Compare the value/fraction of two amounts. Does not compare the currency,
- * i.e. comparing amounts with the same value and fraction but different
- * currency would return 0.
+ * Set @a a to "invalid".
+ *
+ * @param a amount to set to invalid
+ */
+static void
+invalidate (struct TALER_Amount *a)
+{
+ memset (a,
+ 0,
+ sizeof (struct TALER_Amount));
+}
+
+
+/**
+ * Test if @a a is valid
+ *
+ * @param a amount to test
+ * @return #GNUNET_YES if valid,
+ * #GNUNET_NO if invalid
+ */
+static int
+test_valid (const struct TALER_Amount *a)
+{
+ return ('\0' != a->currency[0]);
+}
+
+
+/**
+ * Test if @a a1 and @a a2 are the same currency.
+ *
+ * @param a1 amount to test
+ * @param a2 amount to test
+ * @return #GNUNET_YES if @a a1 and @a a2 are the same currency
+ * #GNUNET_NO if the currencies are different,
+ * #GNUNET_SYSERR if either amount is invalid
+ */
+int
+TALER_amount_cmp_currency (const struct TALER_Amount *a1,
+ const struct TALER_Amount *a2)
+{
+ if ( (GNUNET_NO == test_valid (a1)) ||
+ (GNUNET_NO == test_valid (a2)) )
+ return GNUNET_SYSERR;
+ if (0 == strcmp (a1->currency,
+ a2->currency))
+ return GNUNET_YES;
+ return GNUNET_NO;
+}
+
+
+/**
+ * Compare the value/fraction of two amounts. Does not compare the currency.
+ * Comparing amounts of different currencies will cause the program to abort().
+ * If unsure, check with #TALER_amount_cmp_currency() first to be sure that
+ * the currencies of the two amounts are identical.
*
* @param a1 first amount
* @param a2 second amount
* @return result of the comparison
*/
int
-TALER_amount_cmp (struct TALER_Amount a1,
- struct TALER_Amount a2)
+TALER_amount_cmp (const struct TALER_Amount *a1,
+ const struct TALER_Amount *a2)
{
- a1 = TALER_amount_normalize (a1);
- a2 = TALER_amount_normalize (a2);
- if (a1.value == a2.value)
+ struct TALER_Amount n1;
+ struct TALER_Amount n2;
+
+ GNUNET_assert (GNUNET_YES ==
+ TALER_amount_cmp_currency (a1, a2));
+ n1 = *a1;
+ n2 = *a2;
+ TALER_amount_normalize (&n1);
+ TALER_amount_normalize (&n2);
+ if (n1.value == n2.value)
{
- if (a1.fraction < a2.fraction)
+ if (n1.fraction < n2.fraction)
return -1;
- if (a1.fraction > a2.fraction)
+ if (n1.fraction > n2.fraction)
return 1;
return 0;
}
- if (a1.value < a2.value)
+ if (n1.value < n2.value)
return -1;
return 1;
}
@@ -197,108 +305,142 @@ TALER_amount_cmp (struct TALER_Amount a1,
/**
* Perform saturating subtraction of amounts.
*
+ * @param diff where to store (@a a1 - @a a2), or invalid if @a a2 > @a a1
* @param a1 amount to subtract from
* @param a2 amount to subtract
- * @return (a1-a2) or 0 if a2>=a1
+ * @return #GNUNET_OK if the subtraction worked,
+ * #GNUNET_NO if @a a1 = @a a2
+ * #GNUNET_SYSERR if @a a2 > @a a1 or currencies are incompatible;
+ * @a diff is set to invalid
*/
-struct TALER_Amount
-TALER_amount_subtract (struct TALER_Amount a1,
- struct TALER_Amount a2)
+int
+TALER_amount_subtract (struct TALER_Amount *diff,
+ const struct TALER_Amount *a1,
+ const struct TALER_Amount *a2)
{
- a1 = TALER_amount_normalize (a1);
- a2 = TALER_amount_normalize (a2);
+ struct TALER_Amount n1;
+ struct TALER_Amount n2;
- if (a1.value < a2.value)
+ if (GNUNET_YES !=
+ TALER_amount_cmp_currency (a1, a2))
{
- a1.value = 0;
- a1.fraction = 0;
- return a1;
+ invalidate (diff);
+ return GNUNET_SYSERR;
}
+ n1 = *a1;
+ n2 = *a2;
+ TALER_amount_normalize (&n1);
+ TALER_amount_normalize (&n2);
- if (a1.fraction < a2.fraction)
+ if (n1.fraction < n2.fraction)
{
- if (0 == a1.value)
+ if (0 == n1.value)
{
- a1.fraction = 0;
- return a1;
+ invalidate (diff);
+ return GNUNET_SYSERR;
}
- a1.fraction += AMOUNT_FRAC_BASE;
- a1.value -= 1;
+ n1.fraction += TALER_AMOUNT_FRAC_BASE;
+ n1.value--;
}
-
- a1.fraction -= a2.fraction;
- a1.value -= a2.value;
-
- return a1;
+ if (n1.value < n2.value)
+ {
+ invalidate (diff);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (a1->currency,
+ diff));
+ GNUNET_assert (n1.fraction >= n2.fraction);
+ diff->fraction = n1.fraction - n2.fraction;
+ GNUNET_assert (n1.value >= n2.value);
+ diff->value = n1.value - n2.value;
+ if ( (0 == diff->fraction) &&
+ (0 == diff->value) )
+ return GNUNET_NO;
+ return GNUNET_OK;
}
/**
- * Perform saturating addition of amounts.
+ * Perform addition of amounts.
*
+ * @param sum where to store @a a1 + @a a2, set to "invalid" on overflow
* @param a1 first amount to add
* @param a2 second amount to add
- * @return sum of a1 and a2
+ * @return #GNUNET_OK if the addition worked,
+ * #GNUNET_SYSERR on overflow
*/
-struct TALER_Amount
-TALER_amount_add (struct TALER_Amount a1,
- struct TALER_Amount a2)
+int
+TALER_amount_add (struct TALER_Amount *sum,
+ const struct TALER_Amount *a1,
+ const struct TALER_Amount *a2)
{
- a1 = TALER_amount_normalize (a1);
- a2 = TALER_amount_normalize (a2);
-
- a1.value += a2.value;
- a1.fraction += a2.fraction;
+ struct TALER_Amount n1;
+ struct TALER_Amount n2;
- if (0 == a1.currency[0])
+ if (GNUNET_YES !=
+ TALER_amount_cmp_currency (a1, a2))
{
- memcpy (a2.currency,
- a1.currency,
- TALER_CURRENCY_LEN);
+ invalidate (sum);
+ return GNUNET_SYSERR;
}
-
- if (0 == a2.currency[0])
+ n1 = *a1;
+ n2 = *a2;
+ TALER_amount_normalize (&n1);
+ TALER_amount_normalize (&n2);
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_get_zero (a1->currency,
+ sum));
+ sum->value = n1.value + n2.value;
+ if (sum->value < n1.value)
{
- memcpy (a1.currency,
- a2.currency,
- TALER_CURRENCY_LEN);
+ /* integer overflow */
+ invalidate (sum);
+ return GNUNET_SYSERR;
}
-
- if ( (0 != a1.currency[0]) &&
- (0 != memcmp (a1.currency,
- a2.currency,
- TALER_CURRENCY_LEN)) )
+ sum->fraction = n1.fraction + n2.fraction;
+ if (GNUNET_SYSERR ==
+ TALER_amount_normalize (sum))
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "adding mismatching currencies\n");
- }
-
- if (a1.value < a2.value)
- {
- a1.value = UINT32_MAX;
- a2.value = UINT32_MAX;
- return a1;
+ /* integer overflow via carry from fraction */
+ invalidate (sum);
+ return GNUNET_SYSERR;
}
-
- return TALER_amount_normalize (a1);
+ return GNUNET_OK;
}
/**
* Normalize the given amount.
*
- * @param amout amount to normalize
- * @return normalized amount
+ * @param amount amount to normalize
+ * @return #GNUNET_OK if normalization worked
+ * #GNUNET_NO if value was already normalized
+ * #GNUNET_SYSERR if value was invalid or could not be normalized
*/
-struct TALER_Amount
-TALER_amount_normalize (struct TALER_Amount amount)
+int
+TALER_amount_normalize (struct TALER_Amount *amount)
{
- while (amount.value != UINT32_MAX && amount.fraction >= AMOUNT_FRAC_BASE)
+ int ret;
+
+ if (GNUNET_YES != test_valid (amount))
+ return GNUNET_SYSERR;
+ ret = GNUNET_NO;
+ while ( (amount->value != UINT64_MAX) &&
+ (amount->fraction >= TALER_AMOUNT_FRAC_BASE) )
+ {
+ amount->fraction -= TALER_AMOUNT_FRAC_BASE;
+ amount->value++;
+ ret = GNUNET_OK;
+ }
+ if (amount->fraction >= TALER_AMOUNT_FRAC_BASE)
{
- amount.fraction -= AMOUNT_FRAC_BASE;
- amount.value += 1;
+ /* failed to normalize, adding up fractions caused
+ main value to overflow! */
+ return GNUNET_SYSERR;
}
- return amount;
+ return ret;
}
@@ -309,40 +451,40 @@ TALER_amount_normalize (struct TALER_Amount amount)
* @return freshly allocated string representation
*/
char *
-TALER_amount_to_string (struct TALER_Amount amount)
+TALER_amount_to_string (const struct TALER_Amount *amount)
{
- char tail[AMOUNT_FRAC_LEN + 1] = { 0 };
- char curr[TALER_CURRENCY_LEN + 1] = { 0 };
- char *result = NULL;
- int len;
-
- memcpy (curr, amount.currency, TALER_CURRENCY_LEN);
-
- amount = TALER_amount_normalize (amount);
- if (0 != amount.fraction)
+ char *result;
+ uint32_t n;
+ char tail[TALER_AMOUNT_FRAC_LEN + 1];
+ unsigned int i;
+ struct TALER_Amount norm;
+
+ if (GNUNET_YES != test_valid (amount))
+ return NULL;
+ norm = *amount;
+ GNUNET_break (GNUNET_SYSERR !=
+ TALER_amount_normalize (&norm));
+ if (0 != (n = norm.fraction))
{
- unsigned int i;
- uint32_t n = amount.fraction;
- for (i = 0; (i < AMOUNT_FRAC_LEN) && (n != 0); i++)
+ for (i = 0; (i < TALER_AMOUNT_FRAC_LEN) && (0 != n); i++)
{
- tail[i] = '0' + (n / (AMOUNT_FRAC_BASE / 10));
- n = (n * 10) % (AMOUNT_FRAC_BASE);
+ tail[i] = '0' + (n / (TALER_AMOUNT_FRAC_BASE / 10));
+ n = (n * 10) % (TALER_AMOUNT_FRAC_BASE);
}
- tail[i] = 0;
- len = GNUNET_asprintf (&result,
- "%s:%lu.%s",
- curr,
- (unsigned long) amount.value,
- tail);
+ tail[i] = '\0';
+ GNUNET_asprintf (&result,
+ "%s:%llu.%s",
+ norm.currency,
+ (unsigned long long) norm.value,
+ tail);
}
else
{
- len = GNUNET_asprintf (&result,
- "%s:%lu",
- curr,
- (unsigned long) amount.value);
+ GNUNET_asprintf (&result,
+ "%s:%llu",
+ norm.currency,
+ (unsigned long long) norm.value);
}
- GNUNET_assert (len > 0);
return result;
}
diff --git a/src/util/crypto.c b/src/util/crypto.c
index 5e75d674a..ffc12fed9 100644
--- a/src/util/crypto.c
+++ b/src/util/crypto.c
@@ -52,7 +52,8 @@ fatal_error_handler (void *cls,
void
TALER_gcrypt_init ()
{
- gcry_set_fatalerror_handler (&fatal_error_handler, NULL);
+ gcry_set_fatalerror_handler (&fatal_error_handler,
+ NULL);
TALER_assert_as (gcry_check_version (NEED_LIBGCRYPT_VERSION),
"libgcrypt version mismatch");
/* Disable secure memory. */
@@ -205,11 +206,11 @@ TALER_refresh_decrypt (const struct TALER_RefreshLinkEncrypted *input,
ret = GNUNET_new (struct TALER_RefreshLinkDecrypted);
memcpy (&ret->coin_priv,
buf,
- sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
- ret->blinding_key
+ sizeof (struct TALER_CoinSpendPrivateKey));
+ ret->blinding_key.rsa_blinding_key
= GNUNET_CRYPTO_rsa_blinding_key_decode (&buf[sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)],
input->blinding_key_enc_size);
- if (NULL == ret->blinding_key)
+ if (NULL == ret->blinding_key.rsa_blinding_key)
{
GNUNET_free (ret);
return NULL;
@@ -236,7 +237,7 @@ TALER_refresh_encrypt (const struct TALER_RefreshLinkDecrypted *input,
struct TALER_RefreshLinkEncrypted *ret;
derive_refresh_key (secret, &iv, &skey);
- b_buf_size = GNUNET_CRYPTO_rsa_blinding_key_encode (input->blinding_key,
+ b_buf_size = GNUNET_CRYPTO_rsa_blinding_key_encode (input->blinding_key.rsa_blinding_key,
&b_buf);
ret = GNUNET_malloc (sizeof (struct TALER_RefreshLinkEncrypted) +
b_buf_size);
@@ -308,14 +309,13 @@ TALER_test_coin_valid (const struct TALER_CoinPublicInfo *coin_public_info)
{
struct GNUNET_HashCode c_hash;
- /* FIXME: we had envisioned a more complex scheme... */
GNUNET_CRYPTO_hash (&coin_public_info->coin_pub,
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
&c_hash);
if (GNUNET_OK !=
GNUNET_CRYPTO_rsa_verify (&c_hash,
- coin_public_info->denom_sig,
- coin_public_info->denom_pub))
+ coin_public_info->denom_sig.rsa_signature,
+ coin_public_info->denom_pub.rsa_public_key))
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"coin signature is invalid\n");
diff --git a/src/util/json.c b/src/util/json.c
index a9d6dc5cc..7390eb474 100644
--- a/src/util/json.c
+++ b/src/util/json.c
@@ -48,14 +48,25 @@
* @return a json object describing the amount
*/
json_t *
-TALER_JSON_from_amount (struct TALER_Amount amount)
+TALER_JSON_from_amount (const struct TALER_Amount *amount)
{
json_t *j;
- j = json_pack ("{s: s, s:I, s:I}",
- "currency", amount.currency,
- "value", (json_int_t) amount.value,
- "fraction", (json_int_t) amount.fraction);
+ if ( (amount->value != (uint64_t) ((json_int_t) amount->value)) ||
+ (0 > ((json_int_t) amount->value)) )
+ {
+ /* Theoretically, json_int_t can be a 32-bit "long", or we might
+ have a 64-bit value which converted to a 63-bit signed long
+ long causes problems here. So we check. Note that depending
+ on the platform, the compiler may be able to statically tell
+ that at least the first check is always false. */
+ GNUNET_break (0);
+ return NULL;
+ }
+ j = json_pack ("{s:s, s:I, s:I}",
+ "currency", amount->currency,
+ "value", (json_int_t) amount->value,
+ "fraction", (json_int_t) amount->fraction);
GNUNET_assert (NULL != j);
return j;
}
@@ -151,6 +162,50 @@ TALER_JSON_from_ecdsa_sig (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpo
/**
+ * Convert RSA public key to JSON.
+ *
+ * @param pk public key to convert
+ * @return corresponding JSON encoding
+ */
+json_t *
+TALER_JSON_from_rsa_public_key (struct GNUNET_CRYPTO_rsa_PublicKey *pk)
+{
+ char *buf;
+ size_t buf_len;
+ json_t *ret;
+
+ buf_len = GNUNET_CRYPTO_rsa_public_key_encode (pk,
+ &buf);
+ ret = TALER_JSON_from_data (buf,
+ buf_len);
+ GNUNET_free (buf);
+ return ret;
+}
+
+
+/**
+ * Convert RSA signature to JSON.
+ *
+ * @param sig signature to convert
+ * @return corresponding JSON encoding
+ */
+json_t *
+TALER_JSON_from_rsa_signature (struct GNUNET_CRYPTO_rsa_Signature *sig)
+{
+ char *buf;
+ size_t buf_len;
+ json_t *ret;
+
+ buf_len = GNUNET_CRYPTO_rsa_signature_encode (sig,
+ &buf);
+ ret = TALER_JSON_from_data (buf,
+ buf_len);
+ GNUNET_free (buf);
+ return ret;
+}
+
+
+/**
* Convert binary data to a JSON string
* with the base32crockford encoding.
*
diff --git a/src/util/os_installation.c b/src/util/os_installation.c
new file mode 100644
index 000000000..82dc49180
--- /dev/null
+++ b/src/util/os_installation.c
@@ -0,0 +1,701 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2006-2014 Christian Grothoff (and other contributing authors)
+
+ GNUnet 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.
+
+ GNUnet 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 GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file os_installation.c
+ * @brief get paths used by the program; based heavily on the
+ * corresponding GNUnet file, just adapted for Taler.
+ * @author Milan
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#if DARWIN
+#include <mach-o/ldsyms.h>
+#include <mach-o/dyld.h>
+#elif WINDOWS
+#include <windows.h>
+#endif
+
+
+#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
+
+#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
+
+
+#if LINUX
+/**
+ * Try to determine path by reading /proc/PID/exe
+ *
+ * @return NULL on error
+ */
+static char *
+get_path_from_proc_maps ()
+{
+ char fn[64];
+ char line[1024];
+ char dir[1024];
+ FILE *f;
+ char *lgu;
+
+ GNUNET_snprintf (fn, sizeof (fn), "/proc/%u/maps", getpid ());
+ if (NULL == (f = FOPEN (fn, "r")))
+ return NULL;
+ while (NULL != fgets (line, sizeof (line), f))
+ {
+ if ((1 ==
+ SSCANF (line, "%*x-%*x %*c%*c%*c%*c %*x %*2x:%*2x %*u%*[ ]%1023s", dir)) &&
+ (NULL != (lgu = strstr (dir, "libtalerutil"))))
+ {
+ lgu[0] = '\0';
+ FCLOSE (f);
+ return GNUNET_strdup (dir);
+ }
+ }
+ FCLOSE (f);
+ return NULL;
+}
+
+
+/**
+ * Try to determine path by reading /proc/PID/exe
+ *
+ * @return NULL on error
+ */
+static char *
+get_path_from_proc_exe ()
+{
+ char fn[64];
+ char lnk[1024];
+ ssize_t size;
+
+ GNUNET_snprintf (fn, sizeof (fn), "/proc/%u/exe", getpid ());
+ size = readlink (fn, lnk, sizeof (lnk) - 1);
+ if (size <= 0)
+ {
+ LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "readlink", fn);
+ return NULL;
+ }
+ GNUNET_assert (size < sizeof (lnk));
+ lnk[size] = '\0';
+ while ((lnk[size] != '/') && (size > 0))
+ size--;
+ /* test for being in lib/taler/libexec/ or lib/MULTIARCH/taler/libexec */
+ if ( (size > strlen ("/taler/libexec/")) &&
+ (0 == strcmp ("/taler/libexec/",
+ &lnk[size - strlen ("/taler/libexec/")])) )
+ size -= strlen ("taler/libexec/");
+ if ((size < 4) || (lnk[size - 4] != '/'))
+ {
+ /* not installed in "/bin/" -- binary path probably useless */
+ return NULL;
+ }
+ lnk[size] = '\0';
+ return GNUNET_strdup (lnk);
+}
+#endif
+
+
+#if WINDOWS
+static HINSTANCE dll_instance;
+
+
+/**
+ * GNUNET_util_cl_init() in common_logging.c is preferred.
+ * This function is only for thread-local storage (not used in GNUnet)
+ * and hInstance saving.
+ */
+BOOL WINAPI
+DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ dll_instance = hinstDLL;
+ break;
+ case DLL_THREAD_ATTACH:
+ break;
+ case DLL_THREAD_DETACH:
+ break;
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
+
+/**
+ * Try to determine path with win32-specific function
+ *
+ * @return NULL on error
+ */
+static char *
+get_path_from_module_filename ()
+{
+ size_t pathlen = 512;
+ DWORD real_pathlen;
+ wchar_t *idx;
+ wchar_t *modulepath = NULL;
+ char *upath;
+ uint8_t *u8_string;
+ size_t u8_string_length;
+
+ /* This braindead function won't tell us how much space it needs, so
+ * we start at 1024 and double the space up if it doesn't fit, until
+ * it fits, or we exceed the threshold.
+ */
+ do
+ {
+ pathlen = pathlen * 2;
+ modulepath = GNUNET_realloc (modulepath, pathlen * sizeof (wchar_t));
+ SetLastError (0);
+ real_pathlen = GetModuleFileNameW (dll_instance, modulepath, pathlen * sizeof (wchar_t));
+ } while (real_pathlen >= pathlen && pathlen < 16*1024);
+ if (real_pathlen >= pathlen)
+ GNUNET_assert (0);
+ /* To be safe */
+ modulepath[real_pathlen] = '\0';
+
+ idx = modulepath + real_pathlen;
+ while ((idx > modulepath) && (*idx != L'\\') && (*idx != L'/'))
+ idx--;
+ *idx = L'\0';
+
+ /* Now modulepath holds full path to the directory where libtalerutil is.
+ * This directory should look like <TALER_PREFIX>/bin or <TALER_PREFIX>.
+ */
+ if (wcschr (modulepath, L'/') || wcschr (modulepath, L'\\'))
+ {
+ /* At least one directory component (i.e. we're not in a root directory) */
+ wchar_t *dirname = idx;
+ while ((dirname > modulepath) && (*dirname != L'\\') && (*dirname != L'/'))
+ dirname--;
+ *dirname = L'\0';
+ if (dirname > modulepath)
+ {
+ dirname++;
+ /* Now modulepath holds full path to the parent directory of the directory
+ * where libtalerutil is.
+ * dirname holds the name of the directory where libtalerutil is.
+ */
+ if (wcsicmp (dirname, L"bin") == 0)
+ {
+ /* pass */
+ }
+ else
+ {
+ /* Roll back our changes to modulepath */
+ dirname--;
+ *dirname = L'/';
+ }
+ }
+ }
+
+ /* modulepath is TALER_PREFIX */
+ u8_string = u16_to_u8 (modulepath, wcslen (modulepath), NULL, &u8_string_length);
+ if (NULL == u8_string)
+ GNUNET_assert (0);
+
+ upath = GNUNET_malloc (u8_string_length + 1);
+ memcpy (upath, u8_string, u8_string_length);
+ upath[u8_string_length] = '\0';
+
+ free (u8_string);
+ GNUNET_free (modulepath);
+
+ return upath;
+}
+#endif
+
+
+#if DARWIN
+/**
+ * Signature of the '_NSGetExecutablePath" function.
+ *
+ * @param buf where to write the path
+ * @param number of bytes available in 'buf'
+ * @return 0 on success, otherwise desired number of bytes is stored in 'bufsize'
+ */
+typedef int (*MyNSGetExecutablePathProto) (char *buf, size_t * bufsize);
+
+
+/**
+ * Try to obtain the path of our executable using '_NSGetExecutablePath'.
+ *
+ * @return NULL on error
+ */
+static char *
+get_path_from_NSGetExecutablePath ()
+{
+ static char zero = '\0';
+ char *path;
+ size_t len;
+ MyNSGetExecutablePathProto func;
+
+ path = NULL;
+ if (NULL == (func =
+ (MyNSGetExecutablePathProto) dlsym (RTLD_DEFAULT, "_NSGetExecutablePath")))
+ return NULL;
+ path = &zero;
+ len = 0;
+ /* get the path len, including the trailing \0 */
+ (void) func (path, &len);
+ if (0 == len)
+ return NULL;
+ path = GNUNET_malloc (len);
+ if (0 != func (path, &len))
+ {
+ GNUNET_free (path);
+ return NULL;
+ }
+ len = strlen (path);
+ while ((path[len] != '/') && (len > 0))
+ len--;
+ path[len] = '\0';
+ return path;
+}
+
+
+/**
+ * Try to obtain the path of our executable using '_dyld_image' API.
+ *
+ * @return NULL on error
+ */
+static char *
+get_path_from_dyld_image ()
+{
+ const char *path;
+ char *p;
+ char *s;
+ unsigned int i;
+ int c;
+
+ c = _dyld_image_count ();
+ for (i = 0; i < c; i++)
+ {
+ if (((const void *) _dyld_get_image_header (i)) != (const void *)&_mh_dylib_header)
+ continue;
+ path = _dyld_get_image_name (i);
+ if ( (NULL == path) || (0 == strlen (path)) )
+ continue;
+ p = GNUNET_strdup (path);
+ s = p + strlen (p);
+ while ((s > p) && ('/' != *s))
+ s--;
+ s++;
+ *s = '\0';
+ return p;
+ }
+ return NULL;
+}
+#endif
+
+
+/**
+ * Return the actual path to a file found in the current
+ * PATH environment variable.
+ *
+ * @param binary the name of the file to find
+ * @return path to binary, NULL if not found
+ */
+static char *
+get_path_from_PATH (const char *binary)
+{
+ char *path;
+ char *pos;
+ char *end;
+ char *buf;
+ const char *p;
+
+ if (NULL == (p = getenv ("PATH")))
+ return NULL;
+#if WINDOWS
+ /* On W32 look in CWD first. */
+ GNUNET_asprintf (&path, ".%c%s", PATH_SEPARATOR, p);
+#else
+ path = GNUNET_strdup (p); /* because we write on it */
+#endif
+ buf = GNUNET_malloc (strlen (path) + strlen (binary) + 1 + 1);
+ pos = path;
+ while (NULL != (end = strchr (pos, PATH_SEPARATOR)))
+ {
+ *end = '\0';
+ sprintf (buf, "%s/%s", pos, binary);
+ if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
+ {
+ pos = GNUNET_strdup (pos);
+ GNUNET_free (buf);
+ GNUNET_free (path);
+ return pos;
+ }
+ pos = end + 1;
+ }
+ sprintf (buf, "%s/%s", pos, binary);
+ if (GNUNET_YES == GNUNET_DISK_file_test (buf))
+ {
+ pos = GNUNET_strdup (pos);
+ GNUNET_free (buf);
+ GNUNET_free (path);
+ return pos;
+ }
+ GNUNET_free (buf);
+ GNUNET_free (path);
+ return NULL;
+}
+
+
+/**
+ * Try to obtain the installation path using the "TALER_PREFIX" environment
+ * variable.
+ *
+ * @return NULL on error (environment variable not set)
+ */
+static char *
+get_path_from_TALER_PREFIX ()
+{
+ const char *p;
+
+ if (NULL != (p = getenv ("TALER_PREFIX")))
+ return GNUNET_strdup (p);
+ return NULL;
+}
+
+
+/**
+ * @brief get the path to Taler bin/ or lib/, prefering the lib/ path
+ * @author Milan
+ *
+ * @return a pointer to the executable path, or NULL on error
+ */
+static char *
+os_get_taler_path ()
+{
+ char *ret;
+
+ if (NULL != (ret = get_path_from_TALER_PREFIX ()))
+ return ret;
+#if LINUX
+ if (NULL != (ret = get_path_from_proc_maps ()))
+ return ret;
+ /* try path *first*, before /proc/exe, as /proc/exe can be wrong */
+ if (NULL != (ret = get_path_from_PATH ("taler-mint-httpd")))
+ return ret;
+ if (NULL != (ret = get_path_from_proc_exe ()))
+ return ret;
+#endif
+#if WINDOWS
+ if (NULL != (ret = get_path_from_module_filename ()))
+ return ret;
+#endif
+#if DARWIN
+ if (NULL != (ret = get_path_from_dyld_image ()))
+ return ret;
+ if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
+ return ret;
+#endif
+ if (NULL != (ret = get_path_from_PATH ("taler-mint-httpd")))
+ return ret;
+ /* other attempts here */
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Could not determine installation path for %s. Set `%s' environment variable.\n"),
+ "Taler", "TALER_PREFIX");
+ return NULL;
+}
+
+
+/**
+ * @brief get the path to current app's bin/
+ * @author Milan
+ *
+ * @return a pointer to the executable path, or NULL on error
+ */
+static char *
+os_get_exec_path ()
+{
+ char *ret = NULL;
+
+#if LINUX
+ if (NULL != (ret = get_path_from_proc_exe ()))
+ return ret;
+#endif
+#if WINDOWS
+ if (NULL != (ret = get_path_from_module_filename ()))
+ return ret;
+#endif
+#if DARWIN
+ if (NULL != (ret = get_path_from_NSGetExecutablePath ()))
+ return ret;
+#endif
+ /* other attempts here */
+ return ret;
+}
+
+
+/**
+ * @brief get the path to a specific Taler installation directory or,
+ * with #TALER_OS_IPK_SELF_PREFIX, the current running apps installation directory
+ * @author Milan
+ * @return a pointer to the dir path (to be freed by the caller)
+ */
+char *
+TALER_OS_installation_get_path (enum GNUNET_OS_InstallationPathKind dirkind)
+{
+ size_t n;
+ const char *dirname;
+ char *execpath = NULL;
+ char *tmp;
+ char *multiarch;
+ char *libdir;
+ int isbasedir;
+
+ /* if wanted, try to get the current app's bin/ */
+ if (dirkind == GNUNET_OS_IPK_SELF_PREFIX)
+ execpath = os_get_exec_path ();
+
+ /* try to get Taler's bin/ or lib/, or if previous was unsuccessful some
+ * guess for the current app */
+ if (NULL == execpath)
+ execpath = os_get_taler_path ();
+
+ if (NULL == execpath)
+ return NULL;
+
+ n = strlen (execpath);
+ if (0 == n)
+ {
+ /* should never happen, but better safe than sorry */
+ GNUNET_free (execpath);
+ return NULL;
+ }
+ /* remove filename itself */
+ while ((n > 1) && (DIR_SEPARATOR == execpath[n - 1]))
+ execpath[--n] = '\0';
+
+ isbasedir = 1;
+ if ((n > 6) &&
+ ((0 == strcasecmp (&execpath[n - 6], "/lib32")) ||
+ (0 == strcasecmp (&execpath[n - 6], "/lib64"))))
+ {
+ if ( (GNUNET_OS_IPK_LIBDIR != dirkind) &&
+ (GNUNET_OS_IPK_LIBEXECDIR != dirkind) )
+ {
+ /* strip '/lib32' or '/lib64' */
+ execpath[n - 6] = '\0';
+ n -= 6;
+ }
+ else
+ isbasedir = 0;
+ }
+ else if ((n > 4) &&
+ ((0 == strcasecmp (&execpath[n - 4], "/bin")) ||
+ (0 == strcasecmp (&execpath[n - 4], "/lib"))))
+ {
+ /* strip '/bin' or '/lib' */
+ execpath[n - 4] = '\0';
+ n -= 4;
+ }
+ multiarch = NULL;
+ if (NULL != (libdir = strstr (execpath, "/lib/")))
+ {
+ /* test for multi-arch path of the form "PREFIX/lib/MULTIARCH/";
+ here we need to re-add 'multiarch' to lib and libexec paths later! */
+ multiarch = &libdir[5];
+ if (NULL == strchr (multiarch, '/'))
+ libdir[0] = '\0'; /* Debian multiarch format, cut of from 'execpath' but preserve in multicarch */
+ else
+ multiarch = NULL; /* maybe not, multiarch still has a '/', which is not OK */
+ }
+ /* in case this was a directory named foo-bin, remove "foo-" */
+ while ((n > 1) && (execpath[n - 1] == DIR_SEPARATOR))
+ execpath[--n] = '\0';
+ switch (dirkind)
+ {
+ case GNUNET_OS_IPK_PREFIX:
+ case GNUNET_OS_IPK_SELF_PREFIX:
+ dirname = DIR_SEPARATOR_STR;
+ break;
+ case GNUNET_OS_IPK_BINDIR:
+ dirname = DIR_SEPARATOR_STR "bin" DIR_SEPARATOR_STR;
+ break;
+ case GNUNET_OS_IPK_LIBDIR:
+ if (isbasedir)
+ {
+ GNUNET_asprintf (&tmp,
+ "%s%s%s%s%s",
+ execpath,
+ DIR_SEPARATOR_STR "lib",
+ (NULL != multiarch) ? DIR_SEPARATOR_STR : "",
+ (NULL != multiarch) ? multiarch : "",
+ DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR);
+ if (GNUNET_YES ==
+ GNUNET_DISK_directory_test (tmp, GNUNET_YES))
+ {
+ GNUNET_free (execpath);
+ return tmp;
+ }
+ GNUNET_free (tmp);
+ tmp = NULL;
+ if (4 == sizeof (void *))
+ {
+ dirname =
+ DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR;
+ GNUNET_asprintf (&tmp,
+ "%s%s",
+ execpath,
+ dirname);
+ }
+ if (8 == sizeof (void *))
+ {
+ dirname =
+ DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR;
+ GNUNET_asprintf (&tmp,
+ "%s%s",
+ execpath,
+ dirname);
+ }
+
+ if ( (NULL != tmp) &&
+ (GNUNET_YES ==
+ GNUNET_DISK_directory_test (tmp, GNUNET_YES)) )
+ {
+ GNUNET_free (execpath);
+ return tmp;
+ }
+ GNUNET_free (tmp);
+ }
+ dirname = DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR;
+ break;
+ case GNUNET_OS_IPK_DATADIR:
+ dirname =
+ DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR;
+ break;
+ case GNUNET_OS_IPK_LOCALEDIR:
+ dirname =
+ DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "locale" DIR_SEPARATOR_STR;
+ break;
+ case GNUNET_OS_IPK_ICONDIR:
+ dirname =
+ DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "icons" DIR_SEPARATOR_STR;
+ break;
+ case GNUNET_OS_IPK_DOCDIR:
+ dirname =
+ DIR_SEPARATOR_STR "share" DIR_SEPARATOR_STR "doc" DIR_SEPARATOR_STR \
+ "gnunet" DIR_SEPARATOR_STR;
+ break;
+ case GNUNET_OS_IPK_LIBEXECDIR:
+ if (isbasedir)
+ {
+ dirname =
+ DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR "libexec" DIR_SEPARATOR_STR;
+ GNUNET_asprintf (&tmp,
+ "%s%s%s%s",
+ execpath,
+ DIR_SEPARATOR_STR "lib" DIR_SEPARATOR_STR,
+ (NULL != multiarch) ? multiarch : "",
+ dirname);
+ if (GNUNET_YES ==
+ GNUNET_DISK_directory_test (tmp, GNUNET_YES))
+ {
+ GNUNET_free (execpath);
+ return tmp;
+ }
+ GNUNET_free (tmp);
+ tmp = NULL;
+ if (4 == sizeof (void *))
+ {
+ dirname =
+ DIR_SEPARATOR_STR "lib32" DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR \
+ "libexec" DIR_SEPARATOR_STR;
+ GNUNET_asprintf (&tmp,
+ "%s%s",
+ execpath,
+ dirname);
+ }
+ if (8 == sizeof (void *))
+ {
+ dirname =
+ DIR_SEPARATOR_STR "lib64" DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR \
+ "libexec" DIR_SEPARATOR_STR;
+ GNUNET_asprintf (&tmp,
+ "%s%s",
+ execpath,
+ dirname);
+ }
+ if ( (NULL != tmp) &&
+ (GNUNET_YES ==
+ GNUNET_DISK_directory_test (tmp, GNUNET_YES)) )
+ {
+ GNUNET_free (execpath);
+ return tmp;
+ }
+
+ GNUNET_free (tmp);
+ }
+ dirname =
+ DIR_SEPARATOR_STR "taler" DIR_SEPARATOR_STR \
+ "libexec" DIR_SEPARATOR_STR;
+ break;
+ default:
+ GNUNET_free (execpath);
+ return NULL;
+ }
+ GNUNET_asprintf (&tmp,
+ "%s%s",
+ execpath,
+ dirname);
+ GNUNET_free (execpath);
+ return tmp;
+}
+
+
+/**
+ * Given the name of a taler-helper, taler-service or taler-daemon
+ * binary, try to prefix it with the libexec/-directory to get the
+ * full path.
+ *
+ * @param progname name of the binary
+ * @return full path to the binary, if possible, otherwise copy of 'progname'
+ */
+char *
+TALER_OS_get_libexec_binary_path (const char *progname)
+{
+ static char *cache;
+ char *libexecdir;
+ char *binary;
+
+ if ( (DIR_SEPARATOR == progname[0]) ||
+ (GNUNET_YES == GNUNET_STRINGS_path_is_absolute (progname, GNUNET_NO, NULL, NULL)) )
+ return GNUNET_strdup (progname);
+ if (NULL != cache)
+ libexecdir = cache;
+ else
+ libexecdir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBEXECDIR);
+ if (NULL == libexecdir)
+ return GNUNET_strdup (progname);
+ GNUNET_asprintf (&binary,
+ "%s%s",
+ libexecdir,
+ progname);
+ cache = libexecdir;
+ return binary;
+}
+
+
+
+/* end of os_installation.c */
diff --git a/src/util/util.c b/src/util/util.c
index f2ff01d0f..5c1e5eb9a 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -29,6 +29,34 @@
#include <gcrypt.h>
+/**
+ * Obtain denomination amount from configuration file.
+ *
+ * @param section section of the configuration to access
+ * @param option option of the configuration to access
+ * @param denom[OUT] set to the amount found in configuration
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+int
+TALER_config_get_denom (struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *section,
+ const char *option,
+ struct TALER_Amount *denom)
+{
+ char *str;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ section,
+ option,
+ &str))
+ return GNUNET_NO;
+ if (GNUNET_OK != TALER_string_to_amount (str,
+ denom))
+ return GNUNET_SYSERR;
+ return GNUNET_OK;
+}
+
/**
* Load configuration by parsing all configuration