diff --git a/src/auditor/generate-auditor-basedb.conf b/src/auditor/generate-auditor-basedb.conf index a8d3a7f3a..ffaa54712 100644 --- a/src/auditor/generate-auditor-basedb.conf +++ b/src/auditor/generate-auditor-basedb.conf @@ -122,7 +122,6 @@ exchange = http://localhost:8081/ [coin_kudos_ct_1] value = TESTKUDOS:0.01 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -134,7 +133,6 @@ rsa_keysize = 1024 [coin_kudos_ct_10] value = TESTKUDOS:0.10 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -146,7 +144,6 @@ rsa_keysize = 1024 [coin_kudos_1] value = TESTKUDOS:1 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -158,7 +155,6 @@ rsa_keysize = 1024 [coin_kudos_2] value = TESTKUDOS:2 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -170,7 +166,6 @@ rsa_keysize = 1024 [coin_kudos_4] value = TESTKUDOS:4 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -182,7 +177,6 @@ rsa_keysize = 1024 [coin_kudos_5] value = TESTKUDOS:5 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -194,7 +188,6 @@ rsa_keysize = 1024 [coin_kudos_8] value = TESTKUDOS:8 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -206,7 +199,6 @@ rsa_keysize = 1024 [coin_kudos_10] value = TESTKUDOS:10 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years diff --git a/src/benchmark/benchmark.conf b/src/benchmark/benchmark.conf index 6bfa7a8a2..418b2a677 100644 --- a/src/benchmark/benchmark.conf +++ b/src/benchmark/benchmark.conf @@ -88,7 +88,6 @@ closing-fee-2027 = EUR:0.01 # the exchange should support (and their respective fee structure) [coin_eur_ct_1] value = EUR:0.01 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -100,7 +99,6 @@ rsa_keysize = 2048 [coin_eur_ct_10] value = EUR:0.10 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -112,7 +110,6 @@ rsa_keysize = 2048 [coin_eur_1] value = EUR:1 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -124,7 +121,6 @@ rsa_keysize = 2048 [coin_eur_5] value = EUR:5 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -136,7 +132,6 @@ rsa_keysize = 2048 [coin_eur_10] value = EUR:10 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years diff --git a/src/exchange-tools/coins.conf b/src/exchange-tools/coins.conf index a0a160773..4a32a9f0f 100644 --- a/src/exchange-tools/coins.conf +++ b/src/exchange-tools/coins.conf @@ -15,7 +15,6 @@ # All options are mandatory! # value = EUR:0.01 -# duration_overlap = 60 minutes # duration_withdraw = 7 days # duration_spend = 2 years # duration_legal = 3 years diff --git a/src/exchange-tools/taler-exchange-keyup.c b/src/exchange-tools/taler-exchange-keyup.c index e72396b1d..9f7e01f40 100644 --- a/src/exchange-tools/taler-exchange-keyup.c +++ b/src/exchange-tools/taler-exchange-keyup.c @@ -117,13 +117,6 @@ struct DenominationParameters */ struct GNUNET_TIME_Relative duration_withdraw; - /** - * How much should coin creation (@e duration_withdraw) duration overlap - * with the next denomination? Basically, the starting time of two - * denominations is always @e duration_withdraw - @e duration_overlap apart. - */ - struct GNUNET_TIME_Relative duration_overlap; - /** * What is the value of each coin? */ @@ -161,6 +154,13 @@ struct DenominationParameters }; +/** + * How much should coin creation (@e duration_withdraw) duration overlap + * with the next denomination? Basically, the starting time of two + * denominations is always @e duration_withdraw - #duration_overlap apart. + */ +static struct GNUNET_TIME_Relative duration_overlap; + /** * The configured currency. */ @@ -234,6 +234,13 @@ static struct GNUNET_TIME_Relative max_duration_spend; */ static struct GNUNET_HashCode revoke_dkh; +/** + * Which RSA key size should we use for replacment keys after revocation? + * (Useful because maybe that's the one option one might usefully want to + * change when replacing a key.) + */ +static unsigned int replacement_key_size = 2048; + /** * Return value from main(). */ @@ -641,23 +648,11 @@ get_denomination_type_params (const char *ct, return GNUNET_SYSERR; } GNUNET_TIME_round_rel (¶ms->duration_legal); - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (kcfg, - ct, - "DURATION_OVERLAP", - ¶ms->duration_overlap)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - ct, - "DURATION_OVERLAP"); - return GNUNET_SYSERR; - } - GNUNET_TIME_round_rel (¶ms->duration_overlap); - if (params->duration_overlap.rel_value_us >= + if (duration_overlap.rel_value_us >= params->duration_withdraw.rel_value_us) { GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - ct, + "exchangedb", "DURATION_OVERLAP", "Value given for DURATION_OVERLAP must be smaller than value for DURATION_WITHDRAW!"); return GNUNET_SYSERR; @@ -741,7 +736,7 @@ get_denomination_type_params (const char *ct, dir = get_denomination_dir (params); get_anchor (dir, params->duration_withdraw, - params->duration_overlap, + duration_overlap, ¶ms->anchor); /** @@ -808,6 +803,45 @@ create_denomkey_issue ( } +/** + * Write the @a denomkey_issue to file @a dkf and also (if applicable) + * dump the properties to the #auditor_output_file. + * + * @param dkf where to write the @a denomkey_issue + * @param denomkey_issue data to write + * @return #GNUNET_OK on success + */ +static int +write_denomkey_issue ( + const char *dkf, + const struct TALER_EXCHANGEDB_DenominationKey *denomkey_issue) +{ + if (GNUNET_OK != + TALER_EXCHANGEDB_denomination_key_write (dkf, + denomkey_issue)) + { + fprintf (stderr, + "Failed to write denomination key information to file `%s'.\n", + dkf); + return GNUNET_SYSERR; + } + if ( (NULL != auditor_output_file) && + (1 != + fwrite (&denomkey_issue->issue.properties, + sizeof (struct TALER_DenominationKeyValidityPS), + 1, + auditor_output_file)) ) + { + fprintf (stderr, + "Failed to write denomination key information to %s: %s\n", + auditorrequestfile, + strerror (errno)); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + /** * Generate new denomination signing keys for the denomination type of the given @a * denomination_alias. @@ -862,48 +896,19 @@ exchange_keys_update_denominationtype (void *cls, denomination_alias, GNUNET_STRINGS_absolute_time_to_string (p.anchor), dkf); - create_denomkey_issue (&p, &denomkey_issue); - if (GNUNET_OK != - TALER_EXCHANGEDB_denomination_key_write (dkf, - &denomkey_issue)) - { - fprintf (stderr, - "Failed to write denomination key information to file `%s'.\n", - dkf); - *ret = GNUNET_SYSERR; - GNUNET_CRYPTO_rsa_private_key_free ( - denomkey_issue.denom_priv.rsa_private_key); - GNUNET_CRYPTO_rsa_public_key_free ( - denomkey_issue.denom_pub.rsa_public_key); - return; - } - if ( (NULL != auditor_output_file) && - (1 != - fwrite (&denomkey_issue.issue.properties, - sizeof (struct TALER_DenominationKeyValidityPS), - 1, - auditor_output_file)) ) - { - fprintf (stderr, - "Failed to write denomination key information to %s: %s\n", - auditorrequestfile, - strerror (errno)); - *ret = GNUNET_SYSERR; - GNUNET_CRYPTO_rsa_private_key_free ( - denomkey_issue.denom_priv.rsa_private_key); - GNUNET_CRYPTO_rsa_public_key_free ( - denomkey_issue.denom_pub.rsa_public_key); - return; - } + *ret = write_denomkey_issue (dkf, + &denomkey_issue); GNUNET_CRYPTO_rsa_private_key_free ( denomkey_issue.denom_priv.rsa_private_key); GNUNET_CRYPTO_rsa_public_key_free (denomkey_issue.denom_pub.rsa_public_key); + if (GNUNET_OK != *ret) + return; /* stop loop, hard error */ p.anchor = GNUNET_TIME_absolute_add (p.anchor, p.duration_withdraw); p.anchor = GNUNET_TIME_absolute_subtract (p.anchor, - p.duration_overlap); + duration_overlap); } } @@ -1114,6 +1119,105 @@ create_wire_fees (void) } +/** + * Check if the denomination that we just revoked is currently active, + * and if so, generate a replacement key. + * + * @param cls closure with the revoked denomination key hash, a `struct GNUNET_HashCode *` + * @param alias coin alias + * @param dki the denomination key + * @return #GNUNET_OK to continue to iterate, + * #GNUNET_NO to stop iteration with no error, + * #GNUNET_SYSERR to abort iteration with error! + */ +static int +check_revocation_regeneration ( + void *cls, + const char *alias, + const struct TALER_EXCHANGEDB_DenominationKey *dki) +{ + const struct GNUNET_HashCode *denom_hash = cls; + struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Absolute withdraw_end; + + if (0 != + GNUNET_memcmp (denom_hash, + &dki->issue.properties.denom_hash)) + return GNUNET_OK; /* does not match */ + now = GNUNET_TIME_absolute_get (); + withdraw_end = GNUNET_TIME_absolute_ntoh ( + dki->issue.properties.expire_withdraw); + if (now.abs_value_us >= withdraw_end.abs_value_us) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Revoked denomination key has expired, no need to create a replacment\n"); + return GNUNET_NO; + } + + { + struct GNUNET_TIME_Absolute anchor + = GNUNET_TIME_absolute_ntoh (dki->issue.properties.start); + struct TALER_EXCHANGEDB_DenominationKey dki_new; + const char *dkf; + int ret; + struct DenominationParameters dp = { + .duration_legal + = GNUNET_TIME_absolute_get_difference + (anchor, + GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_legal)), + .duration_spend + = GNUNET_TIME_absolute_get_difference + (anchor, + GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_deposit)), + .duration_withdraw + = GNUNET_TIME_absolute_get_difference + (anchor, + GNUNET_TIME_absolute_ntoh (dki->issue.properties.expire_withdraw)), + .anchor = anchor, + .rsa_keysize = replacement_key_size + }; + char *dkfi; + + TALER_amount_ntoh (&dp.value, + &dki->issue.properties.value); + TALER_amount_ntoh (&dp.fee_withdraw, + &dki->issue.properties.fee_withdraw); + TALER_amount_ntoh (&dp.fee_deposit, + &dki->issue.properties.fee_deposit); + TALER_amount_ntoh (&dp.fee_refresh, + &dki->issue.properties.fee_refresh); + TALER_amount_ntoh (&dp.fee_refund, + &dki->issue.properties.fee_refund); + + /* find unused file name for revocation file by appending -%u */ + dkf = get_denomination_type_file (&dp, + dp.anchor); + for (unsigned int i = 1;; i++) + { + GNUNET_asprintf (&dkfi, + "%s-%u", + dkf, + i); + if (GNUNET_YES != GNUNET_DISK_file_test (dkfi)) + break; + GNUNET_free (dkfi); + } + + create_denomkey_issue (&dp, + &dki_new); + ret = write_denomkey_issue (dkfi, + &dki_new); + GNUNET_free (dkfi); + GNUNET_CRYPTO_rsa_private_key_free (dki_new.denom_priv.rsa_private_key); + GNUNET_CRYPTO_rsa_public_key_free (dki_new.denom_pub.rsa_public_key); + if (GNUNET_OK != ret) + return GNUNET_SYSERR; + } + + return GNUNET_NO; +} + + /** * Revoke the denomination key matching @a hc and request /recoup to be * initiated. @@ -1126,29 +1230,41 @@ create_wire_fees (void) static int revoke_denomination (const struct GNUNET_HashCode *hc) { - char *basedir; + { + char *basedir; - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (kcfg, - "exchange", - "REVOCATION_DIR", - &basedir)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", - "REVOCATION_DIR"); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - TALER_EXCHANGEDB_denomination_key_revoke (basedir, - hc, - &master_priv)) - { + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (kcfg, + "exchange", + "REVOCATION_DIR", + &basedir)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "REVOCATION_DIR"); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + TALER_EXCHANGEDB_denomination_key_revoke (basedir, + hc, + &master_priv)) + { + GNUNET_free (basedir); + GNUNET_break (0); + return GNUNET_SYSERR; + } GNUNET_free (basedir); - GNUNET_break (0); + } + + if (GNUNET_SYSERR == + TALER_EXCHANGEDB_denomination_keys_iterate (exchange_directory, + &check_revocation_regeneration, + (void *) hc)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Might have failed to generate replacement for revoked denomination key!\n"); return GNUNET_SYSERR; } - GNUNET_free (basedir); return GNUNET_OK; } @@ -1186,6 +1302,19 @@ run (void *cls, now = now_tmp; } GNUNET_TIME_round_abs (&now); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (kcfg, + "exchangedb", + "DURATION_OVERLAP", + &duration_overlap)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchangedb", + "DURATION_OVERLAP"); + global_ret = 1; + return; + } + GNUNET_TIME_round_rel (&duration_overlap); if (NULL == feedir) { @@ -1336,6 +1465,11 @@ main (int argc, "DIRNAME", "directory where to write wire transfer fee structure", &feedir), + GNUNET_GETOPT_option_uint ('k', + "replacement-keysize", + "BITS", + "when creating a replacement key in a revocation operation, which key size should be used for the new denomination key", + &replacement_key_size), GNUNET_GETOPT_option_filename ('o', "output", "FILENAME", diff --git a/src/exchange/test_taler_exchange_httpd.conf b/src/exchange/test_taler_exchange_httpd.conf index 153927351..63b59f905 100644 --- a/src/exchange/test_taler_exchange_httpd.conf +++ b/src/exchange/test_taler_exchange_httpd.conf @@ -98,7 +98,6 @@ CLOSING-FEE-2027 = EUR:0.01 # Coins for the tests. [coin_eur_ct_1] value = EUR:0.01 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -110,7 +109,6 @@ rsa_keysize = 1024 [coin_eur_ct_10] value = EUR:0.10 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -122,7 +120,6 @@ rsa_keysize = 1024 [coin_eur_1] value = EUR:1 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years diff --git a/src/exchange/test_taler_exchange_unix.conf b/src/exchange/test_taler_exchange_unix.conf index d41df9abe..b9cc4b3d5 100644 --- a/src/exchange/test_taler_exchange_unix.conf +++ b/src/exchange/test_taler_exchange_unix.conf @@ -102,7 +102,6 @@ CLOSING-FEE-2027 = EUR:0.01 # Coins for the tests. [coin_eur_ct_1] value = EUR:0.01 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -114,7 +113,6 @@ rsa_keysize = 1024 [coin_eur_ct_10] value = EUR:0.10 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -126,7 +124,6 @@ rsa_keysize = 1024 [coin_eur_1] value = EUR:1 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years diff --git a/src/exchangedb/exchangedb.conf b/src/exchangedb/exchangedb.conf index 77748bf5a..6853b8d18 100644 --- a/src/exchangedb/exchangedb.conf +++ b/src/exchangedb/exchangedb.conf @@ -26,3 +26,11 @@ IDLE_RESERVE_EXPIRATION_TIME = 4 weeks # After how long do we forget about reserves? Should be above # the legal expiration timeframe of withdrawn coins. LEGAL_RESERVE_EXPIRATION_TIME = 7 years + + +# How long should generated coins overlap in their validity +# periods. Should be long enough to avoid problems with +# wallets picking one key and then due to network latency +# another key being valid. The DURATION_WITHDRAW period +# must be longer than this value. +DURATION_OVERLAP = 5 minutes \ No newline at end of file diff --git a/src/testing/test-taler-exchange-wirewatch-postgres.conf b/src/testing/test-taler-exchange-wirewatch-postgres.conf index 61029e3f2..67696e583 100644 --- a/src/testing/test-taler-exchange-wirewatch-postgres.conf +++ b/src/testing/test-taler-exchange-wirewatch-postgres.conf @@ -93,7 +93,6 @@ CLOSING-FEE-2027 = EUR:0.01 # refuses to start. [coin_eur_ct_1] value = EUR:0.01 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years diff --git a/src/testing/test_auditor_api.conf b/src/testing/test_auditor_api.conf index b448b12a5..c43e1ad49 100644 --- a/src/testing/test_auditor_api.conf +++ b/src/testing/test_auditor_api.conf @@ -146,7 +146,6 @@ CLOSING-FEE-2027 = EUR:0.01 # the exchange should support (and their respective fee structure) [coin_eur_ct_1] value = EUR:0.01 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -158,7 +157,6 @@ rsa_keysize = 1024 [coin_eur_ct_10] value = EUR:0.10 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -170,7 +168,6 @@ rsa_keysize = 1024 [coin_eur_1] value = EUR:1 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -182,7 +179,6 @@ rsa_keysize = 1024 [coin_eur_5] value = EUR:5 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -194,7 +190,6 @@ rsa_keysize = 1024 [coin_eur_10] value = EUR:10 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years diff --git a/src/testing/test_exchange_api.conf b/src/testing/test_exchange_api.conf index 7454934a8..1b16444ff 100644 --- a/src/testing/test_exchange_api.conf +++ b/src/testing/test_exchange_api.conf @@ -148,7 +148,6 @@ CLOSING-FEE-2027 = EUR:0.01 # the exchange should support (and their respective fee structure) [coin_eur_ct_1] value = EUR:0.01 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -160,7 +159,6 @@ rsa_keysize = 1024 [coin_eur_ct_10] value = EUR:0.10 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -172,7 +170,6 @@ rsa_keysize = 1024 [coin_eur_1] value = EUR:1 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -184,7 +181,6 @@ rsa_keysize = 1024 [coin_eur_5] value = EUR:5 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -196,7 +192,6 @@ rsa_keysize = 1024 [coin_eur_10] value = EUR:10 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years diff --git a/src/testing/test_exchange_api_keys_cherry_picking.conf b/src/testing/test_exchange_api_keys_cherry_picking.conf index 0416c8eec..b67440d68 100644 --- a/src/testing/test_exchange_api_keys_cherry_picking.conf +++ b/src/testing/test_exchange_api_keys_cherry_picking.conf @@ -167,9 +167,11 @@ CLOSING-FEE-2024 = EUR:0.01 CLOSING-FEE-2025 = EUR:0.01 CLOSING-FEE-2026 = EUR:0.01 +[exchangedb] +duration_overlap = 1 s + [coin_eur_1] value = EUR:1 -duration_overlap = 1 s duration_withdraw = 80 s duration_spend = 80 s duration_legal = 60 s diff --git a/src/testing/test_exchange_api_twisted.conf b/src/testing/test_exchange_api_twisted.conf index 8abe13273..f93fe912a 100644 --- a/src/testing/test_exchange_api_twisted.conf +++ b/src/testing/test_exchange_api_twisted.conf @@ -135,7 +135,6 @@ CLOSING-FEE-2027 = EUR:0.01 [coin_eur_ct_1] value = EUR:0.01 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -147,7 +146,6 @@ rsa_keysize = 1024 [coin_eur_ct_10] value = EUR:0.10 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -159,7 +157,6 @@ rsa_keysize = 1024 [coin_eur_1] value = EUR:1 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -171,7 +168,6 @@ rsa_keysize = 1024 [coin_eur_5] value = EUR:5 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years @@ -183,7 +179,6 @@ rsa_keysize = 1024 [coin_eur_10] value = EUR:10 -duration_overlap = 5 minutes duration_withdraw = 7 days duration_spend = 2 years duration_legal = 3 years