summaryrefslogtreecommitdiff
path: root/src/exchange/taler-exchange-httpd_keys.c
diff options
context:
space:
mode:
authorÖzgür Kesim <oec-taler@kesim.org>2022-06-22 21:01:30 +0200
committerÖzgür Kesim <oec-taler@kesim.org>2022-06-23 18:19:45 +0200
commitc165ef31fee97df950081437ebf7484e1b4764ad (patch)
tree5255122bd1e019d2ca03865db709d9cc342e1643 /src/exchange/taler-exchange-httpd_keys.c
parentbdd81674cfb17dc0171f1ef08a3a313723a1a4e2 (diff)
downloadexchange-c165ef31fee97df950081437ebf7484e1b4764ad.tar.gz
exchange-c165ef31fee97df950081437ebf7484e1b4764ad.tar.bz2
exchange-c165ef31fee97df950081437ebf7484e1b4764ad.zip
first steps towards new /keys response: grouped denominations added
Diffstat (limited to 'src/exchange/taler-exchange-httpd_keys.c')
-rw-r--r--src/exchange/taler-exchange-httpd_keys.c321
1 files changed, 241 insertions, 80 deletions
diff --git a/src/exchange/taler-exchange-httpd_keys.c b/src/exchange/taler-exchange-httpd_keys.c
index b3f0eb489..45bed1a19 100644
--- a/src/exchange/taler-exchange-httpd_keys.c
+++ b/src/exchange/taler-exchange-httpd_keys.c
@@ -283,7 +283,6 @@ struct SigningKey
};
-
struct TEH_KeyStateHandle
{
@@ -404,7 +403,6 @@ struct SuspendedKeysRequests
struct GNUNET_TIME_Absolute timeout;
};
-
/**
* Stores the latest generation of our key state.
*/
@@ -1353,7 +1351,7 @@ denomination_info_cb (
dk->meta = *meta;
dk->master_sig = *master_sig;
dk->recoup_possible = recoup_possible;
- dk->denom_pub.age_mask = meta->age_mask;
+ dk->denom_pub.age_mask = meta->age_mask; /* FIXME-oec: age_mask -> reserved_field */
GNUNET_assert (
GNUNET_OK ==
@@ -1361,6 +1359,7 @@ denomination_info_cb (
&dk->h_denom_pub.hash,
dk,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+
}
@@ -1727,12 +1726,12 @@ 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 and age_restricted_denoms
+ * @param[in] denom_keys_hash hash over all the denominatoin keys in @a denoms
* @param last_cpd timestamp to use
* @param signkeys list of sign keys to return
* @param recoup list of revoked keys to return
* @param denoms list of denominations to return
- * @param age_restricted_denoms list of age restricted denominations to return, can be NULL
+ * @param grouped_denominations list of grouped denominations to return
* @return #GNUNET_OK on success
*/
static enum GNUNET_GenericReturnValue
@@ -1742,7 +1741,7 @@ create_krd (struct TEH_KeyStateHandle *ksh,
json_t *signkeys,
json_t *recoup,
json_t *denoms,
- json_t *age_restricted_denoms)
+ json_t *grouped_denominations)
{
struct KeysResponseData krd;
struct TALER_ExchangePublicKeyP exchange_pub;
@@ -1753,6 +1752,7 @@ create_krd (struct TEH_KeyStateHandle *ksh,
GNUNET_assert (NULL != signkeys);
GNUNET_assert (NULL != recoup);
GNUNET_assert (NULL != denoms);
+ GNUNET_assert (NULL != grouped_denominations);
GNUNET_assert (NULL != ksh->auditors);
GNUNET_assert (NULL != TEH_currency);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -1778,6 +1778,7 @@ create_krd (struct TEH_KeyStateHandle *ksh,
return GNUNET_SYSERR;
}
}
+
{
const struct SigningKey *sk;
@@ -1803,6 +1804,8 @@ create_krd (struct TEH_KeyStateHandle *ksh,
recoup),
GNUNET_JSON_pack_array_incref ("denoms",
denoms),
+ GNUNET_JSON_pack_array_incref ("denominations",
+ grouped_denominations),
GNUNET_JSON_pack_array_incref ("auditors",
ksh->auditors),
GNUNET_JSON_pack_array_incref ("global_fees",
@@ -1833,7 +1836,6 @@ create_krd (struct TEH_KeyStateHandle *ksh,
{
json_t *extensions = json_object ();
bool has_extensions = false;
- bool age_restriction_enabled = false;
/* Fill in the configurations of the enabled extensions */
for (const struct TALER_Extension *extension = TALER_extensions_get_head ();
@@ -1851,8 +1853,6 @@ create_krd (struct TEH_KeyStateHandle *ksh,
/* flag our findings so far */
has_extensions = true;
- age_restriction_enabled = (extension->type ==
- TALER_Extension_AgeRestriction);
GNUNET_assert (NULL != extension->config_json);
@@ -1901,20 +1901,6 @@ create_krd (struct TEH_KeyStateHandle *ksh,
{
json_decref (extensions);
}
-
- // Special case for age restrictions: if enabled, provide the list of
- // age-restricted denominations.
- if (age_restriction_enabled &&
- NULL != age_restricted_denoms)
- {
- GNUNET_assert (
- 0 ==
- json_object_set (
- keys,
- "age_restricted_denoms",
- age_restricted_denoms));
- }
-
}
@@ -2010,12 +1996,10 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
json_t *recoup;
struct SignKeyCtx sctx;
json_t *denoms = NULL;
- json_t *age_restricted_denoms = NULL;
+ json_t *grouped_denominations = NULL;
struct GNUNET_TIME_Timestamp last_cpd;
struct GNUNET_CONTAINER_Heap *heap;
struct GNUNET_HashContext *hash_context = NULL;
- struct GNUNET_HashContext *hash_context_restricted = NULL;
- bool have_age_restricted_denoms = false;
sctx.signkeys = json_array ();
GNUNET_assert (NULL != sctx.signkeys);
@@ -2045,20 +2029,25 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
GNUNET_assert (NULL != denoms);
hash_context = GNUNET_CRYPTO_hash_context_start ();
- /* 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 (0)
- {
- age_restricted_denoms = json_array ();
- GNUNET_assert (NULL != age_restricted_denoms);
- hash_context_restricted = GNUNET_CRYPTO_hash_context_start ();
- }
+ grouped_denominations = json_array ();
+ GNUNET_assert (NULL != grouped_denominations);
last_cpd = GNUNET_TIME_UNIT_ZERO_TS;
{
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 */
+ struct groupData
+ {
+ json_t *json; /* The json blob with the group meta-data and list of denominations */
+ struct GNUNET_HashContext *hash_context; /* hash over all denominations in that group */
+ };
/* heap = min heap, sorted by start time */
while (NULL != (dk = GNUNET_CONTAINER_heap_remove_root (heap)))
@@ -2068,12 +2057,12 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
dk->meta.start) &&
(! GNUNET_TIME_absolute_is_zero (last_cpd.abs_time)) )
{
- struct GNUNET_HashCode hc;
-
- /* FIXME-oec: Do we need to take hash_context_restricted into account
- * in this if-branch!? Current tests suggests: no, (they don't fail).
- * But something seems to be odd about only finishing hash_context.
+ /*
+ * This is not the first entry in the heap (because last_cpd !=
+ * GNUNET_TIME_UNIT_ZERO_TS) and the previous entry had a different
+ * start time. Therefore, we create an entry in the ksh.
*/
+ struct GNUNET_HashCode hc;
GNUNET_CRYPTO_hash_context_finish (
GNUNET_CRYPTO_hash_context_copy (hash_context),
@@ -2085,7 +2074,7 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
sctx.signkeys,
recoup,
denoms,
- age_restricted_denoms))
+ grouped_denominations))
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to generate key response data for %s\n",
@@ -2096,8 +2085,7 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
/* intentionally empty */;
GNUNET_CONTAINER_heap_destroy (heap);
json_decref (denoms);
- if (NULL != age_restricted_denoms)
- json_decref (age_restricted_denoms);
+ json_decref (grouped_denominations);
json_decref (sctx.signkeys);
json_decref (recoup);
return GNUNET_SYSERR;
@@ -2108,9 +2096,6 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
{
json_t *denom;
- json_t *array;
- struct GNUNET_HashContext *hc;
-
denom =
GNUNET_JSON_PACK (
@@ -2131,33 +2116,222 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
TALER_JSON_PACK_DENOM_FEES ("fee",
&dk->meta.fees));
- /* 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 (0 &&
- (0 != dk->denom_pub.age_mask.bits))
+ GNUNET_CRYPTO_hash_context_read (hash_context,
+ &dk->h_denom_pub,
+ sizeof (struct GNUNET_HashCode));
+
+ GNUNET_assert (
+ 0 ==
+ json_array_append_new (
+ denoms,
+ denom));
+
+ }
+
+ /**
+ * Group the denominations by {cipher, value, fees, age_mask}.
+ *
+ * For each group we save the group meta-data and the list of
+ * denominations in this group as a json-blob in the multihashmap
+ * denominations_by_group.
+ **/
+
+ {
+ static const char *denoms_key = "denoms";
+ struct groupData *group;
+ json_t *list;
+ json_t *entry;
+ struct GNUNET_HashCode key;
+
+ /* Find the group/JSON-blob for the key */
+ struct
+ {
+ enum TALER_DenominationCipher cipher;
+ struct TALER_AgeMask age_mask;
+ struct TALER_Amount value;
+ struct TALER_DenomFeeSet fees;
+ } meta = {
+ .cipher = dk->denom_pub.cipher,
+ .value = dk->meta.value,
+ .fees = dk->meta.fees,
+ .age_mask = dk->meta.age_mask,
+ };
+
+ GNUNET_CRYPTO_hash (&meta, sizeof(meta), &key);
+
+ group = (struct groupData *) GNUNET_CONTAINER_multihashmap_get (
+ denominations_by_group,
+ &key);
+
+ if (NULL == group)
{
- have_age_restricted_denoms = true;
- array = age_restricted_denoms;
- hc = hash_context_restricted;
+ /*
+ * There is no group for this meta-data yet, so let's create a new
+ * group entry.
+ */
+
+ bool age_restricted = meta.age_mask.bits != 0;
+ char *cipher;
+
+ group = GNUNET_new (struct groupData);
+ group->hash_context = GNUNET_CRYPTO_hash_context_start ();
+
+ switch (meta.cipher)
+ {
+ case TALER_DENOMINATION_RSA:
+ cipher = age_restricted ? "RSA+age_restriction": "RSA";
+ break;
+ case TALER_DENOMINATION_CS:
+ cipher = age_restricted ? "CS+age_restriction": "CS";
+ break;
+ default:
+ GNUNET_assert (false);
+ }
+
+ group->json = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher", cipher),
+ TALER_JSON_PACK_DENOM_FEES ("fee", &meta.fees),
+ TALER_JSON_pack_amount ("value", &meta.value));
+ GNUNET_assert (NULL != group->json);
+
+ if (age_restricted)
+ {
+ GNUNET_assert (0 ==
+ json_object_set (group->json,
+ "age_mask",
+ json_integer (meta.age_mask.bits)));
+ }
+
+ /* Create a new array for the denominations in this group */
+ list = json_array ();
+ GNUNET_assert (NULL != list);
+ GNUNET_assert (0 ==
+ json_object_set (group->json, denoms_key, list));
+
+ GNUNET_assert (
+ GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_put (denominations_by_group,
+ &key,
+ group,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
}
- else
+
+ /*
+ * Now that we have found/created the right group, add the denomination
+ * to the list
+ */
{
- array = denoms;
- hc = hash_context;
+ struct GNUNET_JSON_PackSpec key_spec;
+
+ switch (meta.cipher)
+ {
+ case TALER_DENOMINATION_RSA:
+ key_spec =
+ GNUNET_JSON_pack_rsa_public_key ("rsa_pub",
+ dk->denom_pub.details.
+ rsa_public_key);
+ break;
+ case TALER_DENOMINATION_CS:
+ key_spec =
+ GNUNET_JSON_pack_data_varsize ("cs_pub",
+ &dk->denom_pub.details.
+ cs_public_key,
+ sizeof (dk->denom_pub.details.
+ cs_public_key));
+ break;
+ default:
+ GNUNET_assert (false);
+ }
+
+ entry = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_data_auto ("master_sig",
+ &dk->master_sig),
+ GNUNET_JSON_pack_timestamp ("stamp_start",
+ dk->meta.start),
+ GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
+ dk->meta.expire_withdraw),
+ GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
+ dk->meta.expire_deposit),
+ GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
+ dk->meta.expire_legal),
+ key_spec
+ );
+ GNUNET_assert (NULL != entry);
}
- GNUNET_CRYPTO_hash_context_read (hc,
+ /*
+ * Build up the running hash of all denominations in this group
+ * TODO: FIXME-oec: this is cipher and age_restriction dependend?!
+ */
+ GNUNET_CRYPTO_hash_context_read (group->hash_context,
&dk->h_denom_pub,
sizeof (struct GNUNET_HashCode));
- GNUNET_assert (
- 0 ==
- json_array_append_new (
- array,
- denom));
+ /* 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 (0 ==
+ json_array_append_new (list, entry));
}
}
+
+ /* Create the JSON-array of grouped denominations */
+ if (0 <
+ GNUNET_CONTAINER_multihashmap_size (denominations_by_group))
+ {
+ struct GNUNET_CONTAINER_MultiHashMapIterator *iter;
+ struct GNUNET_HashCode all_hashcode;
+ struct GNUNET_HashContext *all_hash_ctx;
+ struct groupData *group = NULL;
+
+ all_hash_ctx =
+ GNUNET_CRYPTO_hash_context_start ();
+
+ iter =
+ GNUNET_CONTAINER_multihashmap_iterator_create (denominations_by_group);
+
+ while (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_iterator_next (iter, NULL, (const
+ void **)
+ &group))
+ {
+ struct GNUNET_HashCode hc;
+
+ GNUNET_CRYPTO_hash_context_finish (
+ group->hash_context,
+ &hc);
+
+ GNUNET_CRYPTO_hash_context_read (all_hash_ctx,
+ &hc,
+ sizeof (struct GNUNET_HashCode));
+
+ GNUNET_assert (0 ==
+ json_object_set (
+ group->json,
+ "hash",
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_data_auto (NULL, &hc))));
+
+ GNUNET_assert (0 ==
+ json_array_append_new (
+ grouped_denominations,
+ group->json));
+
+ GNUNET_free (group);
+ }
+
+ GNUNET_CONTAINER_multihashmap_iterator_destroy (iter);
+ GNUNET_CONTAINER_multihashmap_destroy (denominations_by_group);
+
+ GNUNET_CRYPTO_hash_context_finish (
+ all_hash_ctx,
+ &all_hashcode);
+
+ /* FIXME-oec: TODO:
+ * sign all_hashcode and add the signature to the /keys response */
+ }
}
GNUNET_CONTAINER_heap_destroy (heap);
@@ -2165,18 +2339,6 @@ 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 (0 && 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);
@@ -2187,14 +2349,12 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
sctx.signkeys,
recoup,
denoms,
- age_restricted_denoms))
+ grouped_denominations))
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to generate key response data for %s\n",
GNUNET_TIME_timestamp2s (last_cpd));
json_decref (denoms);
- if (0 && NULL != age_restricted_denoms)
- json_decref (age_restricted_denoms);
json_decref (sctx.signkeys);
json_decref (recoup);
return GNUNET_SYSERR;
@@ -2210,8 +2370,6 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
json_decref (sctx.signkeys);
json_decref (recoup);
json_decref (denoms);
- if (NULL != age_restricted_denoms)
- json_decref (age_restricted_denoms);
return GNUNET_OK;
}
@@ -2387,11 +2545,13 @@ build_key_state (struct HelperState *hs,
true);
return NULL;
}
+
if (management_only)
{
ksh->management_only = true;
return ksh;
}
+
if (GNUNET_OK !=
finish_keys_response (ksh))
{
@@ -2401,6 +2561,7 @@ build_key_state (struct HelperState *hs,
true);
return NULL;
}
+
return ksh;
}