actually disable 100 continue

This commit is contained in:
Christian Grothoff 2019-02-23 14:47:44 +01:00
parent 3219c14674
commit 4dea098f54
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
14 changed files with 342 additions and 303 deletions

View File

@ -1,3 +1,10 @@
Sat Mar 2 19:09:43 CET 2019
Changing denomination key revocation file format and moving them
to their own directory (preparations for #5536 resolution). -CG
Sat Feb 23 14:47:12 CET 2019
Actually disable 100 CONTINUE. -CG
Sun Aug 19 15:15:48 CEST 2018 Sun Aug 19 15:15:48 CEST 2018
Increase various limits and rework transaction scopes to Increase various limits and rework transaction scopes to
improve scalability. -CG improve scalability. -CG

View File

@ -1148,7 +1148,7 @@ handle_payback_by_reserve (void *cls,
else else
{ {
/* verify msig */ /* verify msig */
struct TALER_MasterDenominationKeyRevocation kr; struct TALER_MasterDenominationKeyRevocationPS kr;
kr.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED); kr.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED);
kr.purpose.size = htonl (sizeof (kr)); kr.purpose.size = htonl (sizeof (kr));

View File

@ -120,7 +120,6 @@ exchange_signkeys_check ()
* @param cls closure (NULL) * @param cls closure (NULL)
* @param dki the denomination key * @param dki the denomination key
* @param alias coin alias * @param alias coin alias
* @param revocation_master_sig non-NULL if @a dki was revoked
* @return #GNUNET_OK to continue to iterate, * @return #GNUNET_OK to continue to iterate,
* #GNUNET_NO to stop iteration with no error, * #GNUNET_NO to stop iteration with no error,
* #GNUNET_SYSERR to abort iteration with error! * #GNUNET_SYSERR to abort iteration with error!
@ -128,8 +127,7 @@ exchange_signkeys_check ()
static int static int
denomkeys_iter (void *cls, denomkeys_iter (void *cls,
const char *alias, const char *alias,
const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki, const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki)
const struct TALER_MasterSignatureP *revocation_master_sig)
{ {
struct GNUNET_HashCode hc; struct GNUNET_HashCode hc;
@ -206,7 +204,6 @@ exchange_denomkeys_check ()
return GNUNET_NO; return GNUNET_NO;
} }
if (0 > TALER_EXCHANGEDB_denomination_keys_iterate (exchange_directory, if (0 > TALER_EXCHANGEDB_denomination_keys_iterate (exchange_directory,
&master_public_key_from_cfg,
&denomkeys_iter, &denomkeys_iter,
NULL)) NULL))
return GNUNET_NO; return GNUNET_NO;

View File

@ -1111,73 +1111,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 * Revoke the denomination key matching @a hc and request /payback to be
* initiated. * initiated.
@ -1190,32 +1123,30 @@ exchange_keys_revoke_by_dki (void *cls,
static int static int
revoke_denomination (const struct GNUNET_HashCode *hc) revoke_denomination (const struct GNUNET_HashCode *hc)
{ {
struct RevokeClosure rc; char *basedir;
rc.hc = hc;
rc.ok = GNUNET_NO;
if (GNUNET_OK != if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_filename (kcfg, GNUNET_CONFIGURATION_get_value_filename (kcfg,
"exchange", "exchange",
"KEYDIR", "REVOCATION_DIR",
&rc.basedir)) &basedir))
{ {
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"exchange", "exchange",
"KEYDIR"); "REVOCATION_DIR");
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
if (-1 == if (GNUNET_OK !=
TALER_EXCHANGEDB_denomination_keys_iterate (rc.basedir, TALER_EXCHANGEDB_denomination_key_revoke (basedir,
&master_public_key, hc,
&exchange_keys_revoke_by_dki, &master_priv))
&rc))
{ {
GNUNET_free (basedir);
GNUNET_break (0); GNUNET_break (0);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
GNUNET_free (rc.basedir); GNUNET_free (basedir);
return rc.ok; return GNUNET_OK;
} }

View File

@ -7,7 +7,12 @@
# in respective subdirectories.) # in respective subdirectories.)
KEYDIR = ${TALER_DATA_HOME}/exchange/live-keys/ 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 # Master public key used to sign the exchange's various keys
# This must be adjusted to your actually installation.
# MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG # MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
# How to access our database # How to access our database

View File

@ -69,6 +69,11 @@ int TEH_exchange_connection_close;
*/ */
char *TEH_exchange_directory; char *TEH_exchange_directory;
/**
* Directory where revocations are stored (global)
*/
char *TEH_revocation_directory;
/** /**
* The exchange's configuration (global) * The exchange's configuration (global)
*/ */
@ -523,6 +528,17 @@ exchange_serve_process_config ()
"KEYDIR"); "KEYDIR");
return GNUNET_SYSERR; 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 != if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg, GNUNET_CONFIGURATION_get_value_string (cfg,
"taler", "taler",

View File

@ -48,6 +48,11 @@ extern struct GNUNET_CONFIGURATION_Handle *cfg;
*/ */
extern char *TEH_exchange_directory; extern char *TEH_exchange_directory;
/**
* Main directory with revocation data.
*/
extern char *TEH_revocation_directory;
/** /**
* Master public key (according to the * Master public key (according to the
* configuration in the exchange directory). * configuration in the exchange directory).

View File

@ -677,7 +677,6 @@ add_denomination_transaction (void *cls,
* @param cls closure with a `struct ResponseFactoryContext *` * @param cls closure with a `struct ResponseFactoryContext *`
* @param dki the denomination key issue * @param dki the denomination key issue
* @param alias coin alias * @param alias coin alias
* @param revocation_master_sig non-NULL if @a dki was revoked
* @return #GNUNET_OK to continue to iterate, * @return #GNUNET_OK to continue to iterate,
* #GNUNET_NO to stop iteration with no error, * #GNUNET_NO to stop iteration with no error,
* #GNUNET_SYSERR to abort iteration with error! * #GNUNET_SYSERR to abort iteration with error!
@ -685,8 +684,7 @@ add_denomination_transaction (void *cls,
static int static int
reload_keys_denom_iter (void *cls, reload_keys_denom_iter (void *cls,
const char *alias, const char *alias,
const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki, const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki)
const struct TALER_MasterSignatureP *revocation_master_sig)
{ {
struct ResponseFactoryContext *rfc = cls; struct ResponseFactoryContext *rfc = cls;
struct TEH_KS_StateHandle *key_state = rfc->key_state; struct TEH_KS_StateHandle *key_state = rfc->key_state;
@ -719,40 +717,6 @@ reload_keys_denom_iter (void *cls,
return GNUNET_OK; 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 ()); horizon = GNUNET_TIME_relative_to_absolute (TALER_EXCHANGE_conf_duration_provide ());
start = GNUNET_TIME_absolute_ntoh (dki->issue.properties.start); start = GNUNET_TIME_absolute_ntoh (dki->issue.properties.start);
if (start.abs_value_us > horizon.abs_value_us) if (start.abs_value_us > horizon.abs_value_us)
@ -793,6 +757,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. * Convert the public part of a sign key issue to a JSON object.
* *
@ -1527,7 +1552,6 @@ make_fresh_key_state ()
'rfc.payback_array' */ 'rfc.payback_array' */
if (-1 == if (-1 ==
TALER_EXCHANGEDB_denomination_keys_iterate (TEH_exchange_directory, TALER_EXCHANGEDB_denomination_keys_iterate (TEH_exchange_directory,
&TEH_master_public_key,
&reload_keys_denom_iter, &reload_keys_denom_iter,
&rfc)) &rfc))
{ {
@ -1540,6 +1564,22 @@ make_fresh_key_state ()
json_decref (rfc.sign_keys_array); json_decref (rfc.sign_keys_array);
return NULL; 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)) if (0 == GNUNET_CONTAINER_multihashmap_size (key_state->denomkey_map))
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,

View File

@ -25,66 +25,70 @@
#include "taler_exchangedb_lib.h" #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 * Mark the given denomination key as revoked and request the wallets
* to initiate /payback. * to initiate /payback.
* *
* @param exchange_base_dir base directory for the exchange, * @param revocation_dir where to write the revocation certificate
* the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS * @param denom_hash hash of the denomination key to revoke
* subdirectory * @param mpriv master private key to sign with
* @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. * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure.
*/ */
int int
TALER_EXCHANGEDB_denomination_key_revoke (const char *exchange_base_dir, TALER_EXCHANGEDB_denomination_key_revoke (const char *revocation_dir,
const char *alias, const struct GNUNET_HashCode *denom_hash,
const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki,
const struct TALER_MasterPrivateKeyP *mpriv) const struct TALER_MasterPrivateKeyP *mpriv)
{ {
struct GNUNET_TIME_Absolute start; struct TALER_MasterDenominationKeyRevocationPS rm;
struct TALER_MasterDenominationKeyRevocation rm;
struct TALER_MasterSignatureP msig;
char *fn; char *fn;
struct GNUNET_DISK_FileHandle *fh;
ssize_t wrote;
int ret; int ret;
struct RevocationFileP rd;
ret = GNUNET_SYSERR; ret = GNUNET_SYSERR;
start = GNUNET_TIME_absolute_ntoh (dki->issue.properties.start);
GNUNET_asprintf (&fn, GNUNET_asprintf (&fn,
"%s" DIR_SEPARATOR_STR "%s" DIR_SEPARATOR_STR
TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS DIR_SEPARATOR_STR "%s.rev",
"%s" DIR_SEPARATOR_STR revocation_dir,
"%llu.rev", GNUNET_h2s_full (denom_hash));
exchange_base_dir,
alias,
(unsigned long long) start.abs_value_us);
rm.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED); rm.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED);
rm.purpose.size = htonl (sizeof (rm)); 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_assert (GNUNET_OK ==
GNUNET_CRYPTO_eddsa_sign (&mpriv->eddsa_priv, GNUNET_CRYPTO_eddsa_sign (&mpriv->eddsa_priv,
&rm.purpose, &rm.purpose,
&msig.eddsa_signature)); &rd.msig.eddsa_signature));
if (NULL == (fh = GNUNET_DISK_file_open rd.denom_hash = *denom_hash;
(fn, if (sizeof (rd) !=
GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_TRUNCATE, GNUNET_DISK_fn_write (fn,
GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE))) &rd,
goto cleanup; sizeof (rd),
if (GNUNET_SYSERR == GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE))
(wrote = GNUNET_DISK_file_write (fh, ret = GNUNET_SYSERR;
&msig, else
sizeof (msig)))) ret = GNUNET_OK;
goto cleanup;
if (wrote != sizeof (msig))
goto cleanup;
ret = GNUNET_OK;
cleanup:
if (NULL != fh)
(void) GNUNET_DISK_file_close (fh);
GNUNET_free (fn); GNUNET_free (fn);
return ret; return ret;
} }
@ -228,11 +232,6 @@ struct DenomkeysIterateContext
*/ */
const char *alias; const char *alias;
/**
* Master public key to use to validate revocations.
*/
const struct TALER_MasterPublicKeyP *master_pub;
/** /**
* Function to call on each denomination key. * Function to call on each denomination key.
*/ */
@ -263,16 +262,6 @@ denomkeys_iterate_keydir_iter (void *cls,
struct DenomkeysIterateContext *dic = cls; struct DenomkeysIterateContext *dic = cls;
struct TALER_EXCHANGEDB_DenominationKeyIssueInformation issue; struct TALER_EXCHANGEDB_DenominationKeyIssueInformation issue;
int ret; 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)); memset (&issue, 0, sizeof (issue));
if (GNUNET_OK != if (GNUNET_OK !=
@ -284,52 +273,9 @@ denomkeys_iterate_keydir_iter (void *cls,
filename); filename);
return GNUNET_OK; 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, ret = dic->it (dic->it_cls,
dic->alias, dic->alias,
&issue, &issue);
revoked);
GNUNET_CRYPTO_rsa_private_key_free (issue.denom_priv.rsa_private_key); GNUNET_CRYPTO_rsa_private_key_free (issue.denom_priv.rsa_private_key);
GNUNET_CRYPTO_rsa_public_key_free (issue.denom_pub.rsa_public_key); GNUNET_CRYPTO_rsa_public_key_free (issue.denom_pub.rsa_public_key);
return ret; return ret;
@ -367,7 +313,6 @@ denomkeys_iterate_topdir_iter (void *cls,
* @param exchange_base_dir base directory for the exchange, * @param exchange_base_dir base directory for the exchange,
* the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS * the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS
* subdirectory * subdirectory
* @param master_pub master public key (used to check revocations)
* @param it function to call on each denomination key found * @param it function to call on each denomination key found
* @param it_cls closure for @a it * @param it_cls closure for @a it
* @return -1 on error, 0 if no files were found, otherwise * @return -1 on error, 0 if no files were found, otherwise
@ -377,7 +322,6 @@ denomkeys_iterate_topdir_iter (void *cls,
*/ */
int int
TALER_EXCHANGEDB_denomination_keys_iterate (const char *exchange_base_dir, TALER_EXCHANGEDB_denomination_keys_iterate (const char *exchange_base_dir,
const struct TALER_MasterPublicKeyP *master_pub,
TALER_EXCHANGEDB_DenominationKeyIterator it, TALER_EXCHANGEDB_DenominationKeyIterator it,
void *it_cls) void *it_cls)
{ {
@ -388,7 +332,6 @@ TALER_EXCHANGEDB_denomination_keys_iterate (const char *exchange_base_dir,
GNUNET_asprintf (&dir, GNUNET_asprintf (&dir,
"%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS, "%s" DIR_SEPARATOR_STR TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS,
exchange_base_dir); exchange_base_dir);
dic.master_pub = master_pub;
dic.it = it; dic.it = it;
dic.it_cls = it_cls; dic.it_cls = it_cls;
ret = GNUNET_DISK_directory_scan (dir, 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 */ /* end of exchangedb_denomkeys.c */

View File

@ -38,7 +38,6 @@
* @param cls closure with expected DKI * @param cls closure with expected DKI
* @param dki the denomination key * @param dki the denomination key
* @param alias coin alias * @param alias coin alias
* @param revocation_master_sig non-NULL if @a dki was revoked
* @return #GNUNET_OK to continue to iterate, * @return #GNUNET_OK to continue to iterate,
* #GNUNET_NO to stop iteration with no error, * #GNUNET_NO to stop iteration with no error,
* #GNUNET_SYSERR to abort iteration with error! * #GNUNET_SYSERR to abort iteration with error!
@ -46,16 +45,10 @@
static int static int
dki_iter (void *cls, dki_iter (void *cls,
const char *alias, const char *alias,
const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki, const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki)
const struct TALER_MasterSignatureP *revocation_master_sig)
{ {
const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *exp = cls; const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *exp = cls;
if (NULL != revocation_master_sig)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
if (0 != memcmp (&exp->issue, if (0 != memcmp (&exp->issue,
&dki->issue, &dki->issue,
sizeof (struct TALER_EXCHANGEDB_DenominationKeyInformationP))) sizeof (struct TALER_EXCHANGEDB_DenominationKeyInformationP)))
@ -85,8 +78,7 @@ dki_iter (void *cls,
* @brief Iterator called on revoked denomination key. * @brief Iterator called on revoked denomination key.
* *
* @param cls closure with expected DKI * @param cls closure with expected DKI
* @param dki the denomination key * @param denom_hash hash of the revoked denomination key
* @param alias coin alias
* @param revocation_master_sig non-NULL if @a dki was revoked * @param revocation_master_sig non-NULL if @a dki was revoked
* @return #GNUNET_OK to continue to iterate, * @return #GNUNET_OK to continue to iterate,
* #GNUNET_NO to stop iteration with no error, * #GNUNET_NO to stop iteration with no error,
@ -94,8 +86,7 @@ dki_iter (void *cls,
*/ */
static int static int
dki_iter_revoked (void *cls, dki_iter_revoked (void *cls,
const char *alias, const struct GNUNET_HashCode *denom_hash,
const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki,
const struct TALER_MasterSignatureP *revocation_master_sig) const struct TALER_MasterSignatureP *revocation_master_sig)
{ {
const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *exp = cls; const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *exp = cls;
@ -105,28 +96,13 @@ dki_iter_revoked (void *cls,
GNUNET_break (0); GNUNET_break (0);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
if (0 != memcmp (&exp->issue, if (0 != memcmp (denom_hash,
&dki->issue, &exp->issue.properties.denom_hash,
sizeof (struct TALER_EXCHANGEDB_DenominationKeyInformationP))) sizeof (struct GNUNET_HashCode)))
{ {
GNUNET_break (0); GNUNET_break (0);
return GNUNET_SYSERR; 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; return GNUNET_OK;
} }
@ -146,6 +122,7 @@ main (int argc,
size_t enc_read_size; size_t enc_read_size;
char *tmpfile; char *tmpfile;
char *tmpdir; char *tmpdir;
char *revdir;
int ret; int ret;
struct GNUNET_TIME_Absolute start; struct GNUNET_TIME_Absolute start;
@ -180,6 +157,10 @@ main (int argc,
TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS, TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS,
"cur-unit-uuid", "cur-unit-uuid",
(unsigned long long) start.abs_value_us); (unsigned long long) start.abs_value_us);
GNUNET_asprintf (&revdir,
"%s/revocations/",
tmpdir,
TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS);
EXITIF (GNUNET_OK != EXITIF (GNUNET_OK !=
TALER_EXCHANGEDB_denomination_key_write (tmpfile, TALER_EXCHANGEDB_denomination_key_write (tmpfile,
&dki)); &dki));
@ -188,21 +169,19 @@ main (int argc,
&dki_read)); &dki_read));
EXITIF (1 != EXITIF (1 !=
TALER_EXCHANGEDB_denomination_keys_iterate (tmpdir, TALER_EXCHANGEDB_denomination_keys_iterate (tmpdir,
&master_pub,
&dki_iter, &dki_iter,
&dki)); &dki));
EXITIF (GNUNET_OK != EXITIF (GNUNET_OK !=
TALER_EXCHANGEDB_denomination_key_revoke (tmpdir, TALER_EXCHANGEDB_denomination_key_revoke (revdir,
"cur-unit-uuid", &dki.issue.properties.denom_hash,
&dki,
&master_priv)); &master_priv));
EXITIF (1 != EXITIF (1 !=
TALER_EXCHANGEDB_denomination_keys_iterate (tmpdir, TALER_EXCHANGEDB_revocations_iterate (revdir,
&master_pub, &master_pub,
&dki_iter_revoked, &dki_iter_revoked,
&dki)); &dki));
GNUNET_free (revdir);
enc_read_size = GNUNET_CRYPTO_rsa_private_key_encode (dki_read.denom_priv.rsa_private_key, enc_read_size = GNUNET_CRYPTO_rsa_private_key_encode (dki_read.denom_priv.rsa_private_key,
&enc_read); &enc_read);

View File

@ -169,7 +169,6 @@ TALER_EXCHANGEDB_signing_key_write (const char *exchange_base_dir,
* @param cls closure * @param cls closure
* @param alias coin alias * @param alias coin alias
* @param dki the denomination key * @param dki the denomination key
* @param revocation_master_sig non-NULL if @a dki was revoked
* @return #GNUNET_OK to continue to iterate, * @return #GNUNET_OK to continue to iterate,
* #GNUNET_NO to stop iteration with no error, * #GNUNET_NO to stop iteration with no error,
* #GNUNET_SYSERR to abort iteration with error! * #GNUNET_SYSERR to abort iteration with error!
@ -177,8 +176,23 @@ TALER_EXCHANGEDB_signing_key_write (const char *exchange_base_dir,
typedef int typedef int
(*TALER_EXCHANGEDB_DenominationKeyIterator)(void *cls, (*TALER_EXCHANGEDB_DenominationKeyIterator)(void *cls,
const char *alias, const char *alias,
const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki, const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki);
const struct TALER_MasterSignatureP *revocation_master_sig);
/**
* @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, * @param exchange_base_dir base directory for the exchange,
* the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS * the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS
* subdirectory * subdirectory
* @param master_pub master public key (used to check revocations)
* @param it function to call on each denomination key found * @param it function to call on each denomination key found
* @param it_cls closure for @a it * @param it_cls closure for @a it
* @return -1 on error, 0 if no files were found, otherwise * @return -1 on error, 0 if no files were found, otherwise
@ -197,27 +210,41 @@ typedef int
*/ */
int int
TALER_EXCHANGEDB_denomination_keys_iterate (const char *exchange_base_dir, TALER_EXCHANGEDB_denomination_keys_iterate (const char *exchange_base_dir,
const struct TALER_MasterPublicKeyP *master_pub,
TALER_EXCHANGEDB_DenominationKeyIterator it, TALER_EXCHANGEDB_DenominationKeyIterator it,
void *it_cls); 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 * Mark the given denomination key as revoked and request the wallets
* to initiate /payback. * to initiate /payback.
* *
* @param exchange_base_dir base directory for the exchange, * @param revocation_dir where to write the revocation certificate
* the signing keys must be in the #TALER_EXCHANGEDB_DIR_DENOMINATION_KEYS * @param denom_hash hash of the denomination key to revoke
* subdirectory * @param mpriv master private key to sign with
* @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. * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure.
*/ */
int int
TALER_EXCHANGEDB_denomination_key_revoke (const char *exchange_base_dir, TALER_EXCHANGEDB_denomination_key_revoke (const char *revocation_dir,
const char *alias, const struct GNUNET_HashCode *denom_hash,
const struct TALER_EXCHANGEDB_DenominationKeyIssueInformation *dki,
const struct TALER_MasterPrivateKeyP *mpriv); const struct TALER_MasterPrivateKeyP *mpriv);

View File

@ -943,7 +943,7 @@ struct TALER_MasterWireFeePS
/** /**
* @brief Message confirming that a denomination key was revoked. * @brief Message confirming that a denomination key was revoked.
*/ */
struct TALER_MasterDenominationKeyRevocation struct TALER_MasterDenominationKeyRevocationPS
{ {
/** /**
* Purpose is #TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED. * Purpose is #TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED.

View File

@ -55,26 +55,5 @@ TEL_curl_easy_get (const char *url)
CURLOPT_TCP_FASTOPEN, CURLOPT_TCP_FASTOPEN,
1L)); 1L));
#endif #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; return eh;
} }

View File

@ -1740,7 +1740,10 @@ TALER_EXCHANGE_connect
TALER_LOG_DEBUG ("Connecting to the exchange (%s)\n", TALER_LOG_DEBUG ("Connecting to the exchange (%s)\n",
url); url);
/* Disable 100 continue processing */
GNUNET_break (GNUNET_OK ==
GNUNET_CURL_append_header (ctx,
"Expect:"));
exchange = GNUNET_new (struct TALER_EXCHANGE_Handle); exchange = GNUNET_new (struct TALER_EXCHANGE_Handle);
exchange->ctx = ctx; exchange->ctx = ctx;
exchange->url = GNUNET_strdup (url); exchange->url = GNUNET_strdup (url);