[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.
This commit is contained in:
Özgür Kesim 2022-06-27 10:10:51 +02:00
parent a55fc45126
commit a6544069f9
Signed by: oec
GPG Key ID: 3D76A56D79EDD9D7
4 changed files with 66 additions and 33 deletions

View File

@ -2068,23 +2068,26 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
last_cpd = GNUNET_TIME_UNIT_ZERO_TS; 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 TEH_DenominationKey *dk;
struct GNUNET_CONTAINER_MultiHashMap *denominations_by_group; struct GNUNET_CONTAINER_MultiHashMap *denominations_by_group;
// 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
json_t *json;
// xor of all hashes of denominations in that group
struct GNUNET_HashCode hash_xor;
};
denominations_by_group = denominations_by_group =
GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_CONTAINER_multihashmap_create (1024,
GNUNET_NO /* NO, because keys are only on the stack */); GNUNET_NO /* NO, because keys are only on the stack */);
/* 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 */
json_t *json;
/* xor of all hashes of denominations in that group */
struct GNUNET_HashCode hash_xor;
};
/* heap = min heap, sorted by start time */ /* heap = min heap, sorted by start time */
while (NULL != (dk = GNUNET_CONTAINER_heap_remove_root (heap))) while (NULL != (dk = GNUNET_CONTAINER_heap_remove_root (heap)))
@ -2113,7 +2116,6 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
recoup, recoup,
denoms, denoms,
grouped_denominations, grouped_denominations,
&grouped_hash_xor)) &grouped_hash_xor))
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
@ -2318,24 +2320,26 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
(const (const
void **) &group)) void **) &group))
{ {
struct GNUNET_HashCode hc; // Add the XOR over all hashes of denominations in this group to the group
GNUNET_CRYPTO_hash_xor (&group->hash_xor,
&grouped_hash_xor,
&grouped_hash_xor);
GNUNET_assert (0 == GNUNET_assert (0 ==
json_object_set ( json_object_set (
group->json, group->json,
"hash", "hash",
GNUNET_JSON_PACK ( 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 == GNUNET_assert (0 ==
json_array_append_new ( json_array_append_new (
grouped_denominations, grouped_denominations,
group->json)); 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); GNUNET_free (group);
} }

View File

@ -370,12 +370,17 @@ TALER_JSON_spec_amount_any_nbo (const char *name,
**/ **/
struct TALER_DenominationGroup struct TALER_DenominationGroup
{ {
/* currency must be set prior to calling TALER_JSON_spec_denomination_group */
const char *currency;
enum TALER_DenominationCipher cipher; enum TALER_DenominationCipher cipher;
struct TALER_Amount value; struct TALER_Amount value;
struct TALER_DenomFeeSet fees; struct TALER_DenomFeeSet fees;
struct TALER_AgeMask age_mask; 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;
}; };
/** /**

View File

@ -265,6 +265,8 @@ parse_denomination_group (void *cls,
GNUNET_JSON_spec_uint32 ("age_mask", GNUNET_JSON_spec_uint32 ("age_mask",
&group->age_mask.bits), &group->age_mask.bits),
&age_mask_missing), &age_mask_missing),
GNUNET_JSON_spec_fixed_auto ("hash",
&group->hash),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
const char *emsg; const char *emsg;

View File

@ -924,8 +924,13 @@ decode_keys_json (const json_t *resp_obj,
key_data->age_mask = TALER_extensions_age_restriction_ageMask (); 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 *denominations_by_group;
json_t *group_obj; json_t *group_obj;
@ -940,23 +945,25 @@ decode_keys_json (const json_t *resp_obj,
json_typeof (denominations_by_group)); json_typeof (denominations_by_group));
json_array_foreach (denominations_by_group, group_idx, group_obj) { json_array_foreach (denominations_by_group, group_idx, group_obj) {
/* First, parse { cipher, fees, value, age_mask } of the current group */ // 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};
struct TALER_DenominationGroup group = { // First, parse { cipher, fees, value, age_mask, hash } of the current
.currency = currency // group.
}; struct TALER_DenominationGroup group = { .currency = currency };
struct GNUNET_JSON_Specification group_spec[] = { struct GNUNET_JSON_Specification group_spec[] = {
TALER_JSON_spec_denomination_group (NULL, &group), TALER_JSON_spec_denomination_group (NULL, &group),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
EXITIF (GNUNET_SYSERR == EXITIF (GNUNET_SYSERR ==
GNUNET_JSON_parse (group_obj, GNUNET_JSON_parse (group_obj,
group_spec, group_spec,
NULL, NULL,
NULL)); NULL));
/* Now, parse the individual denominations */ // Now, parse the individual denominations
{ {
json_t *denom_keys_array; json_t *denom_keys_array;
json_t *denom_key_obj; json_t *denom_key_obj;
@ -970,9 +977,9 @@ decode_keys_json (const json_t *resp_obj,
memset (&dk, 0, sizeof (dk)); memset (&dk, 0, sizeof (dk));
/* Set the common fields from the group for this particular // Set the common fields from the group for this particular
* denomination. Required to make the validity check inside // denomination. Required to make the validity check inside
* parse_json_denomkey_partially pass */ // parse_json_denomkey_partially pass
dk.key.cipher = group.cipher; dk.key.cipher = group.cipher;
dk.value = group.value; dk.value = group.value;
dk.fees = group.fees; dk.fees = group.fees;
@ -987,6 +994,15 @@ decode_keys_json (const json_t *resp_obj,
&key_data->master_pub, &key_data->master_pub,
check_sig ? &hash_xor: NULL)); 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; for (unsigned int j = 0;
j<key_data->num_denom_keys; j<key_data->num_denom_keys;
j++) j++)
@ -1019,9 +1035,15 @@ decode_keys_json (const json_t *resp_obj,
key_data->last_denom_issue_date key_data->last_denom_issue_date
= GNUNET_TIME_timestamp_max (key_data->last_denom_issue_date, = GNUNET_TIME_timestamp_max (key_data->last_denom_issue_date,
dk.valid_from); 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 */ /* parse the auditor information */