diff options
author | Christian Grothoff <christian@grothoff.org> | 2023-09-23 19:28:13 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2023-09-23 19:28:13 +0200 |
commit | 4c220dce4d5ef33e00e937e236a744324af9dcf0 (patch) | |
tree | efbea85cb7026da7479ce3e190c03cc05ab15aa3 | |
parent | 493f8fdc92265f421878e805a4dc4ab5b9a6038d (diff) |
fix online denomination signatures; thanks to Jonathan Krebs for pointing out the issue
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | debian/changelog | 6 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_keys.c | 375 | ||||
-rw-r--r-- | src/include/taler_crypto_lib.h | 6 | ||||
-rw-r--r-- | src/json/json_helper.c | 2 | ||||
-rw-r--r-- | src/lib/exchange_api_handle.c | 218 |
6 files changed, 414 insertions, 195 deletions
diff --git a/configure.ac b/configure.ac index fc08c5f0a..e86d21424 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ # # AC_PREREQ([2.69]) -AC_INIT([taler-exchange],[0.9.2],[taler-bug@gnunet.org]) +AC_INIT([taler-exchange],[0.9.3],[taler-bug@gnunet.org]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_SRCDIR([src/util/util.c]) AC_CONFIG_HEADERS([taler_config.h]) diff --git a/debian/changelog b/debian/changelog index f0e914e43..401827f01 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +taler-exchange (0.9.3-1) unstable; urgency=low + + * Actual v0.9.3 release. + + -- Christian Grothoff <grothoff@gnu.org> Wed, 27 Sep 2023 03:50:12 +0200 + taler-exchange (0.9.3) unstable; urgency=low * First work towards packaging v0.9.3. diff --git a/src/exchange/taler-exchange-httpd_keys.c b/src/exchange/taler-exchange-httpd_keys.c index b9194d894..12d50a811 100644 --- a/src/exchange/taler-exchange-httpd_keys.c +++ b/src/exchange/taler-exchange-httpd_keys.c @@ -2412,7 +2412,6 @@ wallet_threshold_cb (void *cls, * @param[in,out] signkeys list of sign keys to return * @param[in,out] recoup list of revoked keys to return * @param[in,out] grouped_denominations list of grouped denominations to return - * @param h_grouped XOR of all hashes in @a grouped_demoninations * @return #GNUNET_OK on success */ static enum GNUNET_GenericReturnValue @@ -2421,14 +2420,11 @@ create_krd (struct TEH_KeyStateHandle *ksh, struct GNUNET_TIME_Timestamp last_cherry_pick_date, json_t *signkeys, json_t *recoup, - json_t *grouped_denominations, - const struct GNUNET_HashCode *h_grouped) + json_t *grouped_denominations) { struct KeysResponseData krd; struct TALER_ExchangePublicKeyP exchange_pub; struct TALER_ExchangeSignatureP exchange_sig; - struct TALER_ExchangePublicKeyP grouped_exchange_pub; - struct TALER_ExchangeSignatureP grouped_exchange_sig; struct WireStateHandle *wsh; json_t *keys; @@ -2443,14 +2439,14 @@ create_krd (struct TEH_KeyStateHandle *ksh, GNUNET_assert (NULL != signkeys); GNUNET_assert (NULL != recoup); GNUNET_assert (NULL != grouped_denominations); - GNUNET_assert (NULL != h_grouped); GNUNET_assert (NULL != ksh->auditors); GNUNET_assert (NULL != TEH_currency); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Creating /keys at cherry pick date %s\n", GNUNET_TIME_timestamp2s (last_cherry_pick_date)); - /* Sign hash over denomination keys */ + /* Sign hash over master signatures of all denomination keys until this time + (in reverse order). */ { enum TALER_ErrorCode ec; @@ -2471,33 +2467,6 @@ create_krd (struct TEH_KeyStateHandle *ksh, } } - /* Sign grouped hash */ - { - enum TALER_ErrorCode ec; - - if (TALER_EC_NONE != - (ec = - TALER_exchange_online_key_set_sign ( - &TEH_keys_exchange_sign2_, - ksh, - last_cherry_pick_date, - h_grouped, - &grouped_exchange_pub, - &grouped_exchange_sig))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Could not create key response data: cannot sign grouped hash (%s)\n", - TALER_ErrorCode_get_hint (ec)); - return GNUNET_SYSERR; - } - } - - /* both public keys really must be the same */ - GNUNET_assert (0 == - memcmp (&grouped_exchange_pub, - &exchange_pub, - sizeof(exchange_pub))); - { const struct SigningKey *sk; @@ -2559,12 +2528,10 @@ create_krd (struct TEH_KeyStateHandle *ksh, ksh->global_fees), GNUNET_JSON_pack_timestamp ("list_issue_date", last_cherry_pick_date), - GNUNET_JSON_pack_data_auto ("eddsa_pub", + GNUNET_JSON_pack_data_auto ("exchange_pub", &exchange_pub), - GNUNET_JSON_pack_data_auto ("eddsa_sig", - &exchange_sig), - GNUNET_JSON_pack_data_auto ("denominations_sig", - &grouped_exchange_sig)); + GNUNET_JSON_pack_data_auto ("exchange_sig", + &exchange_sig)); GNUNET_assert (NULL != keys); /* Set wallet limit if KYC is configured */ @@ -2733,6 +2700,194 @@ create_krd (struct TEH_KeyStateHandle *ksh, /** + * Element in the `struct SignatureContext` array. + */ +struct SignatureElement +{ + + /** + * Offset of the denomination in the group array, + * for sorting (2nd rank, ascending). + */ + unsigned int offset; + + /** + * Offset of the group in the denominations array, + * for sorting (2nd rank, ascending). + */ + unsigned int group_offset; + + /** + * Pointer to actual master signature to hash over. + */ + struct TALER_MasterSignatureP master_sig; +}; + +/** + * Context for collecting the array of master signatures + * needed to verify the exchange_sig online signature. + */ +struct SignatureContext +{ + /** + * Array of signatures to hash over. + */ + struct SignatureElement *elements; + + /** + * Write offset in the @e elements array. + */ + unsigned int elements_pos; + + /** + * Allocated space for @e elements. + */ + unsigned int elements_size; +}; + + +/** + * Determine order to sort two elements by before + * we hash the master signatures. Used for + * sorting with qsort(). + * + * @param a pointer to a `struct SignatureElement` + * @param b pointer to a `struct SignatureElement` + * @return 0 if equal, -1 if a < b, 1 if a > b. + */ +static int +signature_context_sort_cb (const void *a, + const void *b) +{ + const struct SignatureElement *sa = a; + const struct SignatureElement *sb = b; + + if (sa->group_offset < sb->group_offset) + return -1; + if (sa->group_offset > sb->group_offset) + return 1; + if (sa->offset < sb->offset) + return -1; + if (sa->offset > sb->offset) + return 1; + /* We should never have two disjoint elements + with same time and offset */ + GNUNET_assert (sa == sb); + return 0; +} + + +/** + * Append a @a master_sig to the @a sig_ctx using the + * given attributes for (later) sorting. + * + * @param[in,out] sig_ctx signature context to update + * @param group_offset offset for the group + * @param offset offset for the entry + * @param master_sig master signature for the entry + */ +static void +append_signature (struct SignatureContext *sig_ctx, + unsigned int group_offset, + unsigned int offset, + const struct TALER_MasterSignatureP *master_sig) +{ + struct SignatureElement *element; + unsigned int new_size; + + if (sig_ctx->elements_pos == sig_ctx->elements_size) + { + if (0 == sig_ctx->elements_size) + new_size = 1024; + else + new_size = sig_ctx->elements_size; + GNUNET_array_grow (sig_ctx->elements, + sig_ctx->elements_size, + new_size); + } + element = &sig_ctx->elements[sig_ctx->elements_pos++]; + element->offset = offset; + element->group_offset = group_offset; + element->master_sig = *master_sig; +} + + +/** + *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; + + /** + * List of denominations for the group, + * included in @e json, do not free separately! + */ + json_t *list; + + /** + * Offset of the group in the final array. + */ + unsigned int group_off; + +}; + + +/** + * Helper function called to clean up the group data + * in the denominations_by_group below. + * + * @param cls unused + * @param key unused + * @param value a `struct GroupData` to free + * @return #GNUNET_OK + */ +static int +free_group (void *cls, + const struct GNUNET_HashCode *key, + void *value) +{ + struct GroupData *gd = value; + + (void) cls; + (void) key; + GNUNET_free (gd); + return GNUNET_OK; +} + + +static void +compute_msig_hash (struct SignatureContext *sig_ctx, + struct GNUNET_HashCode *hc) +{ + struct GNUNET_HashContext *hash_context; + + hash_context = GNUNET_CRYPTO_hash_context_start (); + qsort (sig_ctx->elements, + sig_ctx->elements_pos, + sizeof (struct SignatureElement), + &signature_context_sort_cb); + for (unsigned int i = 0; i<sig_ctx->elements_pos; i++) + { + struct SignatureElement *element = &sig_ctx->elements[i]; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Adding %u,%u,%s\n", + element->group_offset, + element->offset, + TALER_B2S (&element->master_sig)); + GNUNET_CRYPTO_hash_context_read (hash_context, + &element->master_sig, + sizeof (element->master_sig)); + } + GNUNET_CRYPTO_hash_context_finish (hash_context, + hc); +} + + +/** * Update the "/keys" responses in @a ksh, computing the detailed replies. * * This function is to recompute all (including cherry-picked) responses we @@ -2750,8 +2905,7 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh) json_t *grouped_denominations = NULL; struct GNUNET_TIME_Timestamp last_cherry_pick_date; struct GNUNET_CONTAINER_Heap *heap; - struct GNUNET_HashContext *hash_context = NULL; - struct GNUNET_HashCode grouped_hash_xor = {0}; + struct SignatureContext sig_ctx = { 0 }; /* Remember if we have any denomination with age restriction */ bool has_age_restricted_denomination = false; @@ -2779,39 +2933,19 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh) sctx.min_sk_frequency); } - hash_context = GNUNET_CRYPTO_hash_context_start (); - grouped_denominations = json_array (); GNUNET_assert (NULL != grouped_denominations); last_cherry_pick_date = GNUNET_TIME_UNIT_ZERO_TS; - // FIXME: This block contains the implementation of the DEPRECATED - // "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; - /* 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 = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_NO /* NO, because keys are only on the stack */); - - - /* heap = min heap, sorted by start time */ + /* heap = max heap, sorted by start time */ while (NULL != (dk = GNUNET_CONTAINER_heap_remove_root (heap))) { if (GNUNET_TIME_timestamp_cmp (last_cherry_pick_date, @@ -2826,23 +2960,19 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh) */ struct GNUNET_HashCode hc; - GNUNET_CRYPTO_hash_context_finish ( - GNUNET_CRYPTO_hash_context_copy (hash_context), - &hc); - + compute_msig_hash (&sig_ctx, + &hc); if (GNUNET_OK != create_krd (ksh, &hc, last_cherry_pick_date, sctx.signkeys, recoup, - grouped_denominations, - &grouped_hash_xor)) + grouped_denominations)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to generate key response data for %s\n", GNUNET_TIME_timestamp2s (last_cherry_pick_date)); - GNUNET_CRYPTO_hash_context_abort (hash_context); /* drain heap before destroying it */ while (NULL != (dk = GNUNET_CONTAINER_heap_remove_root (heap))) /* intentionally empty */; @@ -2860,9 +2990,7 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh) * denominations_by_group. */ { - static const char *denoms_key = "denoms"; struct GroupData *group; - json_t *list; json_t *entry; struct GNUNET_HashCode key; struct TALER_DenominationGroup meta = { @@ -2896,35 +3024,36 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh) default: GNUNET_assert (false); } - + /* Create a new array for the denominations in this group */ + group->list = json_array (); + GNUNET_assert (NULL != group->list); group->json = GNUNET_JSON_PACK ( GNUNET_JSON_pack_string ("cipher", cipher), + GNUNET_JSON_pack_array_steal ("denoms", + group->list), TALER_JSON_PACK_DENOM_FEES ("fee", &meta.fees), TALER_JSON_pack_amount ("value", &meta.value)); GNUNET_assert (NULL != group->json); - if (age_restricted) { - int r = json_object_set_new (group->json, - "age_mask", - json_integer (meta.age_mask.bits)); - - GNUNET_assert (0 == r); - + GNUNET_assert ( + 0 == + json_object_set_new (group->json, + "age_mask", + json_integer ( + meta.age_mask.bits))); /* Remember that we have found at least _one_ age restricted denomination */ has_age_restricted_denomination = true; } - - /* Create a new array for the denominations in this group */ - list = json_array (); - GNUNET_assert (NULL != list); + group->group_off + = json_array_size (grouped_denominations); GNUNET_assert (0 == - json_object_set_new (group->json, - denoms_key, - list)); + json_array_append_new ( + grouped_denominations, + group->json)); GNUNET_assert ( GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (denominations_by_group, @@ -2989,62 +3118,24 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh) GNUNET_assert (NULL != entry); } - /* Build up the running xor of all hashes of the denominations in this - group */ - GNUNET_CRYPTO_hash_xor (&dk->h_denom_pub.hash, - &group->hash_xor, - &group->hash_xor); - + /* Build up the running hash of all master signatures of the + denominations */ + append_signature (&sig_ctx, + group->group_off, + (unsigned int) json_array_size (group->list), + &dk->master_sig); /* Finally, add the denomination to the list of denominations in this group */ - list = json_object_get (group->json, denoms_key); - GNUNET_assert (NULL != list); - GNUNET_assert (true == json_is_array (list)); + GNUNET_assert (json_is_array (group->list)); GNUNET_assert (0 == - json_array_append_new (list, entry)); + json_array_append_new (group->list, + entry)); } } /* loop over heap ends */ - /* Create the JSON-array of grouped denominations */ - if (0 < - GNUNET_CONTAINER_multihashmap_size (denominations_by_group)) - { - struct GNUNET_CONTAINER_MultiHashMapIterator *iter; - struct GroupData *group = NULL; - - iter = - GNUNET_CONTAINER_multihashmap_iterator_create (denominations_by_group); - - while (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_iterator_next (iter, - NULL, - (const - void **) &group)) - { - /* Add the XOR over all hashes of denominations in this group to the group */ - GNUNET_assert (0 == - json_object_set_new ( - group->json, - "hash", - GNUNET_JSON_PACK ( - 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); - } - GNUNET_CONTAINER_multihashmap_iterator_destroy (iter); - - } - + GNUNET_CONTAINER_multihashmap_iterate (denominations_by_group, + &free_group, + NULL); GNUNET_CONTAINER_multihashmap_destroy (denominations_by_group); } @@ -3053,16 +3144,15 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh) { struct GNUNET_HashCode hc; - GNUNET_CRYPTO_hash_context_finish (hash_context, - &hc); + compute_msig_hash (&sig_ctx, + &hc); if (GNUNET_OK != create_krd (ksh, &hc, last_cherry_pick_date, sctx.signkeys, recoup, - grouped_denominations, - &grouped_hash_xor)) + grouped_denominations)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to generate key response data for %s\n", @@ -3090,12 +3180,13 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "No denomination keys available. Refusing to generate /keys response.\n"); - GNUNET_CRYPTO_hash_context_abort (hash_context); } - ret = GNUNET_OK; CLEANUP: + GNUNET_array_grow (sig_ctx.elements, + sig_ctx.elements_size, + 0); json_decref (grouped_denominations); json_decref (sctx.signkeys); json_decref (recoup); diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h index dfce91cdb..ffb48285f 100644 --- a/src/include/taler_crypto_lib.h +++ b/src/include/taler_crypto_lib.h @@ -6044,12 +6044,6 @@ struct TALER_DenominationGroup { /** - * XOR of all SHA-512 hashes of the public keys in this - * group. - */ - struct GNUNET_HashCode hash; - - /** * Value of coins in this denomination group. */ struct TALER_Amount value; diff --git a/src/json/json_helper.c b/src/json/json_helper.c index 9d7df0900..ab1ce7876 100644 --- a/src/json/json_helper.c +++ b/src/json/json_helper.c @@ -266,8 +266,6 @@ 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 5562936fd..6009b7c10 100644 --- a/src/lib/exchange_api_handle.c +++ b/src/lib/exchange_api_handle.c @@ -84,7 +84,7 @@ struct TALER_EXCHANGE_GetKeysHandle { /** - * The exchange base URL (i.e. "http://exchange.taler.net/") + * The exchange base URL (i.e. "https://exchange.demo.taler.net/") */ char *exchange_url; @@ -124,6 +124,119 @@ struct TALER_EXCHANGE_GetKeysHandle /** + * Element in the `struct SignatureContext` array. + */ +struct SignatureElement +{ + + /** + * Offset of the denomination in the group array, + * for sorting (2nd rank, ascending). + */ + unsigned int offset; + + /** + * Offset of the group in the denominations array, + * for sorting (2nd rank, ascending). + */ + unsigned int group_offset; + + /** + * Pointer to actual master signature to hash over. + */ + struct TALER_MasterSignatureP master_sig; +}; + +/** + * Context for collecting the array of master signatures + * needed to verify the exchange_sig online signature. + */ +struct SignatureContext +{ + /** + * Array of signatures to hash over. + */ + struct SignatureElement *elements; + + /** + * Write offset in the @e elements array. + */ + unsigned int elements_pos; + + /** + * Allocated space for @e elements. + */ + unsigned int elements_size; +}; + + +/** + * Determine order to sort two elements by before + * we hash the master signatures. Used for + * sorting with qsort(). + * + * @param a pointer to a `struct SignatureElement` + * @param b pointer to a `struct SignatureElement` + * @return 0 if equal, -1 if a < b, 1 if a > b. + */ +static int +signature_context_sort_cb (const void *a, + const void *b) +{ + const struct SignatureElement *sa = a; + const struct SignatureElement *sb = b; + + if (sa->group_offset < sb->group_offset) + return -1; + if (sa->group_offset > sb->group_offset) + return 1; + if (sa->offset < sb->offset) + return -1; + if (sa->offset > sb->offset) + return 1; + /* We should never have two disjoint elements + with same time and offset */ + GNUNET_assert (sa == sb); + return 0; +} + + +/** + * Append a @a master_sig to the @a sig_ctx using the + * given attributes for (later) sorting. + * + * @param[in,out] sig_ctx signature context to update + * @param group_offset offset for the group + * @param offset offset for the entry + * @param master_sig master signature for the entry + */ +static void +append_signature (struct SignatureContext *sig_ctx, + unsigned int group_offset, + unsigned int offset, + const struct TALER_MasterSignatureP *master_sig) +{ + struct SignatureElement *element; + unsigned int new_size; + + if (sig_ctx->elements_pos == sig_ctx->elements_size) + { + if (0 == sig_ctx->elements_size) + new_size = 1024; + else + new_size = sig_ctx->elements_size; + GNUNET_array_grow (sig_ctx->elements, + sig_ctx->elements_size, + new_size); + } + element = &sig_ctx->elements[sig_ctx->elements_pos++]; + element->offset = offset; + element->group_offset = group_offset; + element->master_sig = *master_sig; +} + + +/** * Frees @a wfm array. * * @param wfm fee array to release @@ -335,7 +448,10 @@ parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key, * @param check_sigs should we check signatures? * @param denom_key_obj json to parse * @param master_key master key to use to verify signature - * @param[in,out] hash_xor where to accumulate data for signature verification via XOR + * @param group_offset offset for the group + * @param index index of this denomination key in the group + * @param sig_ctx where to write details about encountered + * master signatures, NULL if not used * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is * invalid or the json malformed. */ @@ -346,7 +462,9 @@ parse_json_denomkey_partially ( bool check_sigs, const json_t *denom_key_obj, struct TALER_MasterPublicKeyP *master_key, - struct GNUNET_HashCode *hash_xor) + unsigned int group_offset, + unsigned int index, + struct SignatureContext *sig_ctx) { struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("master_sig", @@ -379,10 +497,11 @@ parse_json_denomkey_partially ( } TALER_denom_pub_hash (&denom_key->key, &denom_key->h_key); - if (NULL != hash_xor) - GNUNET_CRYPTO_hash_xor (&denom_key->h_key.hash, - hash_xor, - hash_xor); + if (NULL != sig_ctx) + append_signature (sig_ctx, + group_offset, + index, + &denom_key->master_sig); if (! check_sigs) return GNUNET_OK; EXITIF (GNUNET_SYSERR == @@ -644,9 +763,8 @@ decode_keys_json (const json_t *resp_obj, struct TALER_EXCHANGE_Keys *key_data, enum TALER_EXCHANGE_VersionCompatibility *vc) { - struct TALER_ExchangeSignatureP denominations_sig; - struct GNUNET_HashCode hash_xor = {0}; - struct TALER_ExchangePublicKeyP pub; + struct TALER_ExchangeSignatureP exchange_sig; + struct TALER_ExchangePublicKeyP exchange_pub; const json_t *wblwk = NULL; const json_t *global_fees; const json_t *sign_keys_array; @@ -659,6 +777,7 @@ decode_keys_json (const json_t *resp_obj, const json_t *accounts; const json_t *fees; const json_t *wads; + struct SignatureContext sig_ctx = { 0 }; if (JSON_OBJECT != json_typeof (resp_obj)) { @@ -722,11 +841,11 @@ decode_keys_json (const json_t *resp_obj, const char *asset_type; struct GNUNET_JSON_Specification mspec[] = { GNUNET_JSON_spec_fixed_auto ( - "denominations_sig", - &denominations_sig), + "exchange_sig", + &exchange_sig), GNUNET_JSON_spec_fixed_auto ( - "eddsa_pub", - &pub), + "exchange_pub", + &exchange_pub), GNUNET_JSON_spec_fixed_auto ( "master_public_key", &key_data->master_pub), @@ -959,13 +1078,10 @@ decode_keys_json (const json_t *resp_obj, json_t *group_obj; unsigned int group_idx; - json_array_foreach (denominations_by_group, group_idx, group_obj) + json_array_foreach (denominations_by_group, + group_idx, + group_obj) { - /* 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 = {0}; @@ -988,7 +1104,9 @@ decode_keys_json (const json_t *resp_obj, NULL)); /* Now, parse the individual denominations */ - json_array_foreach (denom_keys_array, index, denom_key_obj) + json_array_foreach (denom_keys_array, + index, + denom_key_obj) { /* Set the common fields from the group for this particular denomination. Required to make the validity check inside @@ -1007,12 +1125,11 @@ decode_keys_json (const json_t *resp_obj, check_sig, denom_key_obj, &key_data->master_pub, - check_sig ? &hash_xor : NULL)); - - /* Build the running xor of the SHA512-hash of the public keys for the group */ - GNUNET_CRYPTO_hash_xor (&dk.h_key.hash, - &group_hash_xor, - &group_hash_xor); + group_idx, + index, + check_sig + ? &sig_ctx + : NULL)); for (unsigned int j = 0; j<key_data->num_denom_keys; j++) @@ -1046,13 +1163,6 @@ decode_keys_json (const json_t *resp_obj, = GNUNET_TIME_timestamp_max (key_data->last_denom_issue_date, dk.valid_from); }; /* end of 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)); - } /* end of json_array_foreach over groups of denominations */ } /* end of scope for group_ojb/group_idx */ @@ -1162,15 +1272,41 @@ decode_keys_json (const json_t *resp_obj, if (check_sig) { + struct GNUNET_HashContext *hash_context; + struct GNUNET_HashCode hc; + + hash_context = GNUNET_CRYPTO_hash_context_start (); + qsort (sig_ctx.elements, + sig_ctx.elements_pos, + sizeof (struct SignatureElement), + &signature_context_sort_cb); + for (unsigned int i = 0; i<sig_ctx.elements_pos; i++) + { + struct SignatureElement *element = &sig_ctx.elements[i]; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Adding %u,%u,%s\n", + element->group_offset, + element->offset, + TALER_B2S (&element->master_sig)); + GNUNET_CRYPTO_hash_context_read (hash_context, + &element->master_sig, + sizeof (element->master_sig)); + } + GNUNET_array_grow (sig_ctx.elements, + sig_ctx.elements_size, + 0); + GNUNET_CRYPTO_hash_context_finish (hash_context, + &hc); EXITIF (GNUNET_OK != TALER_EXCHANGE_test_signing_key (key_data, - &pub)); + &exchange_pub)); EXITIF (GNUNET_OK != TALER_exchange_online_key_set_verify ( key_data->list_issue_date, - &hash_xor, - &pub, - &denominations_sig)); + &hc, + &exchange_pub, + &exchange_sig)); } return GNUNET_OK; @@ -1853,8 +1989,6 @@ add_grp (void *cls, } ge = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_data_auto ("hash", - &gd->meta.hash), GNUNET_JSON_pack_string ("cipher", cipher), GNUNET_JSON_pack_array_steal ("denoms", @@ -2023,10 +2157,6 @@ TALER_EXCHANGE_keys_to_json (const struct TALER_EXCHANGE_Keys *kd) GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); } - /* Build the running xor of the SHA512-hash of the public keys */ - GNUNET_CRYPTO_hash_xor (&dk->h_key.hash, - &gd->meta.hash, - &gd->meta.hash); switch (meta.cipher) { case TALER_DENOMINATION_RSA: |