From 1b1a6c142ac60698d80d2a3151f73190c987768e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96zg=C3=BCr=20Kesim?= Date: Tue, 8 Feb 2022 00:00:24 +0100 Subject: [PATCH] [WIP] hash and signature verification of /keys works again - 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 So far: test_exchange_api runs, including withdraw_age! However, test_auditor_api fails and another is in a endless loop! --- .../taler-exchange-httpd_extensions.c | 6 +++ src/exchange/taler-exchange-httpd_keys.c | 52 +++++++++++++++---- src/lib/exchange_api_handle.c | 40 ++++++++++---- src/lib/exchange_api_refresh_common.c | 2 + src/testing/testing_api_cmd_withdraw.c | 2 + 5 files changed, 81 insertions(+), 21 deletions(-) diff --git a/src/exchange/taler-exchange-httpd_extensions.c b/src/exchange/taler-exchange-httpd_extensions.c index 8edb24d40..e46fc1b45 100644 --- a/src/exchange/taler-exchange-httpd_extensions.c +++ b/src/exchange/taler-exchange-httpd_extensions.c @@ -157,6 +157,12 @@ TEH_extensions_init () it = it->next) extension_update_event_cb (NULL, &it->type, sizeof(it->type)); + /* FIXME: shall we load the extensions from the config right away? + * We do have to for now, as otherwise denominations with age restriction + * will not have the age mask set right upon initial generation. + */ + TALER_extensions_load_taler_config (TEH_cfg); + return GNUNET_OK; } diff --git a/src/exchange/taler-exchange-httpd_keys.c b/src/exchange/taler-exchange-httpd_keys.c index 28d4e8745..2696a6bc6 100644 --- a/src/exchange/taler-exchange-httpd_keys.c +++ b/src/exchange/taler-exchange-httpd_keys.c @@ -1590,7 +1590,7 @@ setup_general_response_headers (struct TEH_KeyStateHandle *ksh, * @a recoup and @a denoms. * * @param[in,out] ksh key state handle we build @a krd for - * @param[in] denom_keys_hash hash over all the denominatoin keys in @a denoms + * @param[in] denom_keys_hash hash over all the denominatoin keys in @a denoms and age_restricted_denoms * @param last_cpd timestamp to use * @param signkeys list of sign keys to return * @param recoup list of revoked keys to return @@ -1846,9 +1846,11 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh) json_t *age_restricted_denoms = NULL; struct GNUNET_TIME_Timestamp last_cpd; struct GNUNET_CONTAINER_Heap *heap; - struct GNUNET_HashContext *hash_context; + struct GNUNET_HashContext *hash_context = NULL; + struct GNUNET_HashContext *hash_context_restricted = NULL; bool age_restriction_active = TALER_extensions_is_enabled_type (TALER_Extension_AgeRestriction); + bool have_age_restricted_denoms = false; sctx.signkeys = json_array (); GNUNET_assert (NULL != sctx.signkeys); @@ -1873,19 +1875,24 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh) = GNUNET_TIME_relative_min (dkc.min_dk_frequency, sctx.min_sk_frequency); } + denoms = json_array (); GNUNET_assert (NULL != denoms); + hash_context = GNUNET_CRYPTO_hash_context_start (); - // If age restriction is enabled, initialize the array of age restricted denoms. - /* TODO: optimize by putting this into global? */ + /* If age restriction is enabled, initialize the array of age restricted + denoms and prepare a hash for them, separate from the others. We will join + those hashes afterwards.*/ if (age_restriction_active) { age_restricted_denoms = json_array (); GNUNET_assert (NULL != age_restricted_denoms); + + hash_context_restricted = GNUNET_CRYPTO_hash_context_start (); } last_cpd = GNUNET_TIME_UNIT_ZERO_TS; - hash_context = GNUNET_CRYPTO_hash_context_start (); + { struct TEH_DenominationKey *dk; @@ -1927,14 +1934,14 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh) return GNUNET_SYSERR; } } + last_cpd = dk->meta.start; - GNUNET_CRYPTO_hash_context_read (hash_context, - &dk->h_denom_pub, - sizeof (struct GNUNET_HashCode)); { json_t *denom; json_t *array; + struct GNUNET_HashContext *hc; + denom = GNUNET_JSON_PACK ( @@ -1961,13 +1968,25 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh) TALER_JSON_pack_amount ("fee_refund", &dk->meta.fee_refund)); - /* Put the denom into the correct array - denoms or age_restricted_denoms - - * depending on the settings and the properties of the denomination */ + /* Put the denom into the correct array depending on the settings and + * the properties of the denomination. Also, we build up the right + * hash for the corresponding array. */ if (age_restriction_active && (0 != dk->denom_pub.age_mask.mask)) + { + have_age_restricted_denoms = true; array = age_restricted_denoms; + hc = hash_context_restricted; + } else + { array = denoms; + hc = hash_context; + } + + GNUNET_CRYPTO_hash_context_read (hc, + &dk->h_denom_pub, + sizeof (struct GNUNET_HashCode)); GNUNET_assert ( 0 == @@ -1983,8 +2002,21 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh) { struct GNUNET_HashCode hc; + /* If age restriction is active and we had at least one denomination of + * that sort, we simply add the hash of all age restricted denominations at + * the end of the others. */ + if (age_restriction_active && have_age_restricted_denoms) + { + struct GNUNET_HashCode hcr; + GNUNET_CRYPTO_hash_context_finish (hash_context_restricted, &hcr); + GNUNET_CRYPTO_hash_context_read (hash_context, + &hcr, + sizeof (struct GNUNET_HashCode)); + } + GNUNET_CRYPTO_hash_context_finish (hash_context, &hc); + if (GNUNET_OK != create_krd (ksh, &hc, diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c index 8d8e71c4d..41656a61d 100644 --- a/src/lib/exchange_api_handle.c +++ b/src/lib/exchange_api_handle.c @@ -67,7 +67,7 @@ /** * Set to 1 for extra debug logging. */ -#define DEBUG 1 /* FIXME-oec */ +#define DEBUG 0 /** * Log error related to CURL operations. @@ -364,9 +364,6 @@ parse_json_denomkey (struct TALER_EXCHANGE_DenomPublicKey *denom_key, sizeof (struct GNUNET_HashCode)); if (! check_sigs) return GNUNET_OK; - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "XXXXX checking validity of %s with age_mask %d\n", GNUNET_h2s ( - &denom_key->h_key.hash), denom_key->key.age_mask.mask); EXITIF (GNUNET_SYSERR == TALER_exchange_offline_denom_validity_verify ( &denom_key->h_key, @@ -381,8 +378,6 @@ parse_json_denomkey (struct TALER_EXCHANGE_DenomPublicKey *denom_key, &denom_key->fee_refund, master_key, &denom_key->master_sig)); - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "XXXXX validity of %s OK\n", - GNUNET_h2s (&denom_key->h_key.hash)); return GNUNET_OK; EXITIF_exit: /* invalidate denom_key, just to be sure */ @@ -672,7 +667,9 @@ decode_keys_json (const json_t *resp_obj, enum TALER_EXCHANGE_VersionCompatibility *vc) { struct TALER_ExchangeSignatureP sig; - struct GNUNET_HashContext *hash_context; + struct GNUNET_HashContext *hash_context = NULL; + struct GNUNET_HashContext *hash_context_restricted = NULL; + bool have_age_restricted_denom = false; struct TALER_ExchangePublicKeyP pub; const char *currency; struct GNUNET_JSON_Specification mspec[] = { @@ -751,7 +748,6 @@ decode_keys_json (const json_t *resp_obj, key_data->version = GNUNET_strdup (ver); } - hash_context = NULL; EXITIF (GNUNET_OK != GNUNET_JSON_parse (resp_obj, (check_sig) ? mspec : &mspec[2], @@ -771,7 +767,10 @@ decode_keys_json (const json_t *resp_obj, /* parse the master public key and issue date of the response */ if (check_sig) + { hash_context = GNUNET_CRYPTO_hash_context_start (); + hash_context_restricted = GNUNET_CRYPTO_hash_context_start (); + } /* parse the signing keys */ { @@ -847,10 +846,15 @@ decode_keys_json (const json_t *resp_obj, */ struct { char *name; + struct GNUNET_HashContext *hc; bool is_optional_age_restriction;} hive[2] = { - { "denoms", false }, - { "age_restricted_denoms", true } + { "denoms", + hash_context, + false }, + { "age_restricted_denoms", + hash_context_restricted, + true } }; for (size_t s = 0; s < sizeof(hive) / sizeof(hive[0]); s++) @@ -881,6 +885,8 @@ decode_keys_json (const json_t *resp_obj, struct TALER_EXCHANGE_DenomPublicKey dk; bool found = false; + have_age_restricted_denom = true; + memset (&dk, 0, sizeof (dk)); @@ -889,7 +895,7 @@ decode_keys_json (const json_t *resp_obj, check_sig, denom_key_obj, &key_data->master_pub, - hash_context)); + hive[s].hc)); /* Mark age restriction according where we got this denomination from, * "denoms" or "age_restricted_denoms" */ @@ -1057,6 +1063,18 @@ decode_keys_json (const json_t *resp_obj, .list_issue_date = GNUNET_TIME_timestamp_hton (key_data->list_issue_date) }; + /* If we had any age restricted denominations, add their hash to the end of + * the normal denominations. */ + if (have_age_restricted_denom) + { + struct GNUNET_HashCode hcr; + GNUNET_CRYPTO_hash_context_finish (hash_context_restricted, + &hcr); + GNUNET_CRYPTO_hash_context_read (hash_context, + &hcr, + sizeof(struct GNUNET_HashCode)); + } + GNUNET_CRYPTO_hash_context_finish (hash_context, &ks.hc); hash_context = NULL; diff --git a/src/lib/exchange_api_refresh_common.c b/src/lib/exchange_api_refresh_common.c index 7b5d467a9..ece9fe94f 100644 --- a/src/lib/exchange_api_refresh_common.c +++ b/src/lib/exchange_api_refresh_common.c @@ -355,6 +355,7 @@ TALER_EXCHANGE_refresh_prepare ( struct MeltData md; json_t *ret; struct TALER_Amount total; + struct TALER_AgeCommitmentHash ach = {0}; struct TALER_CoinSpendPublicKeyP coin_pub; struct TALER_TransferSecretP trans_sec[TALER_CNC_KAPPA]; struct TALER_RefreshCommitmentEntry rce[TALER_CNC_KAPPA]; @@ -372,6 +373,7 @@ TALER_EXCHANGE_refresh_prepare ( md.melted_coin.original_value = melt_pk->value; md.melted_coin.expire_deposit = melt_pk->expire_deposit; + md.melted_coin.h_age_commitment = ach; TALER_age_commitment_hash (age_commitment, &md.melted_coin.h_age_commitment); diff --git a/src/testing/testing_api_cmd_withdraw.c b/src/testing/testing_api_cmd_withdraw.c index ebffaadc5..bd65f4f27 100644 --- a/src/testing/testing_api_cmd_withdraw.c +++ b/src/testing/testing_api_cmd_withdraw.c @@ -470,6 +470,8 @@ withdraw_run (void *cls, ac)); ws->age_commitment = ac; + ws->h_age_commitment = GNUNET_malloc (sizeof(struct + TALER_AgeCommitmentHash)); TALER_age_commitment_hash ( ac, ws->h_age_commitment);