summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2017-04-07 22:37:00 +0200
committerChristian Grothoff <christian@grothoff.org>2017-04-07 22:37:00 +0200
commit209076ebd35458aaf61f4a8a4b71e127e4eda440 (patch)
tree4d0fa8a3f12be5485e6768fed9231be68bc39ad8
parentef6d9cc56d3e3830750d76df1db48bc3d7d10f41 (diff)
downloadexchange-209076ebd35458aaf61f4a8a4b71e127e4eda440.tar.gz
exchange-209076ebd35458aaf61f4a8a4b71e127e4eda440.tar.bz2
exchange-209076ebd35458aaf61f4a8a4b71e127e4eda440.zip
implement denomination key revocation logic in exchangedb and taler-exchange-keyup (part of #3887)
-rw-r--r--doc/taler-exchange-keyup.15
-rw-r--r--src/exchange-tools/taler-exchange-keycheck.c20
-rw-r--r--src/exchange-tools/taler-exchange-keyup.c132
-rw-r--r--src/exchange-tools/taler-exchange-reservemod.c8
-rw-r--r--src/exchange/taler-exchange-httpd_keystate.c5
-rw-r--r--src/exchangedb/exchangedb_denomkeys.c127
-rw-r--r--src/include/taler_exchangedb_lib.h27
-rw-r--r--src/include/taler_signatures.h22
8 files changed, 329 insertions, 17 deletions
diff --git a/doc/taler-exchange-keyup.1 b/doc/taler-exchange-keyup.1
index 541c10ec8..7859d8a89 100644
--- a/doc/taler-exchange-keyup.1
+++ b/doc/taler-exchange-keyup.1
@@ -1,4 +1,4 @@
-.TH TALER\-EXCHANGE\-KEYUP 1 "Apr 22, 2015" "GNU Taler"
+.TH TALER\-EXCHANGE\-KEYUP 1 "Apr 7, 2017" "GNU Taler"
.SH NAME
taler\-exchange\-keyup \- Setup Taler exchange denomination and signing keys.
@@ -25,6 +25,9 @@ Location of the private EdDSA offline master key of the exchange.
.IP "\-o FILE, \-\-ouptut=FILE"
Where to write a denomination key signing request file to be given to the auditor.
.B
+.IP "\-r DKH, \-\-revoke=DKH"
+Revoke the denomination key where the denomination public key's hash is DKH.
+.B
.IP "\-t TIMESTAMP, \-\-time=TIMESTAMP"
Operate as if the current time was TIMESTAMP.
.B
diff --git a/src/exchange-tools/taler-exchange-keycheck.c b/src/exchange-tools/taler-exchange-keycheck.c
index ee5f0c420..3286cff4c 100644
--- a/src/exchange-tools/taler-exchange-keycheck.c
+++ b/src/exchange-tools/taler-exchange-keycheck.c
@@ -122,6 +122,7 @@ exchange_signkeys_check ()
* @param cls closure (NULL)
* @param dki the denomination key
* @param alias coin alias
+ * @param was_revoked #GNUNET_YES if the @a dki was revoked and wallets should trigger /payback
* @return #GNUNET_OK to continue to iterate,
* #GNUNET_NO to stop iteration with no error,
* #GNUNET_SYSERR to abort iteration with error!
@@ -129,7 +130,8 @@ exchange_signkeys_check ()
static int
denomkeys_iter (void *cls,
const char *alias,
- const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki)
+ const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki,
+ int was_revoked)
{
struct GNUNET_HashCode hc;
@@ -190,7 +192,23 @@ denomkeys_iter (void *cls,
static int
exchange_denomkeys_check ()
{
+ struct TALER_MasterPublicKeyP master_public_key_from_cfg;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_data (kcfg,
+ "exchange",
+ "master_public_key",
+ &master_public_key_from_cfg,
+ sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "master_public_key");
+ global_ret = 1;
+ 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 2290419aa..abf8793c7 100644
--- a/src/exchange-tools/taler-exchange-keyup.c
+++ b/src/exchange-tools/taler-exchange-keyup.c
@@ -221,6 +221,11 @@ static struct GNUNET_TIME_Absolute lookahead_sign_stamp;
static struct GNUNET_TIME_Relative max_duration_spend;
/**
+ * Revoke denomination key identified by this hash (if non-zero).
+ */
+static struct GNUNET_HashCode revoke_dkh;
+
+/**
* Return value from main().
*/
static int global_ret;
@@ -1019,6 +1024,106 @@ 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 was_revoked #GNUNET_YES if the @a dki was revoked and wallets should trigger /payback
+ * @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,
+ int was_revoked)
+{
+ struct RevokeClosure *rc = cls;
+
+ if (GNUNET_YES == was_revoked)
+ 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;
+ }
+ return GNUNET_NO;
+}
+
+
+/**
+ * Revoke the denomination key matching @a hc and request /payback to be
+ * initiated.
+ *
+ * @param hc denomination key hash to revoke
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO if @a hc was not found
+ * #GNUNET_SYSERR on error
+ */
+static int
+revoke_denomination (const struct GNUNET_HashCode *hc)
+{
+ struct RevokeClosure rc;
+
+ rc.hc = hc;
+ rc.ok = GNUNET_NO;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (kcfg,
+ "exchange",
+ "KEYDIR",
+ &rc.basedir))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "KEYDIR");
+ return GNUNET_SYSERR;
+ }
+ TALER_EXCHANGEDB_denomination_keys_iterate (rc.basedir,
+ &master_public_key,
+ &exchange_keys_revoke_by_dki,
+ &rc);
+ GNUNET_free (rc.basedir);
+ return rc.ok;
+}
+
+
+/**
* Main function that will be run.
*
* @param cls closure
@@ -1032,6 +1137,7 @@ run (void *cls,
const char *cfgfile,
const struct GNUNET_CONFIGURATION_Handle *cfg)
{
+ static struct GNUNET_HashCode zero;
struct GNUNET_TIME_Relative lookahead_sign;
struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv;
@@ -1119,7 +1225,7 @@ run (void *cls,
/* check if key from file matches the one from the configuration */
{
- struct GNUNET_CRYPTO_EddsaPublicKey master_public_key_from_cfg;
+ struct TALER_MasterPublicKeyP master_public_key_from_cfg;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_data (kcfg,
@@ -1137,7 +1243,7 @@ run (void *cls,
if (0 !=
memcmp (&master_public_key,
&master_public_key_from_cfg,
- sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
+ sizeof (struct TALER_MasterPublicKeyP)))
{
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
"exchange",
@@ -1190,6 +1296,15 @@ run (void *cls,
global_ret = 1;
return;
}
+ if ( (0 != memcmp (&zero,
+ &revoke_dkh,
+ sizeof (zero))) &&
+ (GNUNET_OK !=
+ revoke_denomination (&revoke_dkh)) )
+ {
+ global_ret = 1;
+ return;
+ }
}
@@ -1226,11 +1341,16 @@ main (int argc,
"FILENAME",
"auditor denomination key signing request file to create",
&auditorrequestfile),
+ GNUNET_GETOPT_option_base32_auto ('r',
+ "revoke",
+ "DKH",
+ "revoke denomination key hash (DKH) and request wallets to initiate /payback",
+ &revoke_dkh),
GNUNET_GETOPT_option_absolute_time ('t',
- "time",
- "TIMESTAMP",
- "pretend it is a different time for the update",
- &now),
+ "time",
+ "TIMESTAMP",
+ "pretend it is a different time for the update",
+ &now),
GNUNET_GETOPT_OPTION_END
};
diff --git a/src/exchange-tools/taler-exchange-reservemod.c b/src/exchange-tools/taler-exchange-reservemod.c
index 12d0f9c07..01114a9b1 100644
--- a/src/exchange-tools/taler-exchange-reservemod.c
+++ b/src/exchange-tools/taler-exchange-reservemod.c
@@ -188,10 +188,10 @@ main (int argc, char *const *argv)
GNUNET_GETOPT_option_help ("Deposit funds into a Taler reserve"),
GNUNET_GETOPT_option_mandatory
(GNUNET_GETOPT_option_base32_auto ('R',
- "reserve",
- "KEY",
- "reserve (public key) to modify",
- &reserve_pub)),
+ "reserve",
+ "KEY",
+ "reserve (public key) to modify",
+ &reserve_pub)),
GNUNET_GETOPT_OPTION_END
};
diff --git a/src/exchange/taler-exchange-httpd_keystate.c b/src/exchange/taler-exchange-httpd_keystate.c
index e754eb4fc..164f61abb 100644
--- a/src/exchange/taler-exchange-httpd_keystate.c
+++ b/src/exchange/taler-exchange-httpd_keystate.c
@@ -210,6 +210,7 @@ TALER_EXCHANGE_conf_duration_provide ()
* @param cls closure
* @param dki the denomination key issue
* @param alias coin alias
+ * @param was_revoked #GNUNET_YES if @a dki has been revoked
* @return #GNUNET_OK to continue to iterate,
* #GNUNET_NO to stop iteration with no error,
* #GNUNET_SYSERR to abort iteration with error!
@@ -217,7 +218,8 @@ TALER_EXCHANGE_conf_duration_provide ()
static int
reload_keys_denom_iter (void *cls,
const char *alias,
- const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki)
+ const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki,
+ int was_revoked)
{
struct TEH_KS_StateHandle *ctx = cls;
struct GNUNET_TIME_Absolute now;
@@ -674,6 +676,7 @@ TEH_KS_acquire_ (const char *location)
"Loading keys from `%s'\n",
TEH_exchange_directory);
if (-1 == TALER_EXCHANGEDB_denomination_keys_iterate (TEH_exchange_directory,
+ &TEH_master_public_key,
&reload_keys_denom_iter,
key_state))
{
diff --git a/src/exchangedb/exchangedb_denomkeys.c b/src/exchangedb/exchangedb_denomkeys.c
index de8dfa6f2..bfc3ab8eb 100644
--- a/src/exchangedb/exchangedb_denomkeys.c
+++ b/src/exchangedb/exchangedb_denomkeys.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015, 2016 Inria & GNUnet e.V.
+ Copyright (C) 2014-2017 Inria & GNUnet e.V.
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
@@ -26,6 +26,68 @@
/**
+ * 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
+ * @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,
+ const struct TALER_MasterPrivateKeyP *mpriv)
+{
+ struct GNUNET_TIME_Absolute start;
+ struct TALER_MasterDenominationKeyRevocation rm;
+ struct TALER_MasterSignatureP msig;
+ char *fn;
+ struct GNUNET_DISK_FileHandle *fh;
+ ssize_t wrote;
+ int ret;
+
+ ret = GNUNET_SYSERR;
+ start = GNUNET_TIME_absolute_ntoh (dki->issue.properties.start);
+ GNUNET_asprintf (&fn,
+ "%s" DIR_SEPARATOR_STR "%s" DIR_SEPARATOR_STR "%llu.rev",
+ exchange_base_dir,
+ alias,
+ (unsigned long long) start.abs_value_us);
+
+ 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;
+ 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);
+ GNUNET_free (fn);
+ return ret;
+}
+
+
+/**
* Import a denomination key from the given file.
*
* @param filename the file to import the key from
@@ -158,6 +220,11 @@ 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;
@@ -187,6 +254,15 @@ 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;
+ int revoked;
+
+ 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 !=
@@ -198,9 +274,53 @@ denomkeys_iterate_keydir_iter (void *cls,
filename);
return GNUNET_OK;
}
+ /* check for revocation file */
+ GNUNET_asprintf (&rev,
+ "%s.rev",
+ filename);
+ revoked = GNUNET_NO;
+ 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 = GNUNET_YES;
+ }
+ }
+
+ }
+ GNUNET_free (rev);
ret = dic->it (dic->it_cls,
dic->alias,
- &issue);
+ &issue,
+ revoked);
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;
@@ -238,6 +358,7 @@ 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
@@ -247,6 +368,7 @@ 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)
{
@@ -257,6 +379,7 @@ 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,
diff --git a/src/include/taler_exchangedb_lib.h b/src/include/taler_exchangedb_lib.h
index e4057470f..d70270e8e 100644
--- a/src/include/taler_exchangedb_lib.h
+++ b/src/include/taler_exchangedb_lib.h
@@ -160,8 +160,9 @@ TALER_EXCHANGEDB_signing_key_write (const char *exchange_base_dir,
* @brief Iterator over denomination keys.
*
* @param cls closure
- * @param dki the denomination key
* @param alias coin alias
+ * @param dki the denomination key
+ * @param was_revoked #GNUNET_YES if the @a dki was revoked and wallets should trigger /payback
* @return #GNUNET_OK to continue to iterate,
* #GNUNET_NO to stop iteration with no error,
* #GNUNET_SYSERR to abort iteration with error!
@@ -169,7 +170,8 @@ 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_EXCHANGEDB_DenominationKeyIssueInformation *dki,
+ int was_revoked);
/**
@@ -178,6 +180,7 @@ 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
@@ -187,11 +190,31 @@ 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);
/**
+ * 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
+ * @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,
+ const struct TALER_MasterPrivateKeyP *mpriv);
+
+
+/**
* Exports a denomination key to the given file.
*
* @param filename the file where to write the denomination key
diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h
index c58ea1915..d4c5d864d 100644
--- a/src/include/taler_signatures.h
+++ b/src/include/taler_signatures.h
@@ -83,6 +83,10 @@
*/
#define TALER_SIGNATURE_MASTER_WIRE_FEES 1028
+/**
+ * The given revocation key was revoked and must no longer be used.
+ */
+#define TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED 1029
/*********************************************/
/* Exchange online signatures (with signing key) */
@@ -938,6 +942,24 @@ struct TALER_MasterWireFeePS
/**
+ * @brief Message confirming that a denomination key was revoked.
+ */
+struct TALER_MasterDenominationKeyRevocation
+{
+ /**
+ * Purpose is #TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED.
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+
+ /**
+ * Hash of the denomination key.
+ */
+ struct GNUNET_HashCode h_denom_pub;
+
+};
+
+
+/**
* @brief Format used to generate the signature on a request to obtain
* the wire transfer identifier associated with a deposit.
*/