From 8bdf6ab19df70c16d335ecf82f2c3b2117eeb70e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96zg=C3=BCr=20Kesim?= Date: Wed, 16 Feb 2022 22:01:05 +0100 Subject: [age restriction] progress 14/n - withdraw and deposit Age restriction support for - withdraw is done and tested - deposit is done and tested TODOs: - melt/refresh/reveal - link ------ Added functions - TALER_age_restriction_commit - TALER_age_commitment_derive - TALER_age_commitment_hash - TALER_age_restriction_commitment_free_inside - Hash of age commitment passed around API boundaries Exchangedb adjustments for denominations - all prepared statements re: denominations now handle age_mask - signature parameters adjusted Hash and signature verification of /keys adjusted - Hashes of (normal) denominations and age-restricted denominations are calculated seperately - The hash of the age-restricted ones will then be added to the other hash - The total hash is signed/verified Tests for withdraw with age restriction added - TALER_EXCHANGE_DenomPublickey now carries age_mask - TALER_TESTING_cmd_withdraw_amount* takes age parameter - TALER_TESTING_find_pk takes boolean age_restricted - WithdrawState carries age_commitment and its hash - withdraw_run derives new age commitment, if applicable - Added age parameter to testing (13 as example) Various Fixes and changes - Fixes of post handler for /management/extensions - Fixes for offline tool extensions signing - Slight refactoring of extensions - Age restriction extension simplified - config is now global to extension - added global TEH_age_restriction_enabled and TEH_age_mask in taler-exchange-httpd - helper functions and macros introduced --- src/testing/Makefile.am | 3 + src/testing/test_auditor_api.c | 24 ++- src/testing/test_exchange_api-cs.conf | 10 +- src/testing/test_exchange_api-rsa.conf | 10 +- src/testing/test_exchange_api.c | 93 +++++++++++- src/testing/test_exchange_api_revocation.c | 2 + src/testing/test_kyc_api.c | 4 + src/testing/testing_api_cmd_deposit.c | 27 +++- src/testing/testing_api_cmd_insert_deposit.c | 2 +- .../testing_api_cmd_offline_sign_extensions.c | 164 +++++++++++++++++++++ src/testing/testing_api_cmd_refresh.c | 56 ++++++- src/testing/testing_api_cmd_withdraw.c | 91 +++++++++++- src/testing/testing_api_helpers_exchange.c | 13 +- 13 files changed, 467 insertions(+), 32 deletions(-) create mode 100644 src/testing/testing_api_cmd_offline_sign_extensions.c (limited to 'src/testing') diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am index a6b582709..39cc6cbed 100644 --- a/src/testing/Makefile.am +++ b/src/testing/Makefile.am @@ -68,6 +68,7 @@ libtalertesting_la_SOURCES = \ testing_api_cmd_oauth.c \ testing_api_cmd_offline_sign_fees.c \ testing_api_cmd_offline_sign_keys.c \ + testing_api_cmd_offline_sign_extensions.c \ testing_api_cmd_set_wire_fee.c \ testing_api_cmd_recoup.c \ testing_api_cmd_recoup_refresh.c \ @@ -249,6 +250,7 @@ test_exchange_api_cs_LDADD = \ -lgnunetcurl \ -lgnunetutil \ -ljansson \ + -ltalerextensions \ $(XLIB) test_exchange_api_rsa_SOURCES = \ @@ -265,6 +267,7 @@ test_exchange_api_rsa_LDADD = \ -lgnunetcurl \ -lgnunetutil \ -ljansson \ + -ltalerextensions \ $(XLIB) test_exchange_api_keys_cherry_picking_cs_SOURCES = \ diff --git a/src/testing/test_auditor_api.c b/src/testing/test_auditor_api.c index 38b1b1abe..9ab78664d 100644 --- a/src/testing/test_auditor_api.c +++ b/src/testing/test_auditor_api.c @@ -128,6 +128,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1", "create-reserve-1", "EUR:5", + 0, /* age restriction off */ MHD_HTTP_OK), TALER_TESTING_cmd_end () }; @@ -168,6 +169,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("refresh-withdraw-coin-1", "refresh-create-reserve-1", "EUR:5", + 0, /* age restriction off */ MHD_HTTP_OK), /** * Try to partially spend (deposit) 1 EUR of the 5 EUR coin (in @@ -315,6 +317,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-unaggregated", "create-reserve-unaggregated", "EUR:5", + 0, /* age restriction off */ MHD_HTTP_OK), TALER_TESTING_cmd_deposit ("deposit-unaggregated", "withdraw-coin-unaggregated", @@ -347,6 +350,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-r1", "create-reserve-r1", "EUR:5", + 0, /* age restriction off */ MHD_HTTP_OK), /** * Spend 5 EUR of the 5 EUR coin (in full). Merchant would @@ -402,6 +406,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-1", "recoup-create-reserve-1", "EUR:5", + 0, /* age restriction off */ MHD_HTTP_OK), TALER_TESTING_cmd_revoke ("revoke-1", MHD_HTTP_OK, @@ -417,6 +422,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2", "recoup-create-reserve-1", "EUR:1", + 0, /* age restriction off */ MHD_HTTP_OK), /** * These commands should close the reserve because the aggregator @@ -447,6 +453,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2a", "recoup-create-reserve-2", "EUR:1", + 0, /* age restriction off */ MHD_HTTP_OK), /** * Withdraw a 1 EUR coin, at fee of 1 ct @@ -454,6 +461,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2b", "recoup-create-reserve-2", "EUR:1", + 0, /* age restriction off */ MHD_HTTP_OK), TALER_TESTING_cmd_deposit ("recoup-deposit-partial", "recoup-withdraw-coin-2a", @@ -491,42 +499,52 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-1", "massive-reserve", "EUR:1", + 0, /* age restriction off */ MHD_HTTP_OK), TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-2", "massive-reserve", "EUR:1", + 0, /* age restriction off */ MHD_HTTP_OK), TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-3", "massive-reserve", "EUR:1", + 0, /* age restriction off */ MHD_HTTP_OK), TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-4", "massive-reserve", "EUR:1", + 0, /* age restriction off */ MHD_HTTP_OK), TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-5", "massive-reserve", "EUR:1", + 0, /* age restriction off */ MHD_HTTP_OK), TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-6", "massive-reserve", "EUR:1", + 0, /* age restriction off */ MHD_HTTP_OK), TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-7", "massive-reserve", "EUR:1", + 0, /* age restriction off */ MHD_HTTP_OK), TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-8", "massive-reserve", "EUR:1", + 0, /* age restriction off */ MHD_HTTP_OK), TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-9", "massive-reserve", "EUR:1", + 0, /* age restriction off */ MHD_HTTP_OK), TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-10", "massive-reserve", "EUR:1", + 0, /* age restriction off */ MHD_HTTP_OK), TALER_TESTING_cmd_deposit ( "massive-deposit-1", @@ -719,7 +737,7 @@ main (int argc, GNUNET_break (0); return 1; case GNUNET_NO: - return 77; + return 78; case GNUNET_OK: if (GNUNET_OK != /* Set up event loop and reschedule context, plus @@ -729,11 +747,11 @@ main (int argc, TALER_TESTING_auditor_setup (&run, NULL, config_file)) - return 1; + return 2; break; default: GNUNET_break (0); - return 1; + return 3; } return 0; } diff --git a/src/testing/test_exchange_api-cs.conf b/src/testing/test_exchange_api-cs.conf index 3fbf4c3c3..79332d648 100644 --- a/src/testing/test_exchange_api-cs.conf +++ b/src/testing/test_exchange_api-cs.conf @@ -149,7 +149,7 @@ fee_withdraw = EUR:0.00 fee_deposit = EUR:0.00 fee_refresh = EUR:0.01 fee_refund = EUR:0.01 -age_restricted = true +age_restricted = YES CIPHER = CS [coin_eur_ct_10_age_restricted] @@ -161,7 +161,7 @@ fee_withdraw = EUR:0.01 fee_deposit = EUR:0.01 fee_refresh = EUR:0.03 fee_refund = EUR:0.01 -age_restricted = true +age_restricted = YES CIPHER = CS [coin_eur_1_age_restricted] @@ -173,7 +173,7 @@ fee_withdraw = EUR:0.01 fee_deposit = EUR:0.01 fee_refresh = EUR:0.03 fee_refund = EUR:0.01 -age_restricted = true +age_restricted = YES CIPHER = CS [coin_eur_5_age_restricted] @@ -185,7 +185,7 @@ fee_withdraw = EUR:0.01 fee_deposit = EUR:0.01 fee_refresh = EUR:0.03 fee_refund = EUR:0.01 -age_restricted = true +age_restricted = YES CIPHER = CS [coin_eur_10_age_restricted] @@ -197,5 +197,5 @@ fee_withdraw = EUR:0.01 fee_deposit = EUR:0.01 fee_refresh = EUR:0.03 fee_refund = EUR:0.01 -age_restricted = true +age_restricted = YES CIPHER = CS diff --git a/src/testing/test_exchange_api-rsa.conf b/src/testing/test_exchange_api-rsa.conf index cffe3b87a..1d4456623 100644 --- a/src/testing/test_exchange_api-rsa.conf +++ b/src/testing/test_exchange_api-rsa.conf @@ -155,7 +155,7 @@ fee_deposit = EUR:0.00 fee_refresh = EUR:0.01 fee_refund = EUR:0.01 rsa_keysize = 1024 -age_restricted = true +age_restricted = YES CIPHER = RSA [coin_eur_ct_10_age_restricted] @@ -168,7 +168,7 @@ fee_deposit = EUR:0.01 fee_refresh = EUR:0.03 fee_refund = EUR:0.01 rsa_keysize = 1024 -age_restricted = true +age_restricted = YES CIPHER = RSA [coin_eur_1_age_restricted] @@ -181,7 +181,7 @@ fee_deposit = EUR:0.01 fee_refresh = EUR:0.03 fee_refund = EUR:0.01 rsa_keysize = 1024 -age_restricted = true +age_restricted = YES CIPHER = RSA [coin_eur_5_age_restricted] @@ -194,7 +194,7 @@ fee_deposit = EUR:0.01 fee_refresh = EUR:0.03 fee_refund = EUR:0.01 rsa_keysize = 1024 -age_restricted = true +age_restricted = YES CIPHER = RSA [coin_eur_10_age_restricted] @@ -207,5 +207,5 @@ fee_deposit = EUR:0.01 fee_refresh = EUR:0.03 fee_refund = EUR:0.01 rsa_keysize = 1024 -age_restricted = true +age_restricted = YES CIPHER = RSA diff --git a/src/testing/test_exchange_api.c b/src/testing/test_exchange_api.c index b1779a7d4..957e42e8a 100644 --- a/src/testing/test_exchange_api.c +++ b/src/testing/test_exchange_api.c @@ -34,6 +34,7 @@ #include "taler_bank_service.h" #include "taler_fakebank_lib.h" #include "taler_testing_lib.h" +#include "taler_extensions.h" /** * Configuration file we use. One (big) configuration is used @@ -149,6 +150,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1", "create-reserve-1", "EUR:5", + 0, /* age restriction off */ MHD_HTTP_OK), /** * Withdraw EUR:1 using the SAME private coin key as for the previous coin @@ -162,6 +164,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount_reuse_key ("withdraw-coin-1x", "create-reserve-1", "EUR:1", + 0, /* age restriction off */ "withdraw-coin-1", MHD_HTTP_OK), /** @@ -177,6 +180,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-2", "create-reserve-1", "EUR:5", + 0, /* age restriction off */ MHD_HTTP_CONFLICT), TALER_TESTING_cmd_end () }; @@ -282,6 +286,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("refresh-withdraw-coin-1", "refresh-create-reserve-1", "EUR:5", + 0, /* age restriction off */ MHD_HTTP_OK), /* Try to partially spend (deposit) 1 EUR of the 5 EUR coin * (in full) (merchant would receive EUR:0.99 due to 1 ct @@ -358,6 +363,61 @@ run (void *cls, TALER_TESTING_cmd_end () }; + /** + * Test withdrawal with age restriction. Success is expected, so it MUST be + * called _after_ TALER_TESTING_cmd_exec_offline_sign_extensions is called, + * i. e. age restriction is activated in the exchange! + * + * TODO: create a test that tries to withdraw coins with age restriction but + * (expectedly) fails because the exchange doesn't support age restriction + * yet. + */ + struct TALER_TESTING_Command withdraw_age[] = { + /** + * Move money to the exchange's bank account. + */ + CMD_TRANSFER_TO_EXCHANGE ("create-reserve-age", + "EUR:5.01"), + TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-age", + "EUR:5.01", + bc.user42_payto, + bc.exchange_payto, + "create-reserve-age"), + /** + * Make a reserve exist, according to the previous + * transfer. + */ + CMD_EXEC_WIREWATCH ("wirewatch-age"), + /** + * Withdraw EUR:5. + */ + TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-age-1", + "create-reserve-age", + "EUR:5", + 13, + MHD_HTTP_OK), + + TALER_TESTING_cmd_end () + }; + + struct TALER_TESTING_Command spend_age[] = { + /** + * Spend the coin. + */ + TALER_TESTING_cmd_deposit ("deposit-simple-age", + "withdraw-coin-age-1", + 0, + bc.user42_payto, + "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", + GNUNET_TIME_UNIT_ZERO, + "EUR:4.99", + MHD_HTTP_OK), + TALER_TESTING_cmd_deposit_replay ("deposit-simple-replay-age", + "deposit-simple-age", + MHD_HTTP_OK), + TALER_TESTING_cmd_end () + }; + struct TALER_TESTING_Command track[] = { /* Try resolving a deposit's WTID, as we never triggered * execution of transactions, the answer should be that @@ -400,6 +460,11 @@ run (void *cls, "EUR:4.98", bc.exchange_payto, bc.user42_payto), + TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-499c2", + ec.exchange_url, + "EUR:4.97", + bc.exchange_payto, + bc.user42_payto), TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c1", ec.exchange_url, "EUR:0.98", @@ -463,6 +528,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-unaggregated", "create-reserve-unaggregated", "EUR:5", + 0, /* age restriction off */ MHD_HTTP_OK), TALER_TESTING_cmd_deposit ("deposit-unaggregated", "withdraw-coin-unaggregated", @@ -501,6 +567,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-aggtest", "create-reserve-aggtest", "EUR:5", + 0, /* age restriction off */ MHD_HTTP_OK), TALER_TESTING_cmd_deposit ("deposit-aggtest-1", "withdraw-coin-aggtest", @@ -549,6 +616,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-r1", "create-reserve-r1", "EUR:5", + 0, /* age restriction off */ MHD_HTTP_OK), /** * Spend 5 EUR of the 5 EUR coin (in full) (merchant would @@ -649,6 +717,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-rb", "create-reserve-rb", "EUR:5", + 0, /* age restriction off */ MHD_HTTP_OK), TALER_TESTING_cmd_deposit ("deposit-refund-1b", "withdraw-coin-rb", @@ -698,11 +767,13 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-1", "recoup-create-reserve-1", "EUR:5", + 0, /* age restriction off */ MHD_HTTP_OK), /* Withdraw a 10 EUR coin, at fee of 1 ct */ TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-1b", "recoup-create-reserve-1", "EUR:10", + 0, /* age restriction off */ MHD_HTTP_OK), /* melt 10 EUR coin to get 5 EUR refreshed coin */ TALER_TESTING_cmd_melt ("recoup-melt-coin-1b", @@ -793,6 +864,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2", "recoup-create-reserve-1", "EUR:1", + 0, /* age restriction off */ MHD_HTTP_OK), /** * This withdrawal will test the logic to create a "recoup" @@ -801,6 +873,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2-over", "recoup-create-reserve-1", "EUR:10", + 0, /* age restriction off */ MHD_HTTP_CONFLICT), TALER_TESTING_cmd_status ("recoup-reserve-status-2", "recoup-create-reserve-1", @@ -833,6 +906,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("expired-withdraw", "short-lived-reserve", "EUR:1", + 0, /* age restriction off */ MHD_HTTP_CONFLICT), TALER_TESTING_cmd_check_bank_transfer ("check_bank_short-lived_reimburse", ec.exchange_url, @@ -857,11 +931,13 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2a", "recoup-create-reserve-2", "EUR:1", + 0, /* age restriction off */ MHD_HTTP_OK), /* Withdraw a 1 EUR coin, at fee of 1 ct */ TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2b", "recoup-create-reserve-2", "EUR:1", + 0, /* age restriction off */ MHD_HTTP_OK), TALER_TESTING_cmd_deposit ("recoup-deposit-partial", "recoup-withdraw-coin-2a", @@ -924,6 +1000,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-3-revoked", "recoup-create-reserve-3", "EUR:1", + 0, /* age restriction off */ MHD_HTTP_GONE), /* check that we are empty before the rejection test */ TALER_TESTING_cmd_check_bank_empty ("check-empty-again"), @@ -970,6 +1047,8 @@ run (void *cls, TALER_TESTING_cmd_auditor_add ("add-auditor-OK", MHD_HTTP_NO_CONTENT, false), + TALER_TESTING_cmd_exec_offline_sign_extensions ("offline-sign-extensions", + config_file), TALER_TESTING_cmd_wire_add ("add-wire-account", "payto://x-taler-bank/localhost/2", MHD_HTTP_NO_CONTENT, @@ -990,6 +1069,10 @@ run (void *cls, spend), TALER_TESTING_cmd_batch ("refresh", refresh), + TALER_TESTING_cmd_batch ("withdraw-age", + withdraw_age), + TALER_TESTING_cmd_batch ("spend-age", + spend_age), TALER_TESTING_cmd_batch ("track", track), TALER_TESTING_cmd_batch ("unaggregation", @@ -1026,6 +1109,9 @@ main (int argc, GNUNET_log_setup (argv[0], "INFO", NULL); + + TALER_extensions_init (); + cipher = GNUNET_TESTING_get_testname_from_underscore (argv[0]); GNUNET_assert (NULL != cipher); uses_cs = (0 == strcmp (cipher, "cs")); @@ -1036,6 +1122,7 @@ main (int argc, "test_exchange_api_expire_reserve_now-%s.conf", cipher); GNUNET_free (cipher); + /* Check fakebank port is available and get config */ if (GNUNET_OK != TALER_TESTING_prepare_fakebank (config_file, @@ -1054,7 +1141,7 @@ main (int argc, GNUNET_break (0); return 1; case GNUNET_NO: - return 77; + return 78; case GNUNET_OK: if (GNUNET_OK != /* Set up event loop and reschedule context, plus @@ -1064,11 +1151,11 @@ main (int argc, TALER_TESTING_setup_with_exchange (&run, NULL, config_file)) - return 1; + return 2; break; default: GNUNET_break (0); - return 1; + return 3; } return 0; } diff --git a/src/testing/test_exchange_api_revocation.c b/src/testing/test_exchange_api_revocation.c index beb94dbaf..bb3dcc06e 100644 --- a/src/testing/test_exchange_api_revocation.c +++ b/src/testing/test_exchange_api_revocation.c @@ -96,11 +96,13 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("withdraw-revocation-coin-1", "create-reserve-1", "EUR:5", + 0, /* age restriction off */ MHD_HTTP_OK), /* Withdraw another 5 EUR coin, at fee of 1 ct */ TALER_TESTING_cmd_withdraw_amount ("withdraw-revocation-coin-2", "create-reserve-1", "EUR:5", + 0, /* age restriction off */ MHD_HTTP_OK), /* Try to partially spend (deposit) 1 EUR of the 5 EUR coin (in full) * (merchant would receive EUR:0.99 due to 1 ct deposit fee) */// diff --git a/src/testing/test_kyc_api.c b/src/testing/test_kyc_api.c index b9e9a9f83..ca87edd83 100644 --- a/src/testing/test_kyc_api.c +++ b/src/testing/test_kyc_api.c @@ -105,10 +105,12 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1-no-kyc", "create-reserve-1", "EUR:10", + 0, /* age restriction off */ MHD_HTTP_ACCEPTED), TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1", "create-reserve-1", "EUR:5", + 0, /* age restriction off */ MHD_HTTP_OK), TALER_TESTING_cmd_end () }; @@ -120,6 +122,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1-lacking-kyc", "create-reserve-1", "EUR:5", + 0, /* age restriction off */ MHD_HTTP_ACCEPTED), TALER_TESTING_cmd_proof_kyc ("proof-kyc", "withdraw-coin-1-lacking-kyc", @@ -129,6 +132,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1-with-kyc", "create-reserve-1", "EUR:5", + 0, /* age restriction off */ MHD_HTTP_OK), TALER_TESTING_cmd_end () }; diff --git a/src/testing/testing_api_cmd_deposit.c b/src/testing/testing_api_cmd_deposit.c index b2fd7ddf1..d3fafc630 100644 --- a/src/testing/testing_api_cmd_deposit.c +++ b/src/testing/testing_api_cmd_deposit.c @@ -287,6 +287,8 @@ deposit_run (void *cls, const struct TALER_TESTING_Command *coin_cmd; const struct TALER_CoinSpendPrivateKeyP *coin_priv; struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_AgeCommitment *age_commitment = NULL; + struct TALER_AgeCommitmentHash h_age_commitment = {0}; const struct TALER_EXCHANGE_DenomPublicKey *denom_pub; const struct TALER_DenominationSignature *denom_pub_sig; struct TALER_CoinSpendSignatureP coin_sig; @@ -382,6 +384,10 @@ deposit_run (void *cls, TALER_TESTING_get_trait_coin_priv (coin_cmd, ds->coin_index, &coin_priv)) || + (GNUNET_OK != + TALER_TESTING_get_trait_age_commitment (coin_cmd, + ds->coin_index, + &age_commitment)) || (GNUNET_OK != TALER_TESTING_get_trait_denom_pub (coin_cmd, ds->coin_index, @@ -398,6 +404,12 @@ deposit_run (void *cls, TALER_TESTING_interpreter_fail (is); return; } + + if (NULL != age_commitment) + { + TALER_age_commitment_hash (age_commitment, &h_age_commitment); + } + ds->deposit_fee = denom_pub->fee_deposit; GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, &coin_pub.eddsa_pub); @@ -431,7 +443,8 @@ deposit_run (void *cls, &denom_pub->fee_deposit, &h_wire, &h_contract_terms, - NULL, /* FIXME: extension hash! */ + &h_age_commitment, + NULL, /* FIXME: add hash of extensions */ &denom_pub->h_key, ds->wallet_timestamp, &merchant_pub, @@ -445,7 +458,8 @@ deposit_run (void *cls, payto_uri, &wire_salt, &h_contract_terms, - NULL, /* FIXME: extension object */ + &h_age_commitment, + NULL, /* FIXME: add hash of extensions */ &coin_pub, denom_pub_sig, &denom_pub->key, @@ -520,6 +534,7 @@ deposit_traits (void *cls, const struct TALER_TESTING_Command *coin_cmd; /* Will point to coin cmd internals. */ const struct TALER_CoinSpendPrivateKeyP *coin_spent_priv; + struct TALER_AgeCommitment *age_commitment; if (GNUNET_YES != ds->command_initialized) { @@ -540,7 +555,11 @@ deposit_traits (void *cls, if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv (coin_cmd, ds->coin_index, - &coin_spent_priv)) + &coin_spent_priv) || + (GNUNET_OK != + TALER_TESTING_get_trait_age_commitment (coin_cmd, + ds->coin_index, + &age_commitment))) { GNUNET_break (0); TALER_TESTING_interpreter_fail (ds->is); @@ -555,6 +574,8 @@ deposit_traits (void *cls, /* These traits are always available */ TALER_TESTING_make_trait_coin_priv (0, coin_spent_priv), + TALER_TESTING_make_trait_age_commitment (0, + age_commitment), TALER_TESTING_make_trait_wire_details (ds->wire_details), TALER_TESTING_make_trait_contract_terms (ds->contract_terms), TALER_TESTING_make_trait_merchant_priv (&ds->merchant_priv), diff --git a/src/testing/testing_api_cmd_insert_deposit.c b/src/testing/testing_api_cmd_insert_deposit.c index be49df949..dcda7cf33 100644 --- a/src/testing/testing_api_cmd_insert_deposit.c +++ b/src/testing/testing_api_cmd_insert_deposit.c @@ -244,7 +244,7 @@ insert_deposit_run (void *cls, { uint64_t known_coin_id; struct TALER_DenominationHash dph; - struct TALER_AgeHash agh; + struct TALER_AgeCommitmentHash agh; if ( (GNUNET_OK != ids->dbc->plugin->start (ids->dbc->plugin->cls, diff --git a/src/testing/testing_api_cmd_offline_sign_extensions.c b/src/testing/testing_api_cmd_offline_sign_extensions.c new file mode 100644 index 000000000..f39679f97 --- /dev/null +++ b/src/testing/testing_api_cmd_offline_sign_extensions.c @@ -0,0 +1,164 @@ +/* + This file is part of TALER + Copyright (C) 2022 Taler Systems SA + + 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 Foundation; either version 3, or (at your + option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see +*/ + +/** + * @file testing/testing_api_cmd_offline_sign_extensions.c + * @brief run the taler-exchange-offline command to sign extensions (and therefore activate them) + * @author Özgür Kesim + */ +#include "platform.h" +#include "taler_json_lib.h" +#include +#include "taler_signatures.h" +#include "taler_testing_lib.h" + + +/** + * State for a "extensionssign" CMD. + */ +struct ExtensionsSignState +{ + + /** + * Process for the "extensionssign" command. + */ + struct GNUNET_OS_Process *extensionssign_proc; + + /** + * Configuration file used by the command. + */ + const char *config_filename; + +}; + + +/** + * Run the command; calls the `taler-exchange-offline' program. + * + * @param cls closure. + * @param cmd the commaind being run. + * @param is interpreter state. + */ +static void +extensionssign_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct ExtensionsSignState *ks = cls; + + ks->extensionssign_proc + = GNUNET_OS_start_process ( + GNUNET_OS_INHERIT_STD_ALL, + NULL, NULL, NULL, + "taler-exchange-offline", + "taler-exchange-offline", + "-c", ks->config_filename, + "-L", "INFO", + "extensions", + "sign", + "upload", + NULL); + if (NULL == ks->extensionssign_proc) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + TALER_TESTING_wait_for_sigchld (is); +} + + +/** + * Free the state of a "extensionssign" CMD, and possibly kills its + * process if it did not terminate correctly. + * + * @param cls closure. + * @param cmd the command being freed. + */ +static void +extensionssign_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct ExtensionsSignState *ks = cls; + + (void) cmd; + if (NULL != ks->extensionssign_proc) + { + GNUNET_break (0 == + GNUNET_OS_process_kill (ks->extensionssign_proc, + SIGKILL)); + GNUNET_OS_process_wait (ks->extensionssign_proc); + GNUNET_OS_process_destroy (ks->extensionssign_proc); + ks->extensionssign_proc = NULL; + } + GNUNET_free (ks); +} + + +/** + * Offer "extensionssign" CMD internal data to other commands. + * + * @param cls closure. + * @param[out] ret result + * @param trait name of the trait. + * @param index index number of the object to offer. + * @return #GNUNET_OK on success. + */ +static enum GNUNET_GenericReturnValue +extensionssign_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct ExtensionsSignState *ks = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_process (&ks->extensionssign_proc), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +struct TALER_TESTING_Command +TALER_TESTING_cmd_exec_offline_sign_extensions (const char *label, + const char *config_filename) +{ + struct ExtensionsSignState *ks; + + ks = GNUNET_new (struct ExtensionsSignState); + ks->config_filename = config_filename; + { + struct TALER_TESTING_Command cmd = { + .cls = ks, + .label = label, + .run = &extensionssign_run, + .cleanup = &extensionssign_cleanup, + .traits = &extensionssign_traits + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_exec_offline_sign_extensions.c */ diff --git a/src/testing/testing_api_cmd_refresh.c b/src/testing/testing_api_cmd_refresh.c index de3efd13b..11c88c19c 100644 --- a/src/testing/testing_api_cmd_refresh.c +++ b/src/testing/testing_api_cmd_refresh.c @@ -70,6 +70,11 @@ struct TALER_TESTING_FreshCoinData */ struct TALER_CoinSpendPrivateKeyP coin_priv; + /* + * Age commitment for the coin, NULL if not applicable. + */ + struct TALER_AgeCommitment *age_commitment; + /** * The blinding key (needed for recoup operations). */ @@ -132,6 +137,11 @@ struct RefreshMeltState */ const struct TALER_CoinSpendPrivateKeyP *melt_priv; + /* + * Age commitment for the coin, NULL if not applicable. + */ + struct TALER_AgeCommitment *age_commitment; + /** * Task scheduled to try later. */ @@ -1038,6 +1048,7 @@ melt_run (void *cls, const struct TALER_DenominationSignature *melt_sig; const struct TALER_EXCHANGE_DenomPublicKey *melt_denom_pub; const struct TALER_TESTING_Command *coin_command; + bool age_restricted; if (NULL == (coin_command = TALER_TESTING_interpreter_lookup_command ( @@ -1058,6 +1069,16 @@ melt_run (void *cls, TALER_TESTING_interpreter_fail (rms->is); return; } + if (GNUNET_OK != + TALER_TESTING_get_trait_age_commitment (coin_command, + 0, + &rms->age_commitment)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (rms->is); + return; + } + if (GNUNET_OK != TALER_TESTING_get_trait_denom_sig (coin_command, 0, @@ -1067,6 +1088,7 @@ melt_run (void *cls, TALER_TESTING_interpreter_fail (rms->is); return; } + if (GNUNET_OK != TALER_TESTING_get_trait_denom_pub (coin_command, 0, @@ -1076,9 +1098,11 @@ melt_run (void *cls, TALER_TESTING_interpreter_fail (rms->is); return; } + /* Melt amount starts with the melt fee of the old coin; we'll add the values and withdraw fees of the fresh coins next */ melt_amount = melt_denom_pub->fee_refresh; + age_restricted = melt_denom_pub->key.age_mask.mask != 0; for (unsigned int i = 0; iexchange), - &fresh_amount); + &fresh_amount, + age_restricted); if (NULL == fresh_pk) { GNUNET_break (0); @@ -1117,12 +1142,36 @@ melt_run (void *cls, TALER_denom_pub_deep_copy (&rms->fresh_pks[i].key, &fresh_pk->key); } /* end for */ + rms->refresh_data.melt_priv = *rms->melt_priv; rms->refresh_data.melt_amount = melt_amount; rms->refresh_data.melt_sig = *melt_sig; rms->refresh_data.melt_pk = *melt_denom_pub; rms->refresh_data.fresh_pks = rms->fresh_pks; rms->refresh_data.fresh_pks_len = num_fresh_coins; +/* FIXME-oec: is this needed _here_? + { + struct TALER_AgeCommitment *ac = NULL; + + GNUNET_assert (age_restricted == (NULL != rms->age_commitment)); + + if (NULL != rms->age_commitment) + { + uint32_t seed = GNUNET_CRYPTO_random_u32 ( + GNUNET_CRYPTO_QUALITY_WEAK, + UINT32_MAX); + + GNUNET_assert (GNUNET_OK == + TALER_age_commitment_derive ( + rms->age_commitment, + seed, + ac)); + } + + rms->refresh_data.age_commitment = ac + } +*/ + rms->rmh = TALER_EXCHANGE_melt (is->exchange, &rms->rms, &rms->refresh_data, @@ -1207,6 +1256,8 @@ melt_traits (void *cls, &rms->fresh_pks[index]), TALER_TESTING_make_trait_coin_priv (0, rms->melt_priv), + TALER_TESTING_make_trait_age_commitment (index, + rms->age_commitment), TALER_TESTING_make_trait_exchange_wd_value (index, &rms->mbds[index].alg_value), TALER_TESTING_make_trait_refresh_secret (&rms->rms), @@ -1370,6 +1421,9 @@ refresh_reveal_traits (void *cls, TALER_TESTING_make_trait_coin_priv ( index, &rrs->fresh_coins[index].coin_priv), + TALER_TESTING_make_trait_age_commitment ( + index, + rrs->fresh_coins[index].age_commitment), TALER_TESTING_make_trait_denom_pub ( index, rrs->fresh_coins[index].pk), diff --git a/src/testing/testing_api_cmd_withdraw.c b/src/testing/testing_api_cmd_withdraw.c index c7265c6cd..e5e8adfd5 100644 --- a/src/testing/testing_api_cmd_withdraw.c +++ b/src/testing/testing_api_cmd_withdraw.c @@ -27,6 +27,7 @@ #include #include #include "taler_signatures.h" +#include "taler_extensions.h" #include "taler_testing_lib.h" #include "backoff.h" @@ -131,6 +132,18 @@ struct WithdrawState */ struct TALER_PlanchetMasterSecretP ps; + /** + * An age > 0 signifies age restriction is required + */ + uint8_t age; + + /** + * If age > 0, put here the corresponding age commitment and its hash, + * respectivelly, NULL otherwise. + */ + struct TALER_AgeCommitment *age_commitment; + struct TALER_AgeCommitmentHash *h_age_commitment; + /** * Reserve history entry that corresponds to this operation. * Will be of type #TALER_EXCHANGE_RTT_WITHDRAWAL. @@ -382,12 +395,14 @@ withdraw_run (void *cls, = TALER_TESTING_interpreter_lookup_command ( is, ws->reserve_reference); + if (NULL == create_reserve) { GNUNET_break (0); TALER_TESTING_interpreter_fail (is); return; } + if (GNUNET_OK != TALER_TESTING_get_trait_reserve_priv (create_reserve, &rp)) @@ -396,6 +411,7 @@ withdraw_run (void *cls, TALER_TESTING_interpreter_fail (is); return; } + if (NULL == ws->exchange_url) ws->exchange_url = GNUNET_strdup (TALER_EXCHANGE_get_base_url (is->exchange)); @@ -405,6 +421,7 @@ withdraw_run (void *cls, ws->reserve_payto_uri = TALER_payto_from_reserve (ws->exchange_url, &ws->reserve_pub); + if (NULL == ws->reuse_coin_key_ref) { TALER_planchet_master_setup_random (&ws->ps); @@ -429,10 +446,12 @@ withdraw_run (void *cls, &ps)); ws->ps = *ps; } + if (NULL == ws->pk) { dpk = TALER_TESTING_find_pk (TALER_EXCHANGE_get_keys (is->exchange), - &ws->amount); + &ws->amount, + ws->age > 0); if (NULL == dpk) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, @@ -450,18 +469,24 @@ withdraw_run (void *cls, { ws->amount = ws->pk->value; } + ws->reserve_history.type = TALER_EXCHANGE_RTT_WITHDRAWAL; GNUNET_assert (0 <= TALER_amount_add (&ws->reserve_history.amount, &ws->amount, &ws->pk->fee_withdraw)); ws->reserve_history.details.withdraw.fee = ws->pk->fee_withdraw; - ws->wsh = TALER_EXCHANGE_withdraw (is->exchange, - ws->pk, - rp, - &ws->ps, - &reserve_withdraw_cb, - ws); + + { + + ws->wsh = TALER_EXCHANGE_withdraw (is->exchange, + ws->pk, + rp, + &ws->ps, + ws->h_age_commitment, + &reserve_withdraw_cb, + ws); + } if (NULL == ws->wsh) { GNUNET_break (0); @@ -503,6 +528,16 @@ withdraw_cleanup (void *cls, TALER_EXCHANGE_destroy_denomination_key (ws->pk); ws->pk = NULL; } + if (NULL != ws->age_commitment) + { + GNUNET_free (ws->age_commitment); + ws->age_commitment = NULL; + } + if (NULL != ws->h_age_commitment) + { + GNUNET_free (ws->h_age_commitment); + ws->h_age_commitment = NULL; + } GNUNET_free (ws->exchange_url); GNUNET_free (ws->reserve_payto_uri); GNUNET_free (ws); @@ -538,7 +573,7 @@ withdraw_traits (void *cls, &ws->exchange_vals), TALER_TESTING_make_trait_denom_pub (0 /* only one coin */, ws->pk), - TALER_TESTING_make_trait_denom_sig (0 /* only one coin */, + TALER_TESTING_make_trait_denom_sig (index /* only one coin */, &ws->sig), TALER_TESTING_make_trait_reserve_priv (&ws->reserve_priv), TALER_TESTING_make_trait_reserve_pub (&ws->reserve_pub), @@ -548,6 +583,8 @@ withdraw_traits (void *cls, (const char **) &ws->reserve_payto_uri), TALER_TESTING_make_trait_exchange_url ( (const char **) &ws->exchange_url), + TALER_TESTING_make_trait_age_commitment (index, ws->age_commitment), + TALER_TESTING_make_trait_h_age_commitment (index, ws->h_age_commitment), TALER_TESTING_trait_end () }; @@ -567,6 +604,7 @@ withdraw_traits (void *cls, * @param label command label. * @param reserve_reference command providing us with a reserve to withdraw from * @param amount how much we withdraw. + * @param age if > 0, age restriction is activated * @param expected_response_code which HTTP response code * we expect from the exchange. * @return the withdraw command to be executed by the interpreter. @@ -575,11 +613,45 @@ struct TALER_TESTING_Command TALER_TESTING_cmd_withdraw_amount (const char *label, const char *reserve_reference, const char *amount, + const uint8_t age, unsigned int expected_response_code) { struct WithdrawState *ws; ws = GNUNET_new (struct WithdrawState); + + ws->age = age; + if (0 < age) + { + struct TALER_AgeCommitment *ac; + struct TALER_AgeCommitmentHash *hac; + uint32_t seed; + struct TALER_AgeMask mask; + + ac = GNUNET_new (struct TALER_AgeCommitment); + hac = GNUNET_new (struct TALER_AgeCommitmentHash); + seed = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); + mask = TALER_extensions_age_restriction_ageMask (); + + if (GNUNET_OK != + TALER_age_restriction_commit ( + &mask, + age, + seed, + ac)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to generate age commitment for age %d at %s\n", + age, + label); + GNUNET_assert (0); + } + + TALER_age_commitment_hash (ac,hac); + ws->age_commitment = ac; + ws->h_age_commitment = hac; + } + ws->reserve_reference = reserve_reference; if (GNUNET_OK != TALER_string_to_amount (amount, @@ -615,6 +687,7 @@ TALER_TESTING_cmd_withdraw_amount (const char *label, * @param label command label. * @param reserve_reference command providing us with a reserve to withdraw from * @param amount how much we withdraw. + * @param age if > 0, age restriction is activated * @param coin_ref reference to (withdraw/reveal) command of a coin * from which we should re-use the private key * @param expected_response_code which HTTP response code @@ -626,6 +699,7 @@ TALER_TESTING_cmd_withdraw_amount_reuse_key ( const char *label, const char *reserve_reference, const char *amount, + uint8_t age, const char *coin_ref, unsigned int expected_response_code) { @@ -634,6 +708,7 @@ TALER_TESTING_cmd_withdraw_amount_reuse_key ( cmd = TALER_TESTING_cmd_withdraw_amount (label, reserve_reference, amount, + age, expected_response_code); { struct WithdrawState *ws = cmd.cls; diff --git a/src/testing/testing_api_helpers_exchange.c b/src/testing/testing_api_helpers_exchange.c index 8e0e0298f..1eecbfeb3 100644 --- a/src/testing/testing_api_helpers_exchange.c +++ b/src/testing/testing_api_helpers_exchange.c @@ -27,6 +27,7 @@ #include "taler_json_lib.h" #include #include "taler_signatures.h" +#include "taler_extensions.h" #include "taler_testing_lib.h" /** @@ -312,6 +313,9 @@ sign_keys_for_exchange (void *cls, char *exchange_master_pub; int ret; + /* Load the age restriction mask from the configuration */ + TALER_extensions_load_taler_config (cfg); + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "exchange", @@ -402,7 +406,8 @@ TALER_TESTING_prepare_exchange (const char *config_filename, const struct TALER_EXCHANGE_DenomPublicKey * TALER_TESTING_find_pk (const struct TALER_EXCHANGE_Keys *keys, - const struct TALER_Amount *amount) + const struct TALER_Amount *amount, + bool age_restricted) { struct GNUNET_TIME_Timestamp now; struct TALER_EXCHANGE_DenomPublicKey *pk; @@ -419,7 +424,8 @@ TALER_TESTING_find_pk (const struct TALER_EXCHANGE_Keys *keys, pk->valid_from)) && (GNUNET_TIME_timestamp_cmp (now, <, - pk->withdraw_valid_until)) ) + pk->withdraw_valid_until)) && + (age_restricted == (0 != pk->key.age_mask.mask)) ) return pk; } /* do 2nd pass to check if expiration times are to blame for @@ -435,7 +441,8 @@ TALER_TESTING_find_pk (const struct TALER_EXCHANGE_Keys *keys, pk->valid_from) || GNUNET_TIME_timestamp_cmp (now, >, - pk->withdraw_valid_until) ) ) + pk->withdraw_valid_until) ) && + (age_restricted == (0 != pk->key.age_mask.mask)) ) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -- cgit v1.2.3