donau

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

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

[lib] work on API Keys implementation

Diffstat:
Msrc/include/donau_crypto_lib.h | 32+++++++++++++++++++++++++++++++-
Msrc/include/donau_service.h | 10+++++-----
Msrc/lib/donau_api_handle.c | 357++++++++++++++++++-------------------------------------------------------------
Msrc/util/donau_crypto.c | 34+++++++++++++++++++++++++++++++++-
4 files changed, 150 insertions(+), 283 deletions(-)

diff --git a/src/include/donau_crypto_lib.h b/src/include/donau_crypto_lib.h @@ -118,6 +118,36 @@ struct DONAU_DonationUnitHashP }; /** + * Compare two donation unit public keys. + * + * @param donation_unit1 first key + * @param donation_unit2 second key + * @return 0 if the keys are equal, otherwise -1 or 1 + */ +int +DONAU_donation_unit_pub_cmp (const struct DONAU_DonationUnitPublicKey *donation_unit1, + const struct DONAU_DonationUnitPublicKey *donation_unit2); + +/** + * Make a (deep) copy of the given @a donation_unit_src to + * @a donation_unit_dst. + * + * @param[out] donation_unit_dst target to copy to + * @param donation_unit_src public key to copy + */ +void +DONAU_donation_unit_pub_deep_copy (struct DONAU_DonationUnitPublicKey *donation_unit_dst, + const struct DONAU_DonationUnitPublicKey *donation_unit_src); + +/** + * Free internals of @a donation_unit_pub, but not @a donation_unit_pub itself. + * + * @param[in] donation_unit_pub key to free + */ +void +DONAU_donation_unit_pub_free (struct DONAU_DonationUnitPublicKey *donation_unit_pub); + +/** * Donor's hashed and salted unique donation identifier. */ struct DONAU_HashDonorTaxId @@ -332,7 +362,7 @@ TALER_donation_unit_group_get_key ( * The corresponding JSON-blob will also contain an array of particular * donation units with only the cipher-specific public key. */ -struct TALER_DonationUnitGroup +struct DONAU_DonationUnitGroup { /** diff --git a/src/include/donau_service.h b/src/include/donau_service.h @@ -380,11 +380,11 @@ DONAU_keys_decref (struct DONAU_Keys *keys); * @param year given year * @return #GNUNET_OK if @a pub is (according to /keys and @a year) the corresponding signing key */ -enum GNUNET_GenericReturnValue -DONAU_test_signing_key ( - const struct DONAU_Keys *keys, - const unsigned int year, - const struct DONAU_EddsaPublicKeyP *pub); +// enum GNUNET_GenericReturnValue +// DONAU_test_signing_key ( // always current revocation not yet supported +// const struct DONAU_Keys *keys, +// const unsigned int year, +// const struct DONAU_EddsaPublicKeyP *pub); /** diff --git a/src/lib/donau_api_handle.c b/src/lib/donau_api_handle.c @@ -96,7 +96,7 @@ struct DONAU_GetKeysHandle /** * Previous /keys response, NULL for none. */ - struct DONAU_Keys *prev_keys; + struct DONAU_Keys *prev_keys; // not used, as keys are always completely reloaded /** * Entry for this request with the `struct GNUNET_CURL_Context`. @@ -107,7 +107,7 @@ struct DONAU_GetKeysHandle * Expiration time according to "Expire:" header. * 0 if not provided by the server. */ - struct GNUNET_TIME_Timestamp expire; + struct GNUNET_TIME_Timestamp expire; // not used -> no expiration, always 0 /** * Function to call with the donau's certification data, @@ -160,6 +160,37 @@ parse_json_signkey (struct DONAU_SigningPublicKeyAndValidity *sign_key, } /** + * Compare two donation unit keys. + * + * @param donation_unit1 first donation unit key + * @param donation_unit2 second donation unit key + * @return 0 if the two keys are equal (not necessarily + * the same object), 1 otherwise. + */ +static unsigned int +donation_units_cmp (const struct DONAU_DonationUnitInformation *donation_unit1, + const struct DONAU_DonationUnitInformation *donation_unit2) +{ + struct DONAU_DonationUnitInformation tmp1; + struct DONAU_DonationUnitInformation tmp2; + + if (0 != + DONAU_donation_unit_pub_cmp (&donation_unit1->key, + &donation_unit2->key)) + return 1; + tmp1 = *donation_unit1; + tmp2 = *donation_unit2; + memset (&tmp1.key, + 0, + sizeof (tmp1.key)); + memset (&tmp2.key, + 0, + sizeof (tmp2.key)); + return GNUNET_memcmp (&tmp1, + &tmp2); +} + +/** * Decode the JSON in @a resp_obj from the /keys response * and store the data in the @a key_data. * @@ -319,7 +350,7 @@ decode_keys_json (const json_t *resp_obj, { /* First, parse { cipher, value, hash } of the current group. */ - struct TALER_DonationUnitGroup group = {0}; + struct DONAU_DonationUnitGroup group = {0}; const json_t *donation_unit_keys_array; struct GNUNET_JSON_Specification group_spec[] = { TALER_JSON_spec_denomination_group (NULL, // TODO: check method @@ -353,7 +384,7 @@ decode_keys_json (const json_t *resp_obj, bool found = false; struct GNUNET_JSON_Specification kspec[] = { - TALER_JSON_spec_denom_pub_cipher (NULL, + TALER_JSON_spec_denom_pub_cipher (NULL, // TODO write new JSON function group.cipher, &dk->key), GNUNET_JSON_spec_end () @@ -372,7 +403,7 @@ decode_keys_json (const json_t *resp_obj, j<key_data->num_donation_unit_keys; j++) { - if (0 == GNUNET_CRYPTO_bsign_pub_cmp (&dk, + if (0 == donation_units_cmp (&dk.key, &key_data->donation_unit_keys[j])) { found = true; @@ -384,7 +415,7 @@ decode_keys_json (const json_t *resp_obj, { /* 0:0:0 did not support /keys cherry picking */ TALER_LOG_DEBUG ("Skipping donation unit key: already know it\n"); - TALER_denom_pub_free (&dk.key); + DONAU_donation_unit_pub_free (&dk.key); continue; } @@ -392,7 +423,7 @@ decode_keys_json (const json_t *resp_obj, 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; + key_data->donation_unit_keys[key_data->num_donation_unit_keys++] = dk; /* Update "last_denom_issue_date" */ TALER_LOG_DEBUG ("Adding donation unit key that is valid for the year %d\n", @@ -427,7 +458,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, @@ -435,20 +466,9 @@ keys_completed_cb (void *cls, gkh->job = NULL; GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Received keys from URL `%s' with status %ld and expiration %s.\n", + "Received keys from URL `%s' with status %ld.\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)); - } + response_code); switch (response_code) { case 0: @@ -465,50 +485,7 @@ keys_completed_cb (void *cls, } 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 donation unit 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_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); - 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, @@ -524,19 +501,6 @@ keys_completed_cb (void *cls, 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; @@ -580,108 +544,6 @@ keys_completed_cb (void *cls, /** - * 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. @@ -714,16 +576,16 @@ header_cb (char *buffer, "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; - } + // 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; } @@ -768,10 +630,10 @@ DONAU_get_keys ( 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_HEADERFUNCTION, + // &header_cb)); GNUNET_assert (CURLE_OK == curl_easy_setopt (eh, CURLOPT_HEADERDATA, @@ -800,46 +662,16 @@ DONAU_get_keys_cancel ( } -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_DonationUnitInformation * DONAU_get_donation_unit_key ( const struct DONAU_Keys *keys, - const struct TALER_DenominationPublicKey *pk) + const struct DONAU_DonationUnitPublicKey *pk) { - for (unsigned int i = 0; i<keys->num_denom_keys; i++) + for (unsigned int i = 0; i<keys->num_donation_unit_keys; i++) if (0 == - TALER_denom_pub_cmp (pk, - &keys->denom_keys[i].key)) - return &keys->denom_keys[i]; + DONAU_donation_unit_pub_cmp (pk, + &keys->donation_unit_keys[i].key)) + return &keys->donation_unit_keys[i]; return NULL; } @@ -852,7 +684,7 @@ DONAU_copy_donation_unit_key ( copy = GNUNET_new (struct DONAU_DonationUnitInformation); *copy = *key; - TALER_denom_pub_deep_copy (&copy->key, + DONAU_donation_unit_pub_deep_copy (&copy->key, // only increments rc, still same pointer &key->key); return copy; } @@ -862,7 +694,7 @@ void DONAU_destroy_donation_unit_key ( struct DONAU_DonationUnitInformation *key) { - TALER_denom_pub_free (&key->key); + DONAU_donation_unit_pub_free (&key->key); GNUNET_free (key); } @@ -870,12 +702,13 @@ DONAU_destroy_donation_unit_key ( const struct DONAU_DonationUnitInformation * DONAU_get_donation_unit_key_by_hash ( const struct DONAU_Keys *keys, - const struct TALER_DenominationHashP *hc) + const struct DONAU_DonationUnitHashP *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]; + for (unsigned int i = 0; i<keys->num_donation_unit_keys; i++) + // memcmp needs two pointer of the same type + if (0 == GNUNET_memcmp (&hc->hash, + &keys->donation_unit_keys[i].key.bsign_pub_key.pub_key_hash)) + return &keys->donation_unit_keys[i]; return NULL; } @@ -901,35 +734,14 @@ DONAU_keys_decref (struct DONAU_Keys *keys) 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); + for (unsigned int i = 0; i<keys->num_donation_unit_keys; i++) + DONAU_donation_unit_pub_free (&keys->donation_unit_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, + GNUNET_array_grow (keys->donation_unit_keys, + keys->donation_unit_keys_size, 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); } @@ -941,8 +753,6 @@ 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), @@ -950,10 +760,6 @@ DONAU_keys_from_json (const json_t *j) &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; @@ -984,7 +790,6 @@ DONAU_keys_from_json (const json_t *j) return NULL; } keys->rc = 1; - keys->key_data_expiration = expire; keys->donau_url = GNUNET_strdup (url); return keys; } @@ -1153,7 +958,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 DONAU_DonationUnitInformation *dk = &kd->denom_keys[i]; + const struct DONAU_DonationUnitInformation *dk = &kd->donation_unit_keys[i]; struct TALER_DenominationGroup meta = { .cipher = dk->key.cipher, .value = dk->value, @@ -1236,20 +1041,20 @@ DONAU_keys_to_json (const struct DONAU_Keys *kd) adenoms = json_array (); GNUNET_assert (NULL != adenoms); - for (unsigned int j = 0; j<ai->num_denom_keys; j++) + for (unsigned int j = 0; j<ai->num_donation_unit_keys; j++) { const struct TALER_DONAU_AuditorDenominationInfo *adi = - &ai->denom_keys[j]; + &ai->donation_unit_keys[j]; const struct DONAU_DonationUnitInformation *dk = - &kd->denom_keys[adi->denom_key_offset]; + &kd->donation_unit_keys[adi->denom_key_offset]; json_t *k; - GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys); + GNUNET_assert (adi->denom_key_offset < kd->num_donation_unit_keys); if (GNUNET_TIME_timestamp_cmp (now, >, dk->expire_deposit)) continue; /* skip auditor signatures for donation unit keys that have expired */ - GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys); + GNUNET_assert (adi->denom_key_offset < kd->num_donation_unit_keys); k = GNUNET_JSON_PACK ( GNUNET_JSON_pack_data_auto ("denom_pub_h", &dk->h_key), @@ -1378,10 +1183,10 @@ DONAU_keys_to_json (const struct DONAU_Keys *kd) recoup = json_array (); GNUNET_assert (NULL != recoup); - for (unsigned int i = 0; i<kd->num_denom_keys; i++) + for (unsigned int i = 0; i<kd->num_donation_unit_keys; i++) { const struct DONAU_DonationUnitInformation *dk - = &kd->denom_keys[i]; + = &kd->donation_unit_keys[i]; if (! dk->revoked) continue; GNUNET_assert (0 == diff --git a/src/util/donau_crypto.c b/src/util/donau_crypto.c @@ -31,7 +31,7 @@ GNUNET_NETWORK_STRUCT_BEGIN struct DonationUnitGroupP { /** - * Value of coins in this denomination group. + * Value of coins in this donation unit group. */ struct TALER_AmountNBO value; @@ -60,3 +60,34 @@ TALER_donation_unit_group_get_key ( key); } +int +DONAU_donation_unit_pub_cmp (const struct DONAU_DonationUnitPublicKey *donation_unit1, + const struct DONAU_DonationUnitPublicKey *donation_unit2) +{ + if (donation_unit1->bsign_pub_key->cipher != + donation_unit2->bsign_pub_key->cipher) + return (donation_unit1->bsign_pub_key->cipher > + donation_unit2->bsign_pub_key->cipher) ? 1 : -1; + if (donation_unit1->age_mask.bits != donation_unit2->age_mask.bits) + return (donation_unit1->age_mask.bits > donation_unit2->age_mask.bits) ? 1 : -1; + return GNUNET_CRYPTO_bsign_pub_cmp (donation_unit1->bsign_pub_key, + donation_unit2->bsign_pub_key); +} + +void +DONAU_donation_unit_pub_deep_copy (struct DONAU_DonationUnitPublicKey *donation_unit_dst, + const struct DONAU_DonationUnitPublicKey *donation_unit_src) +{ + donation_unit_dst->bsign_pub_key + = GNUNET_CRYPTO_bsign_pub_incref (donation_unit_src->bsign_pub_key); +} + +void +DONAU_donation_unit_pub_free (struct DONAU_DonationUnitPublicKey *donation_unit_pub) +{ + if (NULL != donation_unit_pub->bsign_pub_key) + { + GNUNET_CRYPTO_blind_sign_pub_decref (donation_unit_pub->bsign_pub_key); + donation_unit_pub->bsign_pub_key = NULL; + } +} +\ No newline at end of file