donau

Donation authority for GNU Taler (experimental)
Log | Files | Refs | Submodules | README | LICENSE

commit 36932835eb7ae1e6a9c8e04822845ff23957409d
parent d63b019e82960b60e5ba9571c4e6b5967cfea56e
Author: Matyja Lukas Adam <lukas.matyja@students.bfh.ch>
Date:   Sun,  7 Jan 2024 01:12:01 +0100

[lib] decode keys implementation

Diffstat:
Msrc/include/donau_crypto_lib.h | 22++++++++++++++++++++++
Msrc/include/donau_service.h | 7++++++-
Msrc/lib/donau_api_handle.c | 417+++++++++++++++----------------------------------------------------------------
3 files changed, 103 insertions(+), 343 deletions(-)

diff --git a/src/include/donau_crypto_lib.h b/src/include/donau_crypto_lib.h @@ -325,5 +325,27 @@ TALER_donation_unit_group_get_key ( const struct DONAU_DonationUnitGroup *dg, struct GNUNET_HashCode *key); +/** + * Group of donation units. These are the common fields of an array of + * donation units. + * + * The corresponding JSON-blob will also contain an array of particular + * donation units with only the cipher-specific public key. + */ +struct TALER_DonationUnitGroup +{ + + /** + * Value of coins in this denomination group. + */ + struct TALER_Amount value; + + /** + * Cipher used for the denomination. + */ + enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher; + + +}; #endif diff --git a/src/include/donau_service.h b/src/include/donau_service.h @@ -64,7 +64,7 @@ struct DONAU_DonationUnitInformation /** * amount of the donation */ - struct TALER_Amount donation_unit; + struct TALER_Amount value; /** * Year of validity @@ -129,6 +129,11 @@ struct DONAU_Keys */ unsigned int num_donation_unit_keys; + /** + * Actual length of the @e donation_unit_keys array (size of allocation). + */ + unsigned int donation_unit_keys_size; + /** * Reference counter for this structure. * Freed when it reaches 0. diff --git a/src/lib/donau_api_handle.c b/src/lib/donau_api_handle.c @@ -37,7 +37,7 @@ #include <gnunet/gnunet_crypto_lib.h> /** - * Which version of the Taler protocol is implemented + * Which version of the Donau protocol is implemented * by this library? Used to determine compatibility. */ #define DONAU_PROTOCOL_CURRENT 0 @@ -144,7 +144,7 @@ parse_json_signkey (struct DONAU_SigningPublicKeyAndValidity *sign_key, GNUNET_JSON_spec_fixed_auto ("key", &sign_key->key), GNUNET_JSON_spec_varsize ("year_of_validity", - &sign_key->year) + &sign_key->year), GNUNET_JSON_spec_end () }; @@ -159,7 +159,6 @@ parse_json_signkey (struct DONAU_SigningPublicKeyAndValidity *sign_key, return GNUNET_OK; } - /** * Decode the JSON in @a resp_obj from the /keys response * and store the data in the @a key_data. @@ -175,8 +174,8 @@ decode_keys_json (const json_t *resp_obj, struct DONAU_Keys *key_data, enum DONAU_VersionCompatibility *vc) { - struct DONAU_DonauPublicKeyP pub; - //const json_t *sign_keys_array; + //struct DONAU_DonauPublicKeyP pub; + const json_t *sign_keys_array; const json_t *donation_units_by_group; if (JSON_OBJECT != json_typeof (resp_obj)) @@ -220,92 +219,37 @@ decode_keys_json (const json_t *resp_obj, GNUNET_break_op (0); return GNUNET_SYSERR; } - *vc = DONAU_VC_MATCH; + *vc = DONAU_VC_MATCH; // 0 if (DONAU_PROTOCOL_CURRENT < current) { - *vc |= DONAU_VC_NEWER; + *vc |= DONAU_VC_NEWER; // 4 if (DONAU_PROTOCOL_CURRENT < current - age) - *vc |= DONAU_VC_INCOMPATIBLE; + *vc |= DONAU_VC_INCOMPATIBLE; // 1 } if (DONAU_PROTOCOL_CURRENT > current) { - *vc |= DONAU_VC_OLDER; + *vc |= DONAU_VC_OLDER; // 2 if (DONAU_PROTOCOL_CURRENT - DONAU_PROTOCOL_AGE > current) - *vc |= DONAU_VC_INCOMPATIBLE; + *vc |= DONAU_VC_INCOMPATIBLE; // 1 } key_data->version = GNUNET_strdup (ver); } { const char *currency; - const char *asset_type; struct GNUNET_JSON_Specification mspec[] = { - GNUNET_JSON_spec_fixed_auto ( - "donation_units_sig", - &donation_units_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", - &currency), - 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_fixed_auto ( + // "eddsa_pub", + // &pub), GNUNET_JSON_spec_array_const ( - "signkeys", + "signkeys", // naming convention? &sign_keys_array), + GNUNET_JSON_spec_string ( + "currency", + &currency), //&key_data->currency instead? GNUNET_JSON_spec_array_const ( "donation_units", &donation_units_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; @@ -313,7 +257,7 @@ decode_keys_json (const json_t *resp_obj, if (GNUNET_OK != GNUNET_JSON_parse (resp_obj, - (check_sig) ? mspec : &mspec[2], + mspec, // ask how this is done &emsg, &eline)) { @@ -324,19 +268,11 @@ decode_keys_json (const json_t *resp_obj, EXITIF (1); } { - struct GNUNET_JSON_Specification sspec[] = { - TALER_JSON_spec_amount ( - "stefan_abs", - currency, - &key_data->stefan_abs), - TALER_JSON_spec_amount ( - "stefan_log", + struct GNUNET_JSON_Specification sspec[] = { // why separate sspec and mspec? + TALER_JSON_spec_currency_specification ( + "currency_specification", currency, - &key_data->stefan_log), - TALER_JSON_spec_amount ( - "stefan_lin", - currency, - &key_data->stefan_lin), + &key_data->currency_specification), GNUNET_JSON_spec_end () }; @@ -347,9 +283,6 @@ decode_keys_json (const json_t *resp_obj, } 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 signing keys */ @@ -366,117 +299,37 @@ decode_keys_json (const json_t *resp_obj, 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)); + sign_key_obj)); } } - /* 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 donation unit keys, merging with the * possibly EXISTING array as required (/keys cherry picking). * * The donation units are grouped by common values of - * {cipher, value, fee, age_mask}. + * {cipher, value}. */ { json_t *group_obj; unsigned int group_idx; - json_array_foreach (donation_units_by_group, group_idx, group_obj) + json_array_foreach (donation_units_by_group, + group_idx, group_obj) { - /* Running XOR of each SHA512 hash of the donation units' 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 + /* First, parse { cipher, value, hash } of the current group. */ - struct TALER_DenominationGroup group = {0}; - const json_t *denom_keys_array; + struct TALER_DonationUnitGroup group = {0}; + const json_t *donation_unit_keys_array; struct GNUNET_JSON_Specification group_spec[] = { - TALER_JSON_spec_donation_unit_group (NULL, + TALER_JSON_spec_denomination_group (NULL, // TODO: check method key_data->currency, &group), - GNUNET_JSON_spec_array_const ("denoms", - &denom_keys_array), + GNUNET_JSON_spec_array_const ("donation_units", // TODO: check method + &donation_unit_keys_array), GNUNET_JSON_spec_end () }; - json_t *denom_key_obj; + json_t *donation_unit_key_obj; unsigned int index; EXITIF (GNUNET_SYSERR == @@ -486,37 +339,41 @@ decode_keys_json (const json_t *resp_obj, NULL)); /* Now, parse the individual donation units */ - json_array_foreach (denom_keys_array, index, denom_key_obj) + json_array_foreach (donation_unit_keys_array, + index, + donation_unit_key_obj) { /* Set the common fields from the group for this particular donation unit. Required to make the validity check inside parse_json_denomkey_partially pass */ - struct DONAU_DenomPublicKey dk = { - .key.cipher = group.cipher, + struct DONAU_DonationUnitInformation dk = { .value = group.value, - .fees = group.fees, - .key.age_mask = group.age_mask + .year = group.year }; bool found = false; - EXITIF (GNUNET_SYSERR == //was partially - parse_json_donation_unit_key (&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); + struct GNUNET_JSON_Specification kspec[] = { + TALER_JSON_spec_denom_pub_cipher (NULL, + group.cipher, + &dk->key), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (donation_unit_key_obj, + kspec, + NULL, NULL)) + { + GNUNET_break_op (0); + EXITIF(1); + } + for (unsigned int j = 0; - j<key_data->num_denom_keys; + j<key_data->num_donation_unit_keys; j++) { if (0 == GNUNET_CRYPTO_bsign_pub_cmp (&dk, - &key_data->denom_keys[j])) + &key_data->donation_unit_keys[j])) { found = true; break; @@ -531,145 +388,21 @@ decode_keys_json (const json_t *resp_obj, 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; + if (key_data->donation_unit_keys_size == key_data->num_donation_unit_keys) + GNUNET_array_grow (key_data->donation_unit_keys, + key_data->donation_unit_keys_size, + key_data->donation_unit_keys_size * 2 + 2); + key_data->denom_keys[key_data->num_donation_unit_keys++] = dk; /* Update "last_denom_issue_date" */ - TALER_LOG_DEBUG ("Adding donation unit 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 donation units */ + TALER_LOG_DEBUG ("Adding donation unit key that is valid for the year %d\n", + dk.year); - /* 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 donation units */ } /* end of json_array_foreach over groups of donation units */ } /* 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 donation unit 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, - &donation_units_sig)); - } return GNUNET_OK; EXITIF_exit: @@ -694,7 +427,7 @@ keys_completed_cb (void *cls, struct DONAU_GetKeysHandle *gkh = cls; const json_t *j = resp_obj; struct DONAU_Keys *kd = NULL; - struct DONAU_KeysResponse kresp = { + struct DONAU_KeysResponse kresp = { // ?? .hr.reply = j, .hr.http_status = (unsigned int) response_code, .details.ok.compat = DONAU_VC_PROTOCOL_ERROR, @@ -749,7 +482,7 @@ keys_completed_cb (void *cls, GNUNET_memcpy (kd->denom_keys, kd_old->denom_keys, kd_old->num_denom_keys - * sizeof (struct DONAU_DenomPublicKey)); + * sizeof (struct DONAU_DonationUnitInformation)); 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); @@ -1097,7 +830,7 @@ DONAU_test_signing_key ( } -const struct DONAU_DenomPublicKey * +const struct DONAU_DonationUnitInformation * DONAU_get_donation_unit_key ( const struct DONAU_Keys *keys, const struct TALER_DenominationPublicKey *pk) @@ -1111,13 +844,13 @@ DONAU_get_donation_unit_key ( } -struct DONAU_DenomPublicKey * +struct DONAU_DonationUnitInformation * DONAU_copy_donation_unit_key ( - const struct DONAU_DenomPublicKey *key) + const struct DONAU_DonationUnitInformation *key) { - struct DONAU_DenomPublicKey *copy; + struct DONAU_DonationUnitInformation *copy; - copy = GNUNET_new (struct DONAU_DenomPublicKey); + copy = GNUNET_new (struct DONAU_DonationUnitInformation); *copy = *key; TALER_denom_pub_deep_copy (&copy->key, &key->key); @@ -1127,14 +860,14 @@ DONAU_copy_donation_unit_key ( void DONAU_destroy_donation_unit_key ( - struct DONAU_DenomPublicKey *key) + struct DONAU_DonationUnitInformation *key) { TALER_denom_pub_free (&key->key); GNUNET_free (key); } -const struct DONAU_DenomPublicKey * +const struct DONAU_DonationUnitInformation * DONAU_get_donation_unit_key_by_hash ( const struct DONAU_Keys *keys, const struct TALER_DenominationHashP *hc) @@ -1420,7 +1153,7 @@ DONAU_keys_to_json (const struct DONAU_Keys *kd) false); for (unsigned int i = 0; i<kd->num_donation_unit_keys; i++) { - const struct TALER_DONAU_DenomPublicKey *dk = &kd->denom_keys[i]; + const struct DONAU_DonationUnitInformation *dk = &kd->denom_keys[i]; struct TALER_DenominationGroup meta = { .cipher = dk->key.cipher, .value = dk->value, @@ -1507,7 +1240,7 @@ DONAU_keys_to_json (const struct DONAU_Keys *kd) { const struct TALER_DONAU_AuditorDenominationInfo *adi = &ai->denom_keys[j]; - const struct TALER_DONAU_DenomPublicKey *dk = + const struct DONAU_DonationUnitInformation *dk = &kd->denom_keys[adi->denom_key_offset]; json_t *k; @@ -1647,7 +1380,7 @@ DONAU_keys_to_json (const struct DONAU_Keys *kd) GNUNET_assert (NULL != recoup); for (unsigned int i = 0; i<kd->num_denom_keys; i++) { - const struct TALER_DONAU_DenomPublicKey *dk + const struct DONAU_DonationUnitInformation *dk = &kd->denom_keys[i]; if (! dk->revoked) continue;