[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-donau] branch master updated: [lib] restore donau_api_handle
From: |
gnunet |
Subject: |
[taler-donau] branch master updated: [lib] restore donau_api_handle |
Date: |
Fri, 05 Jan 2024 15:19:14 +0100 |
This is an automated email from the git hooks/post-receive script.
lukas-matyja pushed a commit to branch master
in repository donau.
The following commit(s) were added to refs/heads/master by this push:
new 15e70b7 [lib] restore donau_api_handle
15e70b7 is described below
commit 15e70b7ccc67b831200537db0ede96b78774a107
Author: Matyja Lukas Adam <lukas.matyja@students.bfh.ch>
AuthorDate: Fri Jan 5 15:19:09 2024 +0100
[lib] restore donau_api_handle
---
src/donau/donau-httpd_keys.c | 10 +-
src/lib/donau_api_handle.c | 1697 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 1702 insertions(+), 5 deletions(-)
diff --git a/src/donau/donau-httpd_keys.c b/src/donau/donau-httpd_keys.c
index 3268200..e71d646 100644
--- a/src/donau/donau-httpd_keys.c
+++ b/src/donau/donau-httpd_keys.c
@@ -771,11 +771,11 @@ DH_keys_update_states ()
// .type = htons (TALER_DBEVENT_DONAU_KEYS_UPDATED),
};
- // DH_plugin->event_notify (DH_plugin->cls,
- // &es,
- // NULL,
- // 0);
- // key_generation++;
+ DH_plugin->event_notify (DH_plugin->cls,
+ &es,
+ NULL,
+ 0);
+ key_generation++;
// DH_resume_keys_requests (false);
}
diff --git a/src/lib/donau_api_handle.c b/src/lib/donau_api_handle.c
index eb755a6..8c720bb 100644
--- a/src/lib/donau_api_handle.c
+++ b/src/lib/donau_api_handle.c
@@ -127,3 +127,1700 @@ struct DONAU_GetKeysHandle
do { \
if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
} while (0)
+
+/**
+ * Parse a donau's signing key encoded in JSON.
+ *
+ * @param[out] sign_key where to return the result
+ * @param sign_key_obj json to parse
+ * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
+ * invalid or the @a sign_key_obj is malformed.
+ */
+static enum GNUNET_GenericReturnValue
+parse_json_signkey (struct DONAU_SigningPublicKeyAndValidity *sign_key,
+ const json_t *sign_key_obj)
+{
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("master_sig",
+ &sign_key->master_sig),
+ GNUNET_JSON_spec_fixed_auto ("key",
+ &sign_key->key),
+ GNUNET_JSON_spec_timestamp ("stamp_start",
+ &sign_key->valid_from),
+ GNUNET_JSON_spec_timestamp ("stamp_expire",
+ &sign_key->valid_until),
+ GNUNET_JSON_spec_timestamp ("stamp_end",
+ &sign_key->valid_legal),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (sign_key_obj,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (! check_sigs)
+ return GNUNET_OK;
+ if (GNUNET_OK !=
+ TALER_donau_offline_signkey_validity_verify (
+ &sign_key->key,
+ sign_key->valid_from,
+ sign_key->valid_until,
+ sign_key->valid_legal,
+ master_key,
+ &sign_key->master_sig))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Parse a donau's denomination key encoded in JSON partially.
+ *
+ * Only the values for master_sig, timestamps and the cipher-specific public
+ * key are parsed. All other fields (fees, age_mask, value) MUST have been set
+ * prior to calling this function, otherwise the signature verification
+ * performed within this function will fail.
+ *
+ * @param[out] denom_key where to return the result
+ * @param cipher cipher type to parse
+ * @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
+ * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
+ * invalid or the json malformed.
+ */
+static enum GNUNET_GenericReturnValue
+parse_json_denomkey_partially (
+ struct DONAU_DenomPublicKey *denom_key,
+ enum TALER_DenominationCipher cipher,
+ bool check_sigs,
+ const json_t *denom_key_obj,
+ struct TALER_MasterPublicKeyP *master_key,
+ struct GNUNET_HashCode *hash_xor)
+{
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("master_sig",
+ &denom_key->master_sig),
+ GNUNET_JSON_spec_timestamp ("stamp_expire_deposit",
+ &denom_key->expire_deposit),
+ GNUNET_JSON_spec_timestamp ("stamp_expire_withdraw",
+ &denom_key->withdraw_valid_until),
+ GNUNET_JSON_spec_timestamp ("stamp_start",
+ &denom_key->valid_from),
+ GNUNET_JSON_spec_timestamp ("stamp_expire_legal",
+ &denom_key->expire_legal),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_bool ("lost",
+ &denom_key->lost),
+ NULL),
+ TALER_JSON_spec_denom_pub_cipher (NULL,
+ cipher,
+ &denom_key->key),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (denom_key_obj,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ 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 (! check_sigs)
+ return GNUNET_OK;
+ EXITIF (GNUNET_SYSERR ==
+ TALER_donau_offline_denom_validity_verify (
+ &denom_key->h_key,
+ denom_key->valid_from,
+ denom_key->withdraw_valid_until,
+ denom_key->expire_deposit,
+ denom_key->expire_legal,
+ &denom_key->value,
+ &denom_key->fees,
+ master_key,
+ &denom_key->master_sig));
+ return GNUNET_OK;
+EXITIF_exit:
+ /* invalidate denom_key, just to be sure */
+ memset (denom_key,
+ 0,
+ sizeof (*denom_key));
+ GNUNET_JSON_parse_free (spec);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Decode the JSON in @a resp_obj from the /keys response
+ * and store the data in the @a key_data.
+ *
+ * @param[in] resp_obj JSON object to parse
+ * @param check_sig true if we should check the signature
+ * @param[out] key_data where to store the results we decoded
+ * @param[out] vc where to store version compatibility data
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ * (malformed JSON)
+ */
+static enum GNUNET_GenericReturnValue
+decode_keys_json (const json_t *resp_obj,
+ bool check_sig,
+ struct DONAU_Keys *key_data,
+ enum DONAU_VersionCompatibility *vc)
+{
+ struct TALER_DonauSignatureP denominations_sig;
+ struct DONAU_DonauPublicKeyP pub;
+ const json_t *sign_keys_array;
+ const json_t *donation_units_by_group;
+ bool no_signature = false;
+
+ if (JSON_OBJECT != json_typeof (resp_obj))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+#if DEBUG
+ json_dumpf (resp_obj,
+ stderr,
+ JSON_INDENT (2));
+#endif
+ /* check the version first */
+ {
+ const char *ver;
+ unsigned int age;
+ unsigned int revision;
+ unsigned int current;
+ char dummy;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("version",
+ &ver),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (resp_obj,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (3 != sscanf (ver,
+ "%u:%u:%u%c",
+ ¤t,
+ &revision,
+ &age,
+ &dummy))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ *vc = DONAU_VC_MATCH;
+ if (DONAU_PROTOCOL_CURRENT < current)
+ {
+ *vc |= DONAU_VC_NEWER;
+ if (DONAU_PROTOCOL_CURRENT < current - age)
+ *vc |= DONAU_VC_INCOMPATIBLE;
+ }
+ if (DONAU_PROTOCOL_CURRENT > current)
+ {
+ *vc |= DONAU_VC_OLDER;
+ if (DONAU_PROTOCOL_CURRENT - DONAU_PROTOCOL_AGE > current)
+ *vc |= DONAU_VC_INCOMPATIBLE;
+ }
+ key_data->version = GNUNET_strdup (ver);
+ }
+
+ {
+ const char *currency;
+ const char *asset_type;
+ struct GNUNET_JSON_Specification mspec[] = {
+ GNUNET_JSON_spec_fixed_auto (
+ "denominations_sig",
+ &denominations_sig),
+ GNUNET_JSON_spec_fixed_auto (
+ "eddsa_pub",
+ &pub),
+ GNUNET_JSON_spec_fixed_auto (
+ "master_public_key",
+ &key_data->master_pub),
+ GNUNET_JSON_spec_array_const ("accounts",
+ &accounts),
+ GNUNET_JSON_spec_object_const ("wire_fees",
+ &fees),
+ GNUNET_JSON_spec_array_const ("wads",
+ &wads),
+ GNUNET_JSON_spec_timestamp (
+ "list_issue_date",
+ &key_data->list_issue_date),
+ GNUNET_JSON_spec_relative_time (
+ "reserve_closing_delay",
+ &key_data->reserve_closing_delay),
+ GNUNET_JSON_spec_string (
+ "currency",
+ ¤cy),
+ GNUNET_JSON_spec_uint32 (
+ "currency_fraction_digits",
+ &key_data->currency_fraction_digits),
+ GNUNET_JSON_spec_string (
+ "asset_type",
+ &asset_type),
+ GNUNET_JSON_spec_array_const (
+ "global_fees",
+ &global_fees),
+ GNUNET_JSON_spec_array_const (
+ "signkeys",
+ &sign_keys_array),
+ GNUNET_JSON_spec_array_const (
+ "denominations",
+ &denominations_by_group),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_array_const (
+ "recoup",
+ &recoup_array),
+ NULL),
+ GNUNET_JSON_spec_array_const (
+ "auditors",
+ &auditors_array),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_bool (
+ "rewards_allowed",
+ &key_data->rewards_allowed),
+ NULL),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_object_const ("extensions",
+ &manifests),
+ &no_extensions),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_fixed_auto (
+ "extensions_sig",
+ &key_data->extensions_sig),
+ &no_signature),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_array_const (
+ "wallet_balance_limit_without_kyc",
+ &wblwk),
+ NULL),
+ GNUNET_JSON_spec_end ()
+ };
+ const char *emsg;
+ unsigned int eline;
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (resp_obj,
+ (check_sig) ? mspec : &mspec[2],
+ &emsg,
+ &eline))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Parsing /keys failed for `%s' (%u)\n",
+ emsg,
+ eline);
+ EXITIF (1);
+ }
+ {
+ struct GNUNET_JSON_Specification sspec[] = {
+ TALER_JSON_spec_amount (
+ "stefan_abs",
+ currency,
+ &key_data->stefan_abs),
+ TALER_JSON_spec_amount (
+ "stefan_log",
+ currency,
+ &key_data->stefan_log),
+ TALER_JSON_spec_amount (
+ "stefan_lin",
+ currency,
+ &key_data->stefan_lin),
+ GNUNET_JSON_spec_end ()
+ };
+
+ EXITIF (GNUNET_OK !=
+ GNUNET_JSON_parse (resp_obj,
+ sspec,
+ NULL, NULL));
+ }
+
+ key_data->currency = GNUNET_strdup (currency);
+ key_data->asset_type = GNUNET_strdup (asset_type);
+ if (! no_extensions)
+ key_data->extensions = json_incref ((json_t *) manifests);
+ }
+
+ /* parse the global fees */
+ key_data->num_global_fees
+ = json_array_size (global_fees);
+ if (0 != key_data->num_global_fees)
+ {
+ json_t *global_fee;
+ unsigned int index;
+
+ key_data->global_fees
+ = GNUNET_new_array (key_data->num_global_fees,
+ struct DONAU_GlobalFee);
+ json_array_foreach (global_fees, index, global_fee)
+ {
+ EXITIF (GNUNET_SYSERR ==
+ parse_global_fee (&key_data->global_fees[index],
+ check_sig,
+ global_fee,
+ key_data));
+ }
+ }
+
+ /* parse the signing keys */
+ key_data->num_sign_keys
+ = json_array_size (sign_keys_array);
+ if (0 != key_data->num_sign_keys)
+ {
+ json_t *sign_key_obj;
+ unsigned int index;
+
+ key_data->sign_keys
+ = GNUNET_new_array (key_data->num_sign_keys,
+ struct DONAU_SigningPublicKey);
+ json_array_foreach (sign_keys_array, index, sign_key_obj) {
+ EXITIF (GNUNET_SYSERR ==
+ parse_json_signkey (&key_data->sign_keys[index],
+ check_sig,
+ sign_key_obj,
+ &key_data->master_pub));
+ }
+ }
+
+ /* Parse balance limits */
+ if (NULL != wblwk)
+ {
+ key_data->wblwk_length = json_array_size (wblwk);
+ key_data->wallet_balance_limit_without_kyc
+ = GNUNET_new_array (key_data->wblwk_length,
+ struct TALER_Amount);
+ for (unsigned int i = 0; i<key_data->wblwk_length; i++)
+ {
+ struct TALER_Amount *a = &key_data->wallet_balance_limit_without_kyc[i];
+ const json_t *aj = json_array_get (wblwk,
+ i);
+ struct GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_amount (NULL,
+ key_data->currency,
+ a),
+ GNUNET_JSON_spec_end ()
+ };
+
+ EXITIF (GNUNET_OK !=
+ GNUNET_JSON_parse (aj,
+ spec,
+ NULL, NULL));
+ }
+ }
+
+ /* Parse wire accounts */
+ key_data->fees = parse_fees (&key_data->master_pub,
+ key_data->currency,
+ fees,
+ &key_data->fees_len);
+ EXITIF (NULL == key_data->fees);
+ /* parse accounts */
+ GNUNET_array_grow (key_data->accounts,
+ key_data->accounts_len,
+ json_array_size (accounts));
+ EXITIF (GNUNET_OK !=
+ DONAU_parse_accounts (&key_data->master_pub,
+ accounts,
+ key_data->accounts_len,
+ key_data->accounts));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Parsed %u wire accounts from JSON\n",
+ (unsigned int) json_array_size (accounts));
+
+
+ /* Parse the supported extension(s): age-restriction. */
+ /* TODO: maybe lift all this into a FP in TALER_Extension ? */
+ if (! no_extensions)
+ {
+ if (no_signature)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "found extensions without signature\n");
+ }
+ else
+ {
+ /* We have an extensions object. Verify its signature. */
+ EXITIF (GNUNET_OK !=
+ TALER_extensions_verify_manifests_signature (
+ manifests,
+ &key_data->extensions_sig,
+ &key_data->master_pub));
+
+ /* Parse and set the the configuration of the extensions accordingly */
+ EXITIF (GNUNET_OK !=
+ TALER_extensions_load_manifests (manifests));
+ }
+
+ /* Assuming we might have now a new value for age_mask, set it in key_data
*/
+ key_data->age_mask = TALER_extensions_get_age_restriction_mask ();
+ }
+
+ /*
+ * 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 *group_obj;
+ unsigned int group_idx;
+
+ 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};
+ const json_t *denom_keys_array;
+ struct GNUNET_JSON_Specification group_spec[] = {
+ TALER_JSON_spec_denomination_group (NULL,
+ key_data->currency,
+ &group),
+ GNUNET_JSON_spec_array_const ("denoms",
+ &denom_keys_array),
+ GNUNET_JSON_spec_end ()
+ };
+ json_t *denom_key_obj;
+ unsigned int index;
+
+ EXITIF (GNUNET_SYSERR ==
+ GNUNET_JSON_parse (group_obj,
+ group_spec,
+ NULL,
+ NULL));
+
+ /* Now, parse the individual denominations */
+ 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
+ parse_json_denomkey_partially pass */
+ struct DONAU_DenomPublicKey dk = {
+ .key.cipher = group.cipher,
+ .value = group.value,
+ .fees = group.fees,
+ .key.age_mask = group.age_mask
+ };
+ bool found = false;
+
+ EXITIF (GNUNET_SYSERR ==
+ parse_json_denomkey_partially (&dk,
+ group.cipher,
+ 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);
+ for (unsigned int j = 0;
+ j<key_data->num_denom_keys;
+ j++)
+ {
+ if (0 == GNUNET_CRYPTO_bsign_pub_cmp (&dk,
+ &key_data->denom_keys[j]))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (found)
+ {
+ /* 0:0:0 did not support /keys cherry picking */
+ TALER_LOG_DEBUG ("Skipping denomination key: already know it\n");
+ TALER_denom_pub_free (&dk.key);
+ continue;
+ }
+
+ if (key_data->denom_keys_size == key_data->num_denom_keys)
+ GNUNET_array_grow (key_data->denom_keys,
+ key_data->denom_keys_size,
+ key_data->denom_keys_size * 2 + 2);
+ key_data->denom_keys[key_data->num_denom_keys++] = dk;
+
+ /* Update "last_denom_issue_date" */
+ TALER_LOG_DEBUG ("Adding denomination key that is valid_until %s\n",
+ GNUNET_TIME_timestamp2s (dk.valid_from));
+ key_data->last_denom_issue_date
+ = 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 */
+
+ /* parse the auditor information */
+ {
+ json_t *auditor_info;
+ unsigned int index;
+
+ /* Merge with the existing auditor information we have (/keys cherry
picking) */
+ json_array_foreach (auditors_array, index, auditor_info)
+ {
+ struct DONAU_AuditorInformation ai;
+ bool found = false;
+
+ memset (&ai,
+ 0,
+ sizeof (ai));
+ EXITIF (GNUNET_SYSERR ==
+ parse_json_auditor (&ai,
+ check_sig,
+ auditor_info,
+ key_data));
+ for (unsigned int j = 0; j<key_data->num_auditors; j++)
+ {
+ struct DONAU_AuditorInformation *aix = &key_data->auditors[j];
+
+ if (0 == GNUNET_memcmp (&ai.auditor_pub,
+ &aix->auditor_pub))
+ {
+ found = true;
+ /* Merge denomination key signatures of downloaded /keys into
existing
+ auditor information 'aix'. */
+ TALER_LOG_DEBUG (
+ "Merging %u new audited keys with %u known audited keys\n",
+ aix->num_denom_keys,
+ ai.num_denom_keys);
+ for (unsigned int i = 0; i<ai.num_denom_keys; i++)
+ {
+ bool kfound = false;
+
+ for (unsigned int k = 0; k<aix->num_denom_keys; k++)
+ {
+ if (aix->denom_keys[k].denom_key_offset ==
+ ai.denom_keys[i].denom_key_offset)
+ {
+ kfound = true;
+ break;
+ }
+ }
+ if (! kfound)
+ GNUNET_array_append (aix->denom_keys,
+ aix->num_denom_keys,
+ ai.denom_keys[i]);
+ }
+ break;
+ }
+ }
+ if (found)
+ {
+ GNUNET_array_grow (ai.denom_keys,
+ ai.num_denom_keys,
+ 0);
+ GNUNET_free (ai.auditor_url);
+ continue; /* we are done */
+ }
+ if (key_data->auditors_size == key_data->num_auditors)
+ GNUNET_array_grow (key_data->auditors,
+ key_data->auditors_size,
+ key_data->auditors_size * 2 + 2);
+ GNUNET_assert (NULL != ai.auditor_url);
+ key_data->auditors[key_data->num_auditors++] = ai;
+ };
+ }
+
+ /* parse the revocation/recoup information */
+ if (NULL != recoup_array)
+ {
+ json_t *recoup_info;
+ unsigned int index;
+
+ json_array_foreach (recoup_array, index, recoup_info)
+ {
+ struct TALER_DenominationHashP h_denom_pub;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
+ &h_denom_pub),
+ GNUNET_JSON_spec_end ()
+ };
+
+ EXITIF (GNUNET_OK !=
+ GNUNET_JSON_parse (recoup_info,
+ spec,
+ NULL, NULL));
+ for (unsigned int j = 0;
+ j<key_data->num_denom_keys;
+ j++)
+ {
+ if (0 == GNUNET_memcmp (&h_denom_pub,
+ &key_data->denom_keys[j].h_key))
+ {
+ key_data->denom_keys[j].revoked = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (check_sig)
+ {
+ EXITIF (GNUNET_OK !=
+ DONAU_test_signing_key (key_data,
+ &pub));
+ EXITIF (GNUNET_OK !=
+ TALER_donau_online_key_set_verify (
+ key_data->list_issue_date,
+ &hash_xor,
+ &pub,
+ &denominations_sig));
+ }
+ return GNUNET_OK;
+
+EXITIF_exit:
+ *vc = DONAU_VC_PROTOCOL_ERROR;
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Callback used when downloading the reply to a /keys request
+ * is complete.
+ *
+ * @param cls the `struct KeysRequest`
+ * @param response_code HTTP response code, 0 on error
+ * @param resp_obj parsed JSON result, NULL on error
+ */
+static void
+keys_completed_cb (void *cls,
+ long response_code,
+ const void *resp_obj)
+{
+ struct DONAU_GetKeysHandle *gkh = cls;
+ const json_t *j = resp_obj;
+ struct DONAU_Keys *kd = NULL;
+ struct DONAU_KeysResponse kresp = {
+ .hr.reply = j,
+ .hr.http_status = (unsigned int) response_code,
+ .details.ok.compat = DONAU_VC_PROTOCOL_ERROR,
+ };
+
+ gkh->job = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Received keys from URL `%s' with status %ld and expiration
%s.\n",
+ gkh->url,
+ response_code,
+ GNUNET_TIME_timestamp2s (gkh->expire));
+ if (GNUNET_TIME_absolute_is_past (gkh->expire.abs_time))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Donau failed to give expiration time, assuming in %s\n",
+ GNUNET_TIME_relative2s (DEFAULT_EXPIRATION,
+ true));
+ gkh->expire
+ = GNUNET_TIME_absolute_to_timestamp (
+ GNUNET_TIME_relative_to_absolute (DEFAULT_EXPIRATION));
+ }
+ switch (response_code)
+ {
+ case 0:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to receive /keys response from donau %s\n",
+ gkh->donau_url);
+ break;
+ case MHD_HTTP_OK:
+ if (NULL == j)
+ {
+ GNUNET_break (0);
+ response_code = 0;
+ break;
+ }
+ kd = GNUNET_new (struct DONAU_Keys);
+ kd->donau_url = GNUNET_strdup (gkh->donau_url);
+ if (NULL != gkh->prev_keys)
+ {
+ const struct DONAU_Keys *kd_old = gkh->prev_keys;
+
+ /* We keep the denomination keys and auditor signatures from the
+ previous iteration (/keys cherry picking) */
+ kd->num_denom_keys
+ = kd_old->num_denom_keys;
+ kd->last_denom_issue_date
+ = kd_old->last_denom_issue_date;
+ GNUNET_array_grow (kd->denom_keys,
+ kd->denom_keys_size,
+ kd->num_denom_keys);
+ /* First make a shallow copy, we then need another pass for the RSA
key... */
+ GNUNET_memcpy (kd->denom_keys,
+ kd_old->denom_keys,
+ kd_old->num_denom_keys
+ * sizeof (struct DONAU_DenomPublicKey));
+ for (unsigned int i = 0; i<kd_old->num_denom_keys; i++)
+ TALER_denom_pub_deep_copy (&kd->denom_keys[i].key,
+ &kd_old->denom_keys[i].key);
+ kd->num_auditors = kd_old->num_auditors;
+ kd->auditors = GNUNET_new_array (kd->num_auditors,
+ struct DONAU_AuditorInformation);
+ /* Now the necessary deep copy... */
+ for (unsigned int i = 0; i<kd_old->num_auditors; i++)
+ {
+ const struct DONAU_AuditorInformation *aold =
+ &kd_old->auditors[i];
+ struct DONAU_AuditorInformation *anew = &kd->auditors[i];
+
+ anew->auditor_pub = aold->auditor_pub;
+ anew->auditor_url = GNUNET_strdup (aold->auditor_url);
+ GNUNET_array_grow (anew->denom_keys,
+ anew->num_denom_keys,
+ aold->num_denom_keys);
+ GNUNET_memcpy (
+ anew->denom_keys,
+ aold->denom_keys,
+ aold->num_denom_keys
+ * sizeof (struct DONAU_AuditorDenominationInfo));
+ }
+ }
+ /* Now decode fresh /keys response */
+ if (GNUNET_OK !=
+ decode_keys_json (j,
+ true,
+ kd,
+ &kresp.details.ok.compat))
+ {
+ TALER_LOG_ERROR ("Could not decode /keys response\n");
+ kd->rc = 1;
+ DONAU_keys_decref (kd);
+ kd = NULL;
+ kresp.hr.http_status = 0;
+ kresp.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ break;
+ }
+ kd->rc = 1;
+ kd->key_data_expiration = gkh->expire;
+ if (GNUNET_TIME_relative_cmp (
+ GNUNET_TIME_absolute_get_remaining (gkh->expire.abs_time),
+ <,
+ MINIMUM_EXPIRATION))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Donau returned keys with expiration time below %s.
Compensating.\n",
+ GNUNET_TIME_relative2s (MINIMUM_EXPIRATION,
+ true));
+ kd->key_data_expiration
+ = GNUNET_TIME_relative_to_timestamp (MINIMUM_EXPIRATION);
+ }
+
+ kresp.details.ok.keys = kd;
+ break;
+ case MHD_HTTP_BAD_REQUEST:
+ case MHD_HTTP_UNAUTHORIZED:
+ case MHD_HTTP_FORBIDDEN:
+ case MHD_HTTP_NOT_FOUND:
+ if (NULL == j)
+ {
+ kresp.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ kresp.hr.hint = TALER_ErrorCode_get_hint (kresp.hr.ec);
+ }
+ else
+ {
+ kresp.hr.ec = TALER_JSON_get_error_code (j);
+ kresp.hr.hint = TALER_JSON_get_error_hint (j);
+ }
+ break;
+ default:
+ if (NULL == j)
+ {
+ kresp.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ kresp.hr.hint = TALER_ErrorCode_get_hint (kresp.hr.ec);
+ }
+ else
+ {
+ kresp.hr.ec = TALER_JSON_get_error_code (j);
+ kresp.hr.hint = TALER_JSON_get_error_hint (j);
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u/%d\n",
+ (unsigned int) response_code,
+ (int) kresp.hr.ec);
+ break;
+ }
+ gkh->cert_cb (gkh->cert_cb_cls,
+ &kresp,
+ kd);
+ DONAU_get_keys_cancel (gkh);
+}
+
+
+/**
+ * Define a max length for the HTTP "Expire:" header
+ */
+#define MAX_DATE_LINE_LEN 32
+
+
+/**
+ * Parse HTTP timestamp.
+ *
+ * @param dateline header to parse header
+ * @param[out] at where to write the result
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+parse_date_string (const char *dateline,
+ struct GNUNET_TIME_Timestamp *at)
+{
+ static const char *MONTHS[] =
+ { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL };
+ int year;
+ int mon;
+ int day;
+ int hour;
+ int min;
+ int sec;
+ char month[4];
+ struct tm tm;
+ time_t t;
+
+ /* We recognize the three formats in RFC2616, section 3.3.1. Month
+ names are always in English. The formats are:
+ Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
+ Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
+ Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
+ Note that the first is preferred.
+ */
+
+ if (strlen (dateline) > MAX_DATE_LINE_LEN)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ while (*dateline == ' ')
+ ++dateline;
+ while (*dateline && *dateline != ' ')
+ ++dateline;
+ while (*dateline == ' ')
+ ++dateline;
+ /* We just skipped over the day of the week. Now we have:*/
+ if ( (sscanf (dateline,
+ "%d %3s %d %d:%d:%d",
+ &day, month, &year, &hour, &min, &sec) != 6) &&
+ (sscanf (dateline,
+ "%d-%3s-%d %d:%d:%d",
+ &day, month, &year, &hour, &min, &sec) != 6) &&
+ (sscanf (dateline,
+ "%3s %d %d:%d:%d %d",
+ month, &day, &hour, &min, &sec, &year) != 6) )
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ /* Two digit dates are defined to be relative to 1900; all other dates
+ * are supposed to be represented as four digits. */
+ if (year < 100)
+ year += 1900;
+
+ for (mon = 0; ; mon++)
+ {
+ if (! MONTHS[mon])
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (0 == strcasecmp (month,
+ MONTHS[mon]))
+ break;
+ }
+
+ memset (&tm, 0, sizeof(tm));
+ tm.tm_year = year - 1900;
+ tm.tm_mon = mon;
+ tm.tm_mday = day;
+ tm.tm_hour = hour;
+ tm.tm_min = min;
+ tm.tm_sec = sec;
+
+ t = mktime (&tm);
+ if (((time_t) -1) == t)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+ "mktime");
+ return GNUNET_SYSERR;
+ }
+ if (t < 0)
+ t = 0; /* can happen due to timezone issues if date was 1.1.1970 */
+ *at = GNUNET_TIME_timestamp_from_s (t);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called for each header in the HTTP /keys response.
+ * Finds the "Expire:" header and parses it, storing the result
+ * in the "expire" field of the keys request.
+ *
+ * @param buffer header data received
+ * @param size size of an item in @a buffer
+ * @param nitems number of items in @a buffer
+ * @param userdata the `struct DONAU_GetKeysHandle`
+ * @return `size * nitems` on success (everything else aborts)
+ */
+static size_t
+header_cb (char *buffer,
+ size_t size,
+ size_t nitems,
+ void *userdata)
+{
+ struct DONAU_GetKeysHandle *kr = userdata;
+ size_t total = size * nitems;
+ char *val;
+
+ if (total < strlen (MHD_HTTP_HEADER_EXPIRES ": "))
+ return total;
+ if (0 != strncasecmp (MHD_HTTP_HEADER_EXPIRES ": ",
+ buffer,
+ strlen (MHD_HTTP_HEADER_EXPIRES ": ")))
+ return total;
+ val = GNUNET_strndup (&buffer[strlen (MHD_HTTP_HEADER_EXPIRES ": ")],
+ total - strlen (MHD_HTTP_HEADER_EXPIRES ": "));
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Found %s header `%s'\n",
+ MHD_HTTP_HEADER_EXPIRES,
+ val);
+ if (GNUNET_OK !=
+ parse_date_string (val,
+ &kr->expire))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to parse %s-header `%s'\n",
+ MHD_HTTP_HEADER_EXPIRES,
+ val);
+ kr->expire = GNUNET_TIME_UNIT_ZERO_TS;
+ }
+ GNUNET_free (val);
+ return total;
+}
+
+
+struct DONAU_GetKeysHandle *
+DONAU_get_keys (
+ struct GNUNET_CURL_Context *ctx,
+ const char *url,
+ struct DONAU_Keys *last_keys,
+ DONAU_GetKeysCallback cert_cb,
+ void *cert_cb_cls)
+{
+ struct DONAU_GetKeysHandle *gkh;
+ CURL *eh;
+
+ TALER_LOG_DEBUG ("Connecting to the donau (%s)\n",
+ url);
+ gkh = GNUNET_new (struct DONAU_GetKeysHandle);
+ gkh->donau_url = GNUNET_strdup (url);
+ gkh->cert_cb = cert_cb;
+ gkh->cert_cb_cls = cert_cb_cls;
+ gkh->url = TALER_url_join (url,
+ "keys");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Requesting keys with URL `%s'.\n",
+ gkh->url);
+ eh = DONAU_curl_easy_get_ (gkh->url);
+ if (NULL == eh)
+ {
+ GNUNET_break (0);
+ GNUNET_free (gkh->donau_url);
+ GNUNET_free (gkh->url);
+ GNUNET_free (gkh);
+ return NULL;
+ }
+ GNUNET_break (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_VERBOSE,
+ 0));
+ GNUNET_break (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_TIMEOUT,
+ 120 /* seconds */));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_HEADERFUNCTION,
+ &header_cb));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_HEADERDATA,
+ gkh));
+ gkh->job = GNUNET_CURL_job_add_with_ct_json (ctx,
+ eh,
+ &keys_completed_cb,
+ gkh);
+ return gkh;
+}
+
+
+void
+DONAU_get_keys_cancel (
+ struct DONAU_GetKeysHandle *gkh)
+{
+ if (NULL != gkh->job)
+ {
+ GNUNET_CURL_job_cancel (gkh->job);
+ gkh->job = NULL;
+ }
+ DONAU_keys_decref (gkh->prev_keys);
+ GNUNET_free (gkh->donau_url);
+ GNUNET_free (gkh->url);
+ GNUNET_free (gkh);
+}
+
+
+enum GNUNET_GenericReturnValue
+DONAU_test_signing_key (
+ const struct DONAU_Keys *keys,
+ const struct DONAU_DonauPublicKeyP *pub)
+{
+ struct GNUNET_TIME_Absolute now;
+
+ /* we will check using a tolerance of 1h for the time */
+ now = GNUNET_TIME_absolute_get ();
+ for (unsigned int i = 0; i<keys->num_sign_keys; i++)
+ if ( (GNUNET_TIME_absolute_cmp (
+ keys->sign_keys[i].valid_from.abs_time,
+ <=,
+ GNUNET_TIME_absolute_add (now,
+ LIFETIME_TOLERANCE))) &&
+ (GNUNET_TIME_absolute_cmp (
+ keys->sign_keys[i].valid_until.abs_time,
+ >,
+ GNUNET_TIME_absolute_subtract (now,
+ LIFETIME_TOLERANCE))) &&
+ (0 == GNUNET_memcmp (pub,
+ &keys->sign_keys[i].key)) )
+ return GNUNET_OK;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Signing key not valid at time %s\n",
+ GNUNET_TIME_absolute2s (now));
+ return GNUNET_SYSERR;
+}
+
+
+const struct DONAU_DenomPublicKey *
+DONAU_get_denomination_key (
+ const struct DONAU_Keys *keys,
+ const struct TALER_DenominationPublicKey *pk)
+{
+ for (unsigned int i = 0; i<keys->num_denom_keys; i++)
+ if (0 ==
+ TALER_denom_pub_cmp (pk,
+ &keys->denom_keys[i].key))
+ return &keys->denom_keys[i];
+ return NULL;
+}
+
+
+struct DONAU_DenomPublicKey *
+DONAU_copy_denomination_key (
+ const struct DONAU_DenomPublicKey *key)
+{
+ struct DONAU_DenomPublicKey *copy;
+
+ copy = GNUNET_new (struct DONAU_DenomPublicKey);
+ *copy = *key;
+ TALER_denom_pub_deep_copy (©->key,
+ &key->key);
+ return copy;
+}
+
+
+void
+DONAU_destroy_denomination_key (
+ struct DONAU_DenomPublicKey *key)
+{
+ TALER_denom_pub_free (&key->key);
+ GNUNET_free (key);
+}
+
+
+const struct DONAU_DenomPublicKey *
+DONAU_get_denomination_key_by_hash (
+ const struct DONAU_Keys *keys,
+ const struct TALER_DenominationHashP *hc)
+{
+ for (unsigned int i = 0; i<keys->num_denom_keys; i++)
+ if (0 == GNUNET_memcmp (hc,
+ &keys->denom_keys[i].h_key))
+ return &keys->denom_keys[i];
+ return NULL;
+}
+
+
+struct DONAU_Keys *
+DONAU_keys_incref (struct DONAU_Keys *keys)
+{
+ GNUNET_assert (keys->rc < UINT_MAX);
+ keys->rc++;
+ return keys;
+}
+
+
+void
+DONAU_keys_decref (struct DONAU_Keys *keys)
+{
+ if (NULL == keys)
+ return;
+ GNUNET_assert (0 < keys->rc);
+ keys->rc--;
+ if (0 != keys->rc)
+ return;
+ GNUNET_array_grow (keys->sign_keys,
+ keys->num_sign_keys,
+ 0);
+ for (unsigned int i = 0; i<keys->num_denom_keys; i++)
+ TALER_denom_pub_free (&keys->denom_keys[i].key);
+
+ GNUNET_array_grow (keys->denom_keys,
+ keys->denom_keys_size,
+ 0);
+ for (unsigned int i = 0; i<keys->num_auditors; i++)
+ {
+ GNUNET_array_grow (keys->auditors[i].denom_keys,
+ keys->auditors[i].num_denom_keys,
+ 0);
+ GNUNET_free (keys->auditors[i].auditor_url);
+ }
+ GNUNET_array_grow (keys->auditors,
+ keys->auditors_size,
+ 0);
+ DONAU_free_accounts (keys->accounts_len,
+ keys->accounts);
+ GNUNET_array_grow (keys->accounts,
+ keys->accounts_len,
+ 0);
+ free_fees (keys->fees,
+ keys->fees_len);
+ json_decref (keys->extensions);
+ GNUNET_free (keys->wallet_balance_limit_without_kyc);
+ GNUNET_free (keys->version);
+ GNUNET_free (keys->currency);
+ GNUNET_free (keys->asset_type);
+ GNUNET_free (keys->global_fees);
+ GNUNET_free (keys->donau_url);
+ GNUNET_free (keys);
+}
+
+
+struct DONAU_Keys *
+DONAU_keys_from_json (const json_t *j)
+{
+ const json_t *jkeys;
+ const char *url;
+ uint32_t version;
+ struct GNUNET_TIME_Timestamp expire
+ = GNUNET_TIME_UNIT_ZERO_TS;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_uint32 ("version",
+ &version),
+ GNUNET_JSON_spec_object_const ("keys",
+ &jkeys),
+ GNUNET_JSON_spec_string ("donau_url",
+ &url),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_timestamp ("expire",
+ &expire),
+ NULL),
+ GNUNET_JSON_spec_end ()
+ };
+ struct DONAU_Keys *keys;
+ enum DONAU_VersionCompatibility compat;
+
+ if (NULL == j)
+ return NULL;
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (j,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return NULL;
+ }
+ if (0 != version)
+ {
+ return NULL; /* unsupported version */
+ }
+ keys = GNUNET_new (struct DONAU_Keys);
+ if (GNUNET_OK !=
+ decode_keys_json (jkeys,
+ false,
+ keys,
+ &compat))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ keys->rc = 1;
+ keys->key_data_expiration = expire;
+ keys->donau_url = GNUNET_strdup (url);
+ return keys;
+}
+
+
+/**
+ * Data we track per donation unit group.
+ */
+struct GroupData
+{
+ /**
+ * The json blob with the group meta-data and list of donation units
+ */
+ json_t *json;
+
+ /**
+ * Meta data for this group.
+ */
+ struct DONAU_DonationUnitGroup meta;
+};
+
+
+/**
+ * Add donation unit group represented by @a value
+ * to list of donation units in @a cls. Also frees
+ * the @a value.
+ *
+ * @param[in,out] cls a `json_t *` with an array to build
+ * @param key unused
+ * @param value a `struct GroupData *`
+ * @return #GNUNET_OK (continue to iterate)
+ */
+static enum GNUNET_GenericReturnValue
+add_grp (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
+{
+ json_t *donation_units_by_group = cls;
+ struct GroupData *gd = value;
+ const char *cipher;
+ json_t *ge;
+
+ (void) key;
+ switch (gd->meta.cipher)
+ {
+ case GNUNET_CRYPTO_BSA_RSA:
+ cipher = age_restricted ? "RSA+age_restricted" : "RSA";
+ break;
+ case GNUNET_CRYPTO_BSA_CS:
+ cipher = age_restricted ? "CS+age_restricted" : "CS";
+ break;
+ default:
+ GNUNET_assert (false);
+ }
+
+ 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",
+ gd->json),
+ TALER_JSON_pack_amount ("value",
+ &gd->meta.value));
+ GNUNET_assert (0 ==
+ json_array_append_new (donation_units_by_group,
+ ge));
+ GNUNET_free (gd);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Convert array of account restrictions @a ars to JSON.
+ *
+ * @param ar_len length of @a ars
+ * @param ars account restrictions to convert
+ * @return JSON representation
+ */
+static json_t *
+ar_to_json (unsigned int ar_len,
+ const struct TALER_DONAU_AccountRestriction ars[static ar_len])
+{
+ json_t *rval;
+
+ rval = json_array ();
+ GNUNET_assert (NULL != rval);
+ for (unsigned int i = 0; i<ar_len; i++)
+ {
+ const struct TALER_DONAU_AccountRestriction *ar = &ars[i];
+
+ switch (ar->type)
+ {
+ case TALER_DONAU_AR_INVALID:
+ GNUNET_break (0);
+ json_decref (rval);
+ return NULL;
+ case TALER_DONAU_AR_DENY:
+ GNUNET_assert (
+ 0 ==
+ json_array_append_new (
+ rval,
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("type",
+ "deny"))));
+ break;
+ case TALER_DONAU_AR_REGEX:
+ GNUNET_assert (
+ 0 ==
+ json_array_append_new (
+ rval,
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string (
+ "type",
+ "regex"),
+ GNUNET_JSON_pack_string (
+ "regex",
+ ar->details.regex.posix_egrep),
+ GNUNET_JSON_pack_string (
+ "human_hint",
+ ar->details.regex.human_hint),
+ GNUNET_JSON_pack_object_incref (
+ "human_hint_i18n",
+ (json_t *) ar->details.regex.human_hint_i18n)
+ )));
+ break;
+ }
+ }
+ return rval;
+}
+
+
+json_t *
+DONAU_keys_to_json (const struct DONAU_Keys *kd)
+{
+ json_t *keys;
+ json_t *signkeys;
+ json_t *donation_units;
+ json_t *accounts;
+
+ now = GNUNET_TIME_timestamp_get ();
+ signkeys = json_array ();
+ GNUNET_assert (NULL != signkeys);
+ for (unsigned int i = 0; i<kd->num_sign_keys; i++)
+ {
+ const struct TALER_DONAU_SigningPublicKey *sk = &kd->sign_keys[i];
+ json_t *signkey;
+
+ signkey = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_data_auto ("key",
+ &sk->key),
+ GNUNET_JSON_pack_uint64 ("year",
+ &sk->year));
+ GNUNET_assert (NULL != signkey);
+ GNUNET_assert (0 ==
+ json_array_append_new (signkeys,
+ signkey));
+ }
+
+ donation_units_by_group = json_array ();
+ GNUNET_assert (NULL != donation_units_by_group);
+ {
+ struct GNUNET_CONTAINER_MultiHashMap *dbg;
+
+ dbg = GNUNET_CONTAINER_multihashmap_create (128,
+ false);
+ for (unsigned int i = 0; i<kd->num_donation_unit_keys; i++)
+ {
+ const struct TALER_DONAU_DenomPublicKey *dk = &kd->denom_keys[i];
+ struct TALER_DenominationGroup meta = {
+ .cipher = dk->key.cipher,
+ .value = dk->value,
+ .year = dk->year
+ };
+ struct GNUNET_HashCode key;
+ struct GroupData *gd;
+ json_t *donation_unit;
+ struct GNUNET_JSON_PackSpec key_spec;
+
+ //TODO: check year
+
+ TALER_donation_unit_group_get_key (&meta,
+ &key);
+ gd = GNUNET_CONTAINER_multihashmap_get (dbg,
+ &key);
+ if (NULL == gd)
+ {
+ gd = GNUNET_new (struct GroupData);
+ gd->meta = meta;
+ gd->json = json_array ();
+ GNUNET_assert (NULL != gd->json);
+ GNUNET_assert (
+ GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_put (dbg,
+ &key,
+ gd,
+
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+
+ }
+
+ switch (meta.cipher)
+ {
+ case GNUNET_CRYPTO_BSA_RSA:
+ key_spec =
+ GNUNET_JSON_pack_rsa_public_key (
+ "rsa_pub",
+ dk->key.bsign_pub_key->details.rsa_public_key);
+ break;
+ case GNUNET_CRYPTO_BSA_CS:
+ key_spec =
+ GNUNET_JSON_pack_data_varsize (
+ "cs_pub",
+ &dk->key.bsign_pub_key->details.cs_public_key,
+ sizeof (dk->key.bsign_pub_key->details.cs_public_key));
+ break;
+ default:
+ GNUNET_assert (false);
+ }
+ donation_unit = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
+ dk->expire_deposit),
+ GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
+ dk->withdraw_valid_until),
+ GNUNET_JSON_pack_timestamp ("stamp_start",
+ dk->valid_from),
+ GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
+ dk->expire_legal),
+ GNUNET_JSON_pack_data_auto ("master_sig",
+ &dk->master_sig),
+ key_spec
+ );
+ GNUNET_assert (0 ==
+ json_array_append_new (gd->json,
+ donation_unit));
+ }
+ GNUNET_CONTAINER_multihashmap_iterate (dbg,
+ &add_grp,
+ donation_unit_by_group);
+ GNUNET_CONTAINER_multihashmap_destroy (dbg);
+ }
+
+ auditors = json_array ();
+ GNUNET_assert (NULL != auditors);
+ for (unsigned int i = 0; i<kd->num_auditors; i++)
+ {
+ const struct TALER_DONAU_AuditorInformation *ai = &kd->auditors[i];
+ json_t *a;
+ json_t *adenoms;
+
+ adenoms = json_array ();
+ GNUNET_assert (NULL != adenoms);
+ for (unsigned int j = 0; j<ai->num_denom_keys; j++)
+ {
+ const struct TALER_DONAU_AuditorDenominationInfo *adi =
+ &ai->denom_keys[j];
+ const struct TALER_DONAU_DenomPublicKey *dk =
+ &kd->denom_keys[adi->denom_key_offset];
+ json_t *k;
+
+ GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys);
+ if (GNUNET_TIME_timestamp_cmp (now,
+ >,
+ dk->expire_deposit))
+ continue; /* skip auditor signatures for denomination keys that have
expired */
+ GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys);
+ k = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_data_auto ("denom_pub_h",
+ &dk->h_key),
+ GNUNET_JSON_pack_data_auto ("auditor_sig",
+ &adi->auditor_sig));
+ GNUNET_assert (0 ==
+ json_array_append_new (adenoms,
+ k));
+ }
+
+ a = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_data_auto ("auditor_pub",
+ &ai->auditor_pub),
+ GNUNET_JSON_pack_string ("auditor_url",
+ ai->auditor_url),
+ GNUNET_JSON_pack_array_steal ("denomination_keys",
+ adenoms));
+ GNUNET_assert (0 ==
+ json_array_append_new (auditors,
+ a));
+ }
+
+ global_fees = json_array ();
+ GNUNET_assert (NULL != global_fees);
+ for (unsigned int i = 0; i<kd->num_global_fees; i++)
+ {
+ const struct TALER_DONAU_GlobalFee *gf
+ = &kd->global_fees[i];
+
+ if (GNUNET_TIME_absolute_is_past (gf->end_date.abs_time))
+ continue;
+ GNUNET_assert (
+ 0 ==
+ json_array_append_new (
+ global_fees,
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_timestamp ("start_date",
+ gf->start_date),
+ GNUNET_JSON_pack_timestamp ("end_date",
+ gf->end_date),
+ TALER_JSON_PACK_GLOBAL_FEES (&gf->fees),
+ GNUNET_JSON_pack_time_rel ("history_expiration",
+ gf->history_expiration),
+ GNUNET_JSON_pack_time_rel ("purse_timeout",
+ gf->purse_timeout),
+ GNUNET_JSON_pack_uint64 ("purse_account_limit",
+ gf->purse_account_limit),
+ GNUNET_JSON_pack_data_auto ("master_sig",
+ &gf->master_sig))));
+ }
+
+ accounts = json_array ();
+ GNUNET_assert (NULL != accounts);
+ for (unsigned int i = 0; i<kd->accounts_len; i++)
+ {
+ const struct TALER_DONAU_WireAccount *acc
+ = &kd->accounts[i];
+ json_t *credit_restrictions;
+ json_t *debit_restrictions;
+
+ credit_restrictions
+ = ar_to_json (acc->credit_restrictions_length,
+ acc->credit_restrictions);
+ GNUNET_assert (NULL != credit_restrictions);
+ debit_restrictions
+ = ar_to_json (acc->debit_restrictions_length,
+ acc->debit_restrictions);
+ GNUNET_assert (NULL != debit_restrictions);
+ GNUNET_assert (
+ 0 ==
+ json_array_append_new (
+ accounts,
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("payto_uri",
+ acc->payto_uri),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("conversion_url",
+ acc->conversion_url)),
+ GNUNET_JSON_pack_array_steal ("debit_restrictions",
+ debit_restrictions),
+ GNUNET_JSON_pack_array_steal ("credit_restrictions",
+ credit_restrictions),
+ GNUNET_JSON_pack_data_auto ("master_sig",
+ &acc->master_sig))));
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Serialized %u/%u wire accounts to JSON\n",
+ (unsigned int) json_array_size (accounts),
+ kd->accounts_len);
+
+ wire_fees = json_object ();
+ GNUNET_assert (NULL != wire_fees);
+ for (unsigned int i = 0; i<kd->fees_len; i++)
+ {
+ const struct TALER_DONAU_WireFeesByMethod *fbw
+ = &kd->fees[i];
+ json_t *wf;
+
+ wf = json_array ();
+ GNUNET_assert (NULL != wf);
+ for (struct TALER_DONAU_WireAggregateFees *p = fbw->fees_head;
+ NULL != p;
+ p = p->next)
+ {
+ GNUNET_assert (
+ 0 ==
+ json_array_append_new (
+ wf,
+ GNUNET_JSON_PACK (
+ TALER_JSON_pack_amount ("wire_fee",
+ &p->fees.wire),
+ TALER_JSON_pack_amount ("closing_fee",
+ &p->fees.closing),
+ GNUNET_JSON_pack_timestamp ("start_date",
+ p->start_date),
+ GNUNET_JSON_pack_timestamp ("end_date",
+ p->end_date),
+ GNUNET_JSON_pack_data_auto ("sig",
+ &p->master_sig))));
+ }
+ GNUNET_assert (0 ==
+ json_object_set_new (wire_fees,
+ fbw->method,
+ wf));
+ }
+
+ recoup = json_array ();
+ GNUNET_assert (NULL != recoup);
+ for (unsigned int i = 0; i<kd->num_denom_keys; i++)
+ {
+ const struct TALER_DONAU_DenomPublicKey *dk
+ = &kd->denom_keys[i];
+ if (! dk->revoked)
+ continue;
+ GNUNET_assert (0 ==
+ json_array_append_new (
+ recoup,
+ GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_data_auto ("h_denom_pub",
+ &dk->h_key))));
+ }
+
+ wblwk = json_array ();
+ GNUNET_assert (NULL != wblwk);
+ for (unsigned int i = 0; i<kd->wblwk_length; i++)
+ {
+ const struct TALER_Amount *a = &kd->wallet_balance_limit_without_kyc[i];
+
+ GNUNET_assert (0 ==
+ json_array_append_new (
+ wblwk,
+ TALER_JSON_from_amount (a)));
+ }
+
+ keys = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("version",
+ kd->version),
+ GNUNET_JSON_pack_string ("currency",
+ kd->currency),
+ GNUNET_JSON_pack_uint64 ("currency_fraction_digits",
+ kd->currency_fraction_digits),
+ GNUNET_JSON_pack_array_steal ("signkeys",
+ signkeys),
+ GNUNET_JSON_pack_array_steal ("donation_units",
+ donation_units_by_group)
+ );
+ return GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_uint64 ("version",
+ DONAU_SERIALIZATION_FORMAT_VERSION),
+ GNUNET_JSON_pack_string ("donau_url",
+ kd->donau_url),
+ GNUNET_JSON_pack_object_steal ("keys",
+ keys));
+}
+
+
+/* end of donau_api_handle.c */
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [taler-donau] branch master updated: [lib] restore donau_api_handle,
gnunet <=