summaryrefslogtreecommitdiff
path: root/src/mint
diff options
context:
space:
mode:
Diffstat (limited to 'src/mint')
-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
31 files changed, 4598 insertions, 3258 deletions
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,