diff options
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | src/auditor/taler-auditor.c | 2 | ||||
-rw-r--r-- | src/exchange-tools/taler-exchange-keycheck.c | 5 | ||||
-rw-r--r-- | src/exchange-tools/taler-exchange-keyup.c | 93 | ||||
-rw-r--r-- | src/exchange/exchange.conf | 5 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd.c | 16 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd.h | 5 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_keystate.c | 116 | ||||
-rw-r--r-- | src/exchangedb/exchangedb_denomkeys.c | 256 | ||||
-rw-r--r-- | src/exchangedb/test_exchangedb_denomkeys.c | 57 | ||||
-rw-r--r-- | src/include/taler_exchangedb_lib.h | 55 | ||||
-rw-r--r-- | src/include/taler_signatures.h | 2 | ||||
-rw-r--r-- | src/lib/exchange_api_curl_defaults.c | 21 | ||||
-rw-r--r-- | src/lib/exchange_api_handle.c | 5 |
14 files changed, 342 insertions, 303 deletions
@@ -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 Increase various limits and rework transaction scopes to improve scalability. -CG 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); |