aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/auditor/taler-auditor.c2
-rw-r--r--src/exchange-tools/taler-exchange-keycheck.c5
-rw-r--r--src/exchange-tools/taler-exchange-keyup.c93
-rw-r--r--src/exchange/exchange.conf5
-rw-r--r--src/exchange/taler-exchange-httpd.c16
-rw-r--r--src/exchange/taler-exchange-httpd.h5
-rw-r--r--src/exchange/taler-exchange-httpd_keystate.c116
-rw-r--r--src/exchangedb/exchangedb_denomkeys.c256
-rw-r--r--src/exchangedb/test_exchangedb_denomkeys.c57
-rw-r--r--src/include/taler_exchangedb_lib.h55
-rw-r--r--src/include/taler_signatures.h2
-rw-r--r--src/lib/exchange_api_curl_defaults.c21
-rw-r--r--src/lib/exchange_api_handle.c5
13 files changed, 335 insertions, 303 deletions
diff --git a/src/auditor/taler-auditor.c b/src/auditor/taler-auditor.c
index d3afbb3d1..1b9c99c84 100644
--- a/src/auditor/taler-auditor.c
+++ b/src/auditor/taler-auditor.c
@@ -1148,7 +1148,7 @@ handle_payback_by_reserve (void *cls,
else
{
/* verify msig */
- struct TALER_MasterDenominationKeyRevocation kr;
+ struct TALER_MasterDenominationKeyRevocationPS kr;
kr.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED);
kr.purpose.size = htonl (sizeof (kr));
diff --git a/src/exchange-tools/taler-exchange-keycheck.c b/src/exchange-tools/taler-exchange-keycheck.c
index 74b73cd09..d58237738 100644
--- a/src/exchange-tools/taler-exchange-keycheck.c
+++ b/src/exchange-tools/taler-exchange-keycheck.c
@@ -120,7 +120,6 @@ exchange_signkeys_check ()
* @param cls closure (NULL)
* @param dki the denomination key
* @param alias coin alias
- * @param revocation_master_sig non-NULL if @a dki was revoked
* @return #GNUNET_OK to continue to iterate,
* #GNUNET_NO to stop iteration with no error,
* #GNUNET_SYSERR to abort iteration with error!
@@ -128,8 +127,7 @@ exchange_signkeys_check ()
static int
denomkeys_iter (void *cls,
const char *alias,
- const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki,
- const struct TALER_MasterSignatureP *revocation_master_sig)
+ const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki)
{
struct GNUNET_HashCode hc;
@@ -206,7 +204,6 @@ exchange_denomkeys_check ()
return GNUNET_NO;
}
if (0 > TALER_EXCHANGEDB_denomination_keys_iterate (exchange_directory,
- &master_public_key_from_cfg,
&denomkeys_iter,
NULL))
return GNUNET_NO;
diff --git a/src/exchange-tools/taler-exchange-keyup.c b/src/exchange-tools/taler-exchange-keyup.c
index cf774957f..f51ff961c 100644
--- a/src/exchange-tools/taler-exchange-keyup.c
+++ b/src/exchange-tools/taler-exchange-keyup.c
@@ -1112,73 +1112,6 @@ create_wire_fees ()
/**
- * Closure for functions processing a request to revoke a denomination
- * public key and request the wallets to initiate /payback.
- */
-struct RevokeClosure
-{
- /**
- * Hash of the denomination public key to revoke.
- */
- const struct GNUNET_HashCode *hc;
-
- /**
- * Base directory for keys.
- */
- char *basedir;
-
- /**
- * Set to #GNUNET_OK if we found a matching key,
- * Set to #GNUNET_SYSERR on error.
- */
- int ok;
-};
-
-
-
-/**
- * Revoke denomination keys matching the given hash.
- *
- * @param cls a `struct RevokeClosure` with information about what to revoke
- * @param dki the denomination key
- * @param alias coin alias
- * @param revocation_master_sig non-NULL if @a dki was revoked
- * @return #GNUNET_OK to continue to iterate,
- * #GNUNET_NO to stop iteration with no error,
- * #GNUNET_SYSERR to abort iteration with error!
- */
-static int
-exchange_keys_revoke_by_dki (void *cls,
- const char *alias,
- const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki,
- const struct TALER_MasterSignatureP *revocation_master_sig)
-{
- struct RevokeClosure *rc = cls;
-
- if (NULL != revocation_master_sig)
- return GNUNET_OK; /* refuse to do it twice */
- if (0 != memcmp (rc->hc,
- &dki->issue.properties.denom_hash,
- sizeof (struct GNUNET_HashCode)))
- return GNUNET_OK;
- rc->ok = GNUNET_OK;
- if (GNUNET_OK !=
- TALER_EXCHANGEDB_denomination_key_revoke (rc->basedir,
- alias,
- dki,
- &master_priv))
- {
- rc->ok = GNUNET_SYSERR;
- return GNUNET_SYSERR;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Successfully revoking denom '%s..'\n",
- TALER_B2S (rc->hc));
- return GNUNET_NO;
-}
-
-
-/**
* Revoke the denomination key matching @a hc and request /payback to be
* initiated.
*
@@ -1190,32 +1123,30 @@ exchange_keys_revoke_by_dki (void *cls,
static int
revoke_denomination (const struct GNUNET_HashCode *hc)
{
- struct RevokeClosure rc;
-
- rc.hc = hc;
- rc.ok = GNUNET_NO;
+ char *basedir;
+
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_filename (kcfg,
"exchange",
- "KEYDIR",
- &rc.basedir))
+ "REVOCATION_DIR",
+ &basedir))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"exchange",
- "KEYDIR");
+ "REVOCATION_DIR");
return GNUNET_SYSERR;
}
- if (-1 ==
- TALER_EXCHANGEDB_denomination_keys_iterate (rc.basedir,
- &master_public_key,
- &exchange_keys_revoke_by_dki,
- &rc))
+ if (GNUNET_OK !=
+ TALER_EXCHANGEDB_denomination_key_revoke (basedir,
+ hc,
+ &master_priv))
{
+ GNUNET_free (basedir);
GNUNET_break (0);
return GNUNET_SYSERR;
}
- GNUNET_free (rc.basedir);
- return rc.ok;
+ GNUNET_free (basedir);
+ return GNUNET_OK;
}
diff --git a/src/exchange/exchange.conf b/src/exchange/exchange.conf
index 5b9ff9be3..87b6f18c3 100644
--- a/src/exchange/exchange.conf
+++ b/src/exchange/exchange.conf
@@ -7,7 +7,12 @@
# in respective subdirectories.)
KEYDIR = ${TALER_DATA_HOME}/exchange/live-keys/
+# Directory where the exchange expects to find revocation
+# certificates (and where taler-exchange-keyup will write them).
+REVOCATION_DIR = ${TALER_DATA_HOME}/exchange/revocations/
+
# Master public key used to sign the exchange's various keys
+# This must be adjusted to your actually installation.
# MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
# How to access our database
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
index eb0ddb415..4813f9215 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -70,6 +70,11 @@ int TEH_exchange_connection_close;
char *TEH_exchange_directory;
/**
+ * Directory where revocations are stored (global)
+ */
+char *TEH_revocation_directory;
+
+/**
* The exchange's configuration (global)
*/
struct GNUNET_CONFIGURATION_Handle *cfg;
@@ -524,6 +529,17 @@ exchange_serve_process_config ()
return GNUNET_SYSERR;
}
if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ "exchange",
+ "REVOCATION_DIR",
+ &TEH_revocation_directory))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "REVOCATION_DIR");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
"taler",
"CURRENCY",
diff --git a/src/exchange/taler-exchange-httpd.h b/src/exchange/taler-exchange-httpd.h
index 69da3c243..ef380e8c4 100644
--- a/src/exchange/taler-exchange-httpd.h
+++ b/src/exchange/taler-exchange-httpd.h
@@ -49,6 +49,11 @@ extern struct GNUNET_CONFIGURATION_Handle *cfg;
extern char *TEH_exchange_directory;
/**
+ * Main directory with revocation data.
+ */
+extern char *TEH_revocation_directory;
+
+/**
* Master public key (according to the
* configuration in the exchange directory).
*/
diff --git a/src/exchange/taler-exchange-httpd_keystate.c b/src/exchange/taler-exchange-httpd_keystate.c
index 10bff8269..36f464ba8 100644
--- a/src/exchange/taler-exchange-httpd_keystate.c
+++ b/src/exchange/taler-exchange-httpd_keystate.c
@@ -677,7 +677,6 @@ add_denomination_transaction (void *cls,
* @param cls closure with a `struct ResponseFactoryContext *`
* @param dki the denomination key issue
* @param alias coin alias
- * @param revocation_master_sig non-NULL if @a dki was revoked
* @return #GNUNET_OK to continue to iterate,
* #GNUNET_NO to stop iteration with no error,
* #GNUNET_SYSERR to abort iteration with error!
@@ -685,8 +684,7 @@ add_denomination_transaction (void *cls,
static int
reload_keys_denom_iter (void *cls,
const char *alias,
- const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki,
- const struct TALER_MasterSignatureP *revocation_master_sig)
+ const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki)
{
struct ResponseFactoryContext *rfc = cls;
struct TEH_KS_StateHandle *key_state = rfc->key_state;
@@ -719,40 +717,6 @@ reload_keys_denom_iter (void *cls,
return GNUNET_OK;
}
- if (NULL != revocation_master_sig)
- {
- struct AddRevocationContext arc;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Adding denomination key `%s' (%s) to revocation set\n",
- alias,
- GNUNET_h2s (&dki->issue.properties.denom_hash));
- res = store_in_map (key_state->revoked_map,
- dki);
- if (GNUNET_NO == res)
- return GNUNET_OK;
- /* Try to insert DKI into DB until we succeed; note that if the DB
- failure is persistent, we need to die, as we cannot continue
- without the DKI being in the DB). */
- arc.dki = dki;
- arc.revocation_master_sig = revocation_master_sig;
- if (GNUNET_OK !=
- TEH_DB_run_transaction (NULL,
- "add denomination key revocations",
- NULL,
- &add_revocations_transaction,
- &arc))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Giving up, this is fatal. Committing suicide via SIGTERM.\n");
- handle_signal (SIGTERM);
- return GNUNET_SYSERR;
- }
- GNUNET_assert (0 ==
- json_array_append_new (rfc->payback_array,
- GNUNET_JSON_from_data_auto (&dki->issue.properties.denom_hash)));
- return GNUNET_OK;
- }
horizon = GNUNET_TIME_relative_to_absolute (TALER_EXCHANGE_conf_duration_provide ());
start = GNUNET_TIME_absolute_ntoh (dki->issue.properties.start);
if (start.abs_value_us > horizon.abs_value_us)
@@ -794,6 +758,67 @@ reload_keys_denom_iter (void *cls,
/**
+ * Iterator for revocation of denomination keys.
+ *
+ * @param cls closure with a `struct ResponseFactoryContext *`
+ * @param denom_hash hash of revoked denomination public key
+ * @param revocation_master_sig signature showing @a denom_hash was revoked
+ * @return #GNUNET_OK to continue to iterate,
+ * #GNUNET_NO to stop iteration with no error,
+ * #GNUNET_SYSERR to abort iteration with error!
+ */
+static int
+revocations_iter (void *cls,
+ const struct GNUNET_HashCode *denom_hash,
+ const struct TALER_MasterSignatureP *revocation_master_sig)
+{
+ struct ResponseFactoryContext *rfc = cls;
+ struct TEH_KS_StateHandle *key_state = rfc->key_state;
+ int res;
+ struct AddRevocationContext arc;
+ const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Adding denomination key `%s' to revocation set\n",
+ GNUNET_h2s (denom_hash));
+ dki = GNUNET_CONTAINER_multihashmap_get (key_state->denomkey_map,
+ denom_hash);
+ if (NULL == dki)
+ {
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (key_state->denomkey_map,
+ denom_hash,
+ dki));
+ res = store_in_map (key_state->revoked_map,
+ dki);
+ if (GNUNET_NO == res)
+ return GNUNET_OK;
+ }
+ /* Try to insert DKI into DB until we succeed; note that if the DB
+ failure is persistent, we need to die, as we cannot continue
+ without the DKI being in the DB). */
+ arc.dki = dki;
+ arc.revocation_master_sig = revocation_master_sig;
+ if (GNUNET_OK !=
+ TEH_DB_run_transaction (NULL,
+ "add denomination key revocations",
+ NULL,
+ &add_revocations_transaction,
+ &arc))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Giving up, this is fatal. Committing suicide via SIGTERM.\n");
+ handle_signal (SIGTERM);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_assert (0 ==
+ json_array_append_new (rfc->payback_array,
+ GNUNET_JSON_from_data_auto (denom_hash)));
+ return GNUNET_OK;
+}
+
+
+/**
* Convert the public part of a sign key issue to a JSON object.
*
* @param ski the sign key issue
@@ -1527,7 +1552,6 @@ make_fresh_key_state ()
'rfc.payback_array' */
if (-1 ==
TALER_EXCHANGEDB_denomination_keys_iterate (TEH_exchange_directory,
- &TEH_master_public_key,
&reload_keys_denom_iter,
&rfc))
{
@@ -1540,6 +1564,22 @@ make_fresh_key_state ()
json_decref (rfc.sign_keys_array);
return NULL;
}
+
+ if (-1 ==
+ TALER_EXCHANGEDB_revocations_iterate (TEH_revocation_directory,
+ &TEH_master_public_key,
+ &revocations_iter,
+ &rfc))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to load denomination keys from `%s'.\n",
+ TEH_exchange_directory);
+ key_state->refcnt = 1;
+ ks_release (key_state);
+ json_decref (rfc.payback_array);
+ json_decref (rfc.sign_keys_array);
+ return NULL;
+ }
if (0 == GNUNET_CONTAINER_multihashmap_size (key_state->denomkey_map))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
diff --git a/src/exchangedb/exchangedb_denomkeys.c b/src/exchangedb/exchangedb_denomkeys.c
index 400912168..9dfb0e855 100644
--- a/src/exchangedb/exchangedb_denomkeys.c
+++ b/src/exchangedb/exchangedb_denomkeys.c
@@ -25,66 +25,70 @@
#include "taler_exchangedb_lib.h"
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Contents of a file with a revocation certificate.
+ */
+struct RevocationFileP
+{
+
+ /**
+ * Hash of the denomination public key being revoked.
+ */
+ struct GNUNET_HashCode denom_hash;
+
+ /**
+ * Master signature over the revocation, must match purpose
+ * #TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED.
+ */
+ struct TALER_MasterSignatureP msig;
+};
+
+GNUNET_NETWORK_STRUCT_END
+
+
/**
* Mark the given denomination key as revoked and request the wallets
* to initiate /payback.
*
- * @param exchange_base_dir base directory for the exchange,
- * the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS
- * subdirectory
- * @param alias coin alias
- * @param dki the denomination key to revoke
- * @param mpriv master private key to sign
+ * @param revocation_dir where to write the revocation certificate
+ * @param denom_hash hash of the denomination key to revoke
+ * @param mpriv master private key to sign with
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure.
*/
int
-TALER_EXCHANGEDB_denomination_key_revoke (const char *exchange_base_dir,
- const char *alias,
- const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki,
+TALER_EXCHANGEDB_denomination_key_revoke (const char *revocation_dir,
+ const struct GNUNET_HashCode *denom_hash,
const struct TALER_MasterPrivateKeyP *mpriv)
{
- struct GNUNET_TIME_Absolute start;
- struct TALER_MasterDenominationKeyRevocation rm;
- struct TALER_MasterSignatureP msig;
+ struct TALER_MasterDenominationKeyRevocationPS rm;
char *fn;
- struct GNUNET_DISK_FileHandle *fh;
- ssize_t wrote;
int ret;
+ struct RevocationFileP rd;
ret = GNUNET_SYSERR;
- start = GNUNET_TIME_absolute_ntoh (dki->issue.properties.start);
GNUNET_asprintf (&fn,
- "%s" DIR_SEPARATOR_STR
- TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS DIR_SEPARATOR_STR
- "%s" DIR_SEPARATOR_STR
- "%llu.rev",
- exchange_base_dir,
- alias,
- (unsigned long long) start.abs_value_us);
-
+ "%s" DIR_SEPARATOR_STR
+ "%s.rev",
+ revocation_dir,
+ GNUNET_h2s_full (denom_hash));
rm.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED);
rm.purpose.size = htonl (sizeof (rm));
- rm.h_denom_pub = dki->issue.properties.denom_hash;
+ rm.h_denom_pub = *denom_hash;
GNUNET_assert (GNUNET_OK ==
GNUNET_CRYPTO_eddsa_sign (&mpriv->eddsa_priv,
&rm.purpose,
- &msig.eddsa_signature));
- if (NULL == (fh = GNUNET_DISK_file_open
- (fn,
- GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_TRUNCATE,
- GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)))
- goto cleanup;
- if (GNUNET_SYSERR ==
- (wrote = GNUNET_DISK_file_write (fh,
- &msig,
- sizeof (msig))))
- goto cleanup;
- if (wrote != sizeof (msig))
- goto cleanup;
- ret = GNUNET_OK;
-cleanup:
- if (NULL != fh)
- (void) GNUNET_DISK_file_close (fh);
+ &rd.msig.eddsa_signature));
+ rd.denom_hash = *denom_hash;
+ if (sizeof (rd) !=
+ GNUNET_DISK_fn_write (fn,
+ &rd,
+ sizeof (rd),
+ GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE))
+ ret = GNUNET_SYSERR;
+ else
+ ret = GNUNET_OK;
GNUNET_free (fn);
return ret;
}
@@ -229,11 +233,6 @@ struct DenomkeysIterateContext
const char *alias;
/**
- * Master public key to use to validate revocations.
- */
- const struct TALER_MasterPublicKeyP *master_pub;
-
- /**
* Function to call on each denomination key.
*/
TALER_EXCHANGEDB_DenominationKeyIterator it;
@@ -263,16 +262,6 @@ denomkeys_iterate_keydir_iter (void *cls,
struct DenomkeysIterateContext *dic = cls;
struct TALER_EXCHANGEDB_DenominationKeyIssueInformation issue;
int ret;
- char *rev;
- struct TALER_MasterSignatureP msig;
- struct TALER_MasterDenominationKeyRevocation rm;
- const struct TALER_MasterSignatureP *revoked;
-
- /* FIXME: #5536: should move .rev files into DB! */
- if ( (strlen(filename) > strlen (".rev")) &&
- (0 == strcmp (&filename[strlen(filename) - strlen (".rev")],
- ".rev")) )
- return GNUNET_OK; /* ignore revocation files _here_; we'll try for them just below */
memset (&issue, 0, sizeof (issue));
if (GNUNET_OK !=
@@ -284,52 +273,9 @@ denomkeys_iterate_keydir_iter (void *cls,
filename);
return GNUNET_OK;
}
- /* check for revocation file */
- GNUNET_asprintf (&rev,
- "%s.rev",
- filename);
- revoked = NULL;
- if (GNUNET_YES == GNUNET_DISK_file_test (rev))
- {
- /* Check if revocation is valid... */
- if (sizeof (msig) !=
- GNUNET_DISK_fn_read (rev,
- &msig,
- sizeof (msig)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Invalid revocation file `%s' found and ignored (bad size)\n"),
- rev);
- }
- else
- {
- rm.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED);
- rm.purpose.size = htonl (sizeof (rm));
- rm.h_denom_pub = issue.issue.properties.denom_hash;
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED,
- &rm.purpose,
- &msig.eddsa_signature,
- &dic->master_pub->eddsa_pub))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Invalid revocation file `%s' found and ignored (bad signature)\n"),
- rev);
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Denomination key `%s' was revoked!\n",
- filename);
- revoked = &msig;
- }
- }
- }
- GNUNET_free (rev);
ret = dic->it (dic->it_cls,
dic->alias,
- &issue,
- revoked);
+ &issue);
GNUNET_CRYPTO_rsa_private_key_free (issue.denom_priv.rsa_private_key);
GNUNET_CRYPTO_rsa_public_key_free (issue.denom_pub.rsa_public_key);
return ret;
@@ -367,7 +313,6 @@ denomkeys_iterate_topdir_iter (void *cls,
* @param exchange_base_dir base directory for the exchange,
* the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS
* subdirectory
- * @param master_pub master public key (used to check revocations)
* @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
@@ -377,7 +322,6 @@ denomkeys_iterate_topdir_iter (void *cls,
*/
int
TALER_EXCHANGEDB_denomination_keys_iterate (const char *exchange_base_dir,
- const struct TALER_MasterPublicKeyP *master_pub,
TALER_EXCHANGEDB_DenominationKeyIterator it,
void *it_cls)
{
@@ -388,7 +332,6 @@ TALER_EXCHANGEDB_denomination_keys_iterate (const char *exchange_base_dir,
GNUNET_asprintf (&dir,
"%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS,
exchange_base_dir);
- dic.master_pub = master_pub;
dic.it = it;
dic.it_cls = it_cls;
ret = GNUNET_DISK_directory_scan (dir,
@@ -399,4 +342,111 @@ TALER_EXCHANGEDB_denomination_keys_iterate (const char *exchange_base_dir,
}
+/**
+ * Closure for #revocations_iterate_cb().
+ */
+struct RevocationsIterateContext
+{
+
+ /**
+ * Function to call on each revoked denomination key.
+ */
+ TALER_EXCHANGEDB_RevocationIterator it;
+
+ /**
+ * Closure for @e it.
+ */
+ void *it_cls;
+
+ /**
+ * Master public key to use to validate revocations.
+ */
+ const struct TALER_MasterPublicKeyP *master_pub;
+
+};
+
+
+/**
+ * Decode the revocation certificate in the given file @a filename and call
+ * the callback in @a cls with the information.
+ *
+ * @param cls the `struct RevocationsIterateContext *`
+ * @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
+revocations_iterate_cb (void *cls,
+ const char *filename)
+{
+ struct RevocationsIterateContext *ric = cls;
+ struct RevocationFileP rf;
+ struct TALER_MasterDenominationKeyRevocationPS rm;
+
+ /* Check if revocation is valid... */
+ if (sizeof (rm) !=
+ GNUNET_DISK_fn_read (filename,
+ &rf,
+ sizeof (rf)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Invalid revocation file `%s' found and ignored (bad size)\n"),
+ filename);
+ return GNUNET_OK;
+ }
+ rm.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED);
+ rm.purpose.size = htonl (sizeof (rm));
+ rm.h_denom_pub = rf.denom_hash;
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED,
+ &rm.purpose,
+ &rf.msig.eddsa_signature,
+ &ric->master_pub->eddsa_pub))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Invalid revocation file `%s' found and ignored (bad signature)\n"),
+ filename);
+ return GNUNET_OK;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Denomination key `%s' was revoked!\n",
+ GNUNET_h2s (&rm.h_denom_pub));
+ return ric->it (ric->it_cls,
+ &rm.h_denom_pub,
+ &rf.msig);
+}
+
+
+/**
+ * Call @a it for each revoked denomination key found in the @a revocation_dir.
+ *
+ * @param revocation_dir base directory where revocations are stored
+ * @param master_pub master public key (used to check revocations)
+ * @param it function to call on each revoked 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_EXCHANGEDB_revocations_iterate (const char *revocation_dir,
+ const struct TALER_MasterPublicKeyP *master_pub,
+ TALER_EXCHANGEDB_RevocationIterator it,
+ void *it_cls)
+{
+ struct RevocationsIterateContext ric = {
+ .it = it,
+ .it_cls = it_cls,
+ .master_pub = master_pub
+ };
+
+ return GNUNET_DISK_directory_scan (revocation_dir,
+ &revocations_iterate_cb,
+ &ric);
+}
+
+
/* end of exchangedb_denomkeys.c */
diff --git a/src/exchangedb/test_exchangedb_denomkeys.c b/src/exchangedb/test_exchangedb_denomkeys.c
index 06465a4ea..b558b3b3b 100644
--- a/src/exchangedb/test_exchangedb_denomkeys.c
+++ b/src/exchangedb/test_exchangedb_denomkeys.c
@@ -38,7 +38,6 @@
* @param cls closure with expected DKI
* @param dki the denomination key
* @param alias coin alias
- * @param revocation_master_sig non-NULL if @a dki was revoked
* @return #GNUNET_OK to continue to iterate,
* #GNUNET_NO to stop iteration with no error,
* #GNUNET_SYSERR to abort iteration with error!
@@ -46,16 +45,10 @@
static int
dki_iter (void *cls,
const char *alias,
- const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki,
- const struct TALER_MasterSignatureP *revocation_master_sig)
+ const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki)
{
const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *exp = cls;
- if (NULL != revocation_master_sig)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
if (0 != memcmp (&exp->issue,
&dki->issue,
sizeof (struct TALER_EXCHANGEDB_DenominationKeyInformationP)))
@@ -85,8 +78,7 @@ dki_iter (void *cls,
* @brief Iterator called on revoked denomination key.
*
* @param cls closure with expected DKI
- * @param dki the denomination key
- * @param alias coin alias
+ * @param denom_hash hash of the revoked denomination key
* @param revocation_master_sig non-NULL if @a dki was revoked
* @return #GNUNET_OK to continue to iterate,
* #GNUNET_NO to stop iteration with no error,
@@ -94,8 +86,7 @@ dki_iter (void *cls,
*/
static int
dki_iter_revoked (void *cls,
- const char *alias,
- const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki,
+ const struct GNUNET_HashCode *denom_hash,
const struct TALER_MasterSignatureP *revocation_master_sig)
{
const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *exp = cls;
@@ -105,28 +96,13 @@ dki_iter_revoked (void *cls,
GNUNET_break (0);
return GNUNET_SYSERR;
}
- if (0 != memcmp (&exp->issue,
- &dki->issue,
- sizeof (struct TALER_EXCHANGEDB_DenominationKeyInformationP)))
+ if (0 != memcmp (denom_hash,
+ &exp->issue.properties.denom_hash,
+ sizeof (struct GNUNET_HashCode)))
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
- if (0 !=
- GNUNET_CRYPTO_rsa_private_key_cmp (exp->denom_priv.rsa_private_key,
- dki->denom_priv.rsa_private_key))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- if (0 !=
- GNUNET_CRYPTO_rsa_public_key_cmp (exp->denom_pub.rsa_public_key,
- dki->denom_pub.rsa_public_key))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
-
return GNUNET_OK;
}
@@ -146,6 +122,7 @@ main (int argc,
size_t enc_read_size;
char *tmpfile;
char *tmpdir;
+ char *revdir;
int ret;
struct GNUNET_TIME_Absolute start;
@@ -180,6 +157,10 @@ main (int argc,
TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS,
"cur-unit-uuid",
(unsigned long long) start.abs_value_us);
+ GNUNET_asprintf (&revdir,
+ "%s/revocations/",
+ tmpdir,
+ TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS);
EXITIF (GNUNET_OK !=
TALER_EXCHANGEDB_denomination_key_write (tmpfile,
&dki));
@@ -188,21 +169,19 @@ main (int argc,
&dki_read));
EXITIF (1 !=
TALER_EXCHANGEDB_denomination_keys_iterate (tmpdir,
- &master_pub,
&dki_iter,
&dki));
EXITIF (GNUNET_OK !=
- TALER_EXCHANGEDB_denomination_key_revoke (tmpdir,
- "cur-unit-uuid",
- &dki,
+ TALER_EXCHANGEDB_denomination_key_revoke (revdir,
+ &dki.issue.properties.denom_hash,
&master_priv));
EXITIF (1 !=
- TALER_EXCHANGEDB_denomination_keys_iterate (tmpdir,
- &master_pub,
- &dki_iter_revoked,
- &dki));
-
+ TALER_EXCHANGEDB_revocations_iterate (revdir,
+ &master_pub,
+ &dki_iter_revoked,
+ &dki));
+ GNUNET_free (revdir);
enc_read_size = GNUNET_CRYPTO_rsa_private_key_encode (dki_read.denom_priv.rsa_private_key,
&enc_read);
diff --git a/src/include/taler_exchangedb_lib.h b/src/include/taler_exchangedb_lib.h
index f942c5fbb..0d06c1881 100644
--- a/src/include/taler_exchangedb_lib.h
+++ b/src/include/taler_exchangedb_lib.h
@@ -169,7 +169,6 @@ TALER_EXCHANGEDB_signing_key_write (const char *exchange_base_dir,
* @param cls closure
* @param alias coin alias
* @param dki the denomination key
- * @param revocation_master_sig non-NULL if @a dki was revoked
* @return #GNUNET_OK to continue to iterate,
* #GNUNET_NO to stop iteration with no error,
* #GNUNET_SYSERR to abort iteration with error!
@@ -177,8 +176,23 @@ TALER_EXCHANGEDB_signing_key_write (const char *exchange_base_dir,
typedef int
(*TALER_EXCHANGEDB_DenominationKeyIterator)(void *cls,
const char *alias,
- const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki,
- const struct TALER_MasterSignatureP *revocation_master_sig);
+ const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki);
+
+
+/**
+ * @brief Iterator over revoked denomination keys.
+ *
+ * @param cls closure
+ * @param denom_hash hash of the denomination public key
+ * @param revocation_master_sig signature showing @a denom_hash was revoked
+ * @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_EXCHANGEDB_RevocationIterator)(void *cls,
+ const struct GNUNET_HashCode *denom_hash,
+ const struct TALER_MasterSignatureP *revocation_master_sig);
/**
@@ -187,7 +201,6 @@ typedef int
* @param exchange_base_dir base directory for the exchange,
* the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS
* subdirectory
- * @param master_pub master public key (used to check revocations)
* @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
@@ -197,27 +210,41 @@ typedef int
*/
int
TALER_EXCHANGEDB_denomination_keys_iterate (const char *exchange_base_dir,
- const struct TALER_MasterPublicKeyP *master_pub,
TALER_EXCHANGEDB_DenominationKeyIterator it,
void *it_cls);
/**
+ * Call @a it for each revoked denomination key found in the @a revocation_dir.
+ *
+ * @param revocation_dir base directory where revocations are stored
+ * @param master_pub master public key (used to check revocations)
+ * @param it function to call on each revoked 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_EXCHANGEDB_revocations_iterate (const char *revocation_dir,
+ const struct TALER_MasterPublicKeyP *master_pub,
+ TALER_EXCHANGEDB_RevocationIterator it,
+ void *it_cls);
+
+
+/**
* Mark the given denomination key as revoked and request the wallets
* to initiate /payback.
*
- * @param exchange_base_dir base directory for the exchange,
- * the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS
- * subdirectory
- * @param alias coin alias
- * @param dki the denomination key to revoke
- * @param mpriv master private key to sign
+ * @param revocation_dir where to write the revocation certificate
+ * @param denom_hash hash of the denomination key to revoke
+ * @param mpriv master private key to sign with
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure.
*/
int
-TALER_EXCHANGEDB_denomination_key_revoke (const char *exchange_base_dir,
- const char *alias,
- const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki,
+TALER_EXCHANGEDB_denomination_key_revoke (const char *revocation_dir,
+ const struct GNUNET_HashCode *denom_hash,
const struct TALER_MasterPrivateKeyP *mpriv);
diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h
index 512198fe8..5472ad01f 100644
--- a/src/include/taler_signatures.h
+++ b/src/include/taler_signatures.h
@@ -943,7 +943,7 @@ struct TALER_MasterWireFeePS
/**
* @brief Message confirming that a denomination key was revoked.
*/
-struct TALER_MasterDenominationKeyRevocation
+struct TALER_MasterDenominationKeyRevocationPS
{
/**
* Purpose is #TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED.
diff --git a/src/lib/exchange_api_curl_defaults.c b/src/lib/exchange_api_curl_defaults.c
index 1a25e564e..3ac1dfdbe 100644
--- a/src/lib/exchange_api_curl_defaults.c
+++ b/src/lib/exchange_api_curl_defaults.c
@@ -55,26 +55,5 @@ TEL_curl_easy_get (const char *url)
CURLOPT_TCP_FASTOPEN,
1L));
#endif
- {
- /* Unfortunately libcurl needs chunk to be alive until after
- curl_easy_perform. To avoid manual cleanup, we keep
- one static list here. */
- static struct curl_slist *chunk = NULL;
- if (NULL == chunk)
- {
- /* With POST requests, we do not want to wait for the
- "100 Continue" response, as our request bodies are usually
- small and directy sending them saves us a round trip.
-
- Clearing the expect header like this disables libcurl's
- default processing of the header.
-
- Disabling this header is safe for other HTTP methods, thus
- we don't distinguish further before setting it. */
- chunk = curl_slist_append (chunk, "Expect:");
- }
- GNUNET_assert (CURLE_OK == curl_easy_setopt (eh, CURLOPT_HTTPHEADER, chunk));
- }
-
return eh;
}
diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c
index 158afd56f..986bcc4c1 100644
--- a/src/lib/exchange_api_handle.c
+++ b/src/lib/exchange_api_handle.c
@@ -1740,7 +1740,10 @@ TALER_EXCHANGE_connect
TALER_LOG_DEBUG ("Connecting to the exchange (%s)\n",
url);
-
+ /* Disable 100 continue processing */
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CURL_append_header (ctx,
+ "Expect:"));
exchange = GNUNET_new (struct TALER_EXCHANGE_Handle);
exchange->ctx = ctx;
exchange->url = GNUNET_strdup (url);