From a6544069f98fdbfce4ac215dd5f0ee0660469c2c Mon Sep 17 00:00:00 2001 From: Özgür Kesim Date: Mon, 27 Jun 2022 10:10:51 +0200 Subject: [new /keys response] added proper hash verification - Running XOR of all SHA-512 hashes of each denomination's public key is compared against the "hash" value in the JSON blob. - Fixed a bug during creation of the running XOR. --- src/exchange/taler-exchange-httpd_keys.c | 36 ++++++++++++---------- src/include/taler_json_lib.h | 9 ++++-- src/json/json_helper.c | 2 ++ src/lib/exchange_api_handle.c | 52 +++++++++++++++++++++++--------- 4 files changed, 66 insertions(+), 33 deletions(-) diff --git a/src/exchange/taler-exchange-httpd_keys.c b/src/exchange/taler-exchange-httpd_keys.c index de5f1fbc9..ee80dcf9e 100644 --- a/src/exchange/taler-exchange-httpd_keys.c +++ b/src/exchange/taler-exchange-httpd_keys.c @@ -2068,24 +2068,27 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh) last_cpd = GNUNET_TIME_UNIT_ZERO_TS; + // FIXME: This block contains the implementation of the DEPRICATED + // "denom_pubs" array along with the new grouped "denominations". + // "denom_pubs" Will be removed sooner or later. { struct TEH_DenominationKey *dk; struct GNUNET_CONTAINER_MultiHashMap *denominations_by_group; - - denominations_by_group = - GNUNET_CONTAINER_multihashmap_create (1024, - GNUNET_NO /* NO, because keys are only on the stack */); - - /* groupData is the value we store for each group meta-data */ + // groupData is the value we store for each group meta-data struct groupData { - /* The json blob with the group meta-data and list of denominations */ + // The json blob with the group meta-data and list of denominations json_t *json; - /* xor of all hashes of denominations in that group */ + // xor of all hashes of denominations in that group struct GNUNET_HashCode hash_xor; }; + denominations_by_group = + GNUNET_CONTAINER_multihashmap_create (1024, + GNUNET_NO /* NO, because keys are only on the stack */); + + /* heap = min heap, sorted by start time */ while (NULL != (dk = GNUNET_CONTAINER_heap_remove_root (heap))) { @@ -2113,7 +2116,6 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh) recoup, denoms, grouped_denominations, - &grouped_hash_xor)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, @@ -2318,24 +2320,26 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh) (const void **) &group)) { - struct GNUNET_HashCode hc; - - GNUNET_CRYPTO_hash_xor (&group->hash_xor, - &grouped_hash_xor, - &grouped_hash_xor); - + // Add the XOR over all hashes of denominations in this group to the group GNUNET_assert (0 == json_object_set ( group->json, "hash", GNUNET_JSON_PACK ( - GNUNET_JSON_pack_data_auto (NULL, &hc)))); + GNUNET_JSON_pack_data_auto (NULL, + &group->hash_xor)))); + // Add this group to the array GNUNET_assert (0 == json_array_append_new ( grouped_denominations, group->json)); + // Build the running XOR over all hash(_xor) + GNUNET_CRYPTO_hash_xor (&group->hash_xor, + &grouped_hash_xor, + &grouped_hash_xor); + GNUNET_free (group); } diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h index f0b105e98..0b58b43d1 100644 --- a/src/include/taler_json_lib.h +++ b/src/include/taler_json_lib.h @@ -370,12 +370,17 @@ TALER_JSON_spec_amount_any_nbo (const char *name, **/ struct TALER_DenominationGroup { - /* currency must be set prior to calling TALER_JSON_spec_denomination_group */ - const char *currency; enum TALER_DenominationCipher cipher; struct TALER_Amount value; struct TALER_DenomFeeSet fees; struct TALER_AgeMask age_mask; + + // currency must be set prior to calling TALER_JSON_spec_denomination_group + const char *currency; + + // hash is/should be the XOR of all SHA-512 hashes of the public keys in this + // group + struct GNUNET_HashCode hash; }; /** diff --git a/src/json/json_helper.c b/src/json/json_helper.c index 9752bb9f8..b29a49b3a 100644 --- a/src/json/json_helper.c +++ b/src/json/json_helper.c @@ -265,6 +265,8 @@ parse_denomination_group (void *cls, GNUNET_JSON_spec_uint32 ("age_mask", &group->age_mask.bits), &age_mask_missing), + GNUNET_JSON_spec_fixed_auto ("hash", + &group->hash), GNUNET_JSON_spec_end () }; const char *emsg; diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c index be7bb3c39..c690c352e 100644 --- a/src/lib/exchange_api_handle.c +++ b/src/lib/exchange_api_handle.c @@ -924,8 +924,13 @@ decode_keys_json (const json_t *resp_obj, key_data->age_mask = TALER_extensions_age_restriction_ageMask (); } - /* parse the denomination keys, merging with the - possibly EXISTING array as required (/keys cherry picking) */ + /** + * Parse the denomination keys, merging with the + * possibly EXISTING array as required (/keys cherry picking). + * + * The denominations are grouped by common values of + * {cipher, value, fee, age_mask}. + **/ { json_t *denominations_by_group; json_t *group_obj; @@ -940,23 +945,25 @@ decode_keys_json (const json_t *resp_obj, json_typeof (denominations_by_group)); json_array_foreach (denominations_by_group, group_idx, group_obj) { - /* First, parse { cipher, fees, value, age_mask } of the current group */ - - struct TALER_DenominationGroup group = { - .currency = currency - }; + // Running XOR of each SHA512 hash of the denominations' public key in + // this group. Used to compare against group.hash after all keys have + // been parsed. + struct GNUNET_HashCode group_hash_xor = {0}; + + // First, parse { cipher, fees, value, age_mask, hash } of the current + // group. + struct TALER_DenominationGroup group = { .currency = currency }; struct GNUNET_JSON_Specification group_spec[] = { TALER_JSON_spec_denomination_group (NULL, &group), GNUNET_JSON_spec_end () }; - EXITIF (GNUNET_SYSERR == GNUNET_JSON_parse (group_obj, group_spec, NULL, NULL)); - /* Now, parse the individual denominations */ + // Now, parse the individual denominations { json_t *denom_keys_array; json_t *denom_key_obj; @@ -970,9 +977,9 @@ decode_keys_json (const json_t *resp_obj, memset (&dk, 0, sizeof (dk)); - /* Set the common fields from the group for this particular - * denomination. Required to make the validity check inside - * parse_json_denomkey_partially pass */ + // Set the common fields from the group for this particular + // denomination. Required to make the validity check inside + // parse_json_denomkey_partially pass dk.key.cipher = group.cipher; dk.value = group.value; dk.fees = group.fees; @@ -987,6 +994,15 @@ decode_keys_json (const json_t *resp_obj, &key_data->master_pub, check_sig ? &hash_xor: NULL)); + // Build the running xor of the SHA512-hash of the public keys + { + struct TALER_DenominationHashP hc = {0}; + TALER_denom_pub_hash (&dk.key, &hc); + GNUNET_CRYPTO_hash_xor (&hc.hash, + &group_hash_xor, + &group_hash_xor); + } + for (unsigned int j = 0; jnum_denom_keys; j++) @@ -1019,9 +1035,15 @@ decode_keys_json (const json_t *resp_obj, key_data->last_denom_issue_date = GNUNET_TIME_timestamp_max (key_data->last_denom_issue_date, dk.valid_from); - } - }; - }; + }; // json_array_foreach over denominations + + // The calculated group_hash_xor must be the same as group.hash from + // the json. + EXITIF (0 != + GNUNET_CRYPTO_hash_cmp (&group_hash_xor, &group.hash)); + + } // block for parsing individual denominations + }; // json_array_foreach over groups of denominations } /* parse the auditor information */ -- cgit v1.2.3