donau

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

commit d01099773d965fc9e47e55e520af765020549d6e
parent 58047a5cc2d7ad5006a94690fc9b249b6062bb15
Author: Matyja Lukas Adam <lukas.matyja@students.bfh.ch>
Date:   Mon, 15 Jan 2024 10:41:51 +0100

Merge remote-tracking branch 'refs/remotes/origin/master'

Diffstat:
Msrc/donau/Makefile.am | 1+
Msrc/donau/donau-httpd.c | 8+++-----
Msrc/donau/donau-httpd_get-history-entry.c | 7+++----
Msrc/donau/donau-httpd_keys.c | 838+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Msrc/donau/donau-httpd_keys.h | 4++--
Asrc/donau/donau-httpd_post-submit-receipt.c | 155+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/donau/donau-httpd_receipt.h | 41+++++++++++++++++++++++++++++++++++++++++
Msrc/donaudb/0002-donation_units.sql | 2+-
Msrc/donaudb/pg_insert_submitted_receipt.c | 8+++++---
Msrc/donaudb/pg_insert_submitted_receipt.h | 8+++++---
Msrc/include/donau_crypto_lib.h | 565+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/include/donau_service.h | 20++++----------------
Msrc/include/donaudb_plugin.h | 2+-
Msrc/util/Makefile.am | 5++++-
Asrc/util/crypto_helper_common.c | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/util/crypto_helper_common.h | 41+++++++++++++++++++++++++++++++++++++++++
Asrc/util/crypto_helper_cs.c | 1317+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/util/crypto_helper_esign.c | 557+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/util/crypto_helper_rsa.c | 917+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
19 files changed, 4249 insertions(+), 298 deletions(-)

diff --git a/src/donau/Makefile.am b/src/donau/Makefile.am @@ -46,6 +46,7 @@ donau_httpd_SOURCES = \ donau-httpd_get-charity.c donau-httpd_post-charity.c \ donau-httpd_get-history-entry.c donau-httpd_history.h \ donau-httpd_get-history.c \ + donau-httpd_post-submit-receipt.c donau_httpd_receipt.h \ donau-httpd_terms.c donau-httpd_terms.h # Testcases diff --git a/src/donau/donau-httpd.c b/src/donau/donau-httpd.c @@ -52,7 +52,7 @@ * Above what request latency do we start to log? */ #define WARN_LATENCY GNUNET_TIME_relative_multiply ( \ - GNUNET_TIME_UNIT_MILLISECONDS, 500) + GNUNET_TIME_UNIT_MILLISECONDS, 500) /** * Are clients allowed to request /keys for times other than the @@ -442,8 +442,7 @@ handle_mhd_request (void *cls, { .url = "keys", .method = MHD_HTTP_METHOD_GET, - .handler.get = &DH_keys_get_handler// , - // .nargs = 1 + .handler.get = &DH_handler_keys }, /* GET charities */ { @@ -1008,4 +1007,4 @@ main (int argc, } -/* end of donau-httpd.c */ -\ No newline at end of file +/* end of donau-httpd.c */ diff --git a/src/donau/donau-httpd_get-history-entry.c b/src/donau/donau-httpd_get-history-entry.c @@ -68,8 +68,8 @@ DH_handler_history_entry_get ( } { - const struct TALER_Amount *final_amount; - const uint64_t donation_year; + struct TALER_Amount final_amount; + uint64_t donation_year; enum GNUNET_DB_QueryStatus qs; MHD_RESULT result; @@ -102,11 +102,10 @@ DH_handler_history_entry_get ( rc->connection, MHD_HTTP_OK, TALER_JSON_pack_amount ("final_amount", - final_amount), + &final_amount), GNUNET_JSON_pack_uint64 ("donation_year", donation_year)); - GNUNET_free (final_amount); return result; } } diff --git a/src/donau/donau-httpd_keys.c b/src/donau/donau-httpd_keys.c @@ -1,23 +1,24 @@ /* - This file is part of TALER - Copyright (C) 2020-2024 Taler Systems SA + This file is part of TALER + Copyright (C) 2020-2024 Taler Systems SA - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ /** * @file donau-httpd_keys.c * @brief management of our various keys * @author Christian Grothoff * @author Özgür Kesim + * @author Pius Loosli */ #include <taler/platform.h> #include <taler/taler_json_lib.h> @@ -26,6 +27,8 @@ #include "donau-httpd_keys.h" #include "donau-httpd_config.h" #include "donaudb_plugin.h" +#include "donau_util.h" + /** * How many /keys request do we hold in suspension at @@ -98,6 +101,21 @@ static struct GNUNET_SCHEDULER_Task *keys_tt; static bool terminating; /** + * RSA security module public key, all zero if not known. + */ +static struct TALER_SecurityModulePublicKeyP donation_unit_rsa_sm_pub; + +/** + * CS security module public key, all zero if not known. + */ +static struct TALER_SecurityModulePublicKeyP donation_unit_cs_sm_pub; + +/** + * EdDSA security module public key, all zero if not known. + */ +static struct TALER_SecurityModulePublicKeyP esign_sm_pub; + +/** * Function called to forcefully resume suspended keys requests. * * @param cls unused, NULL @@ -115,17 +133,14 @@ keys_timeout_cb (void *cls) break; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Resuming /keys request due to timeout\n"); - GNUNET_CONTAINER_DLL_remove (skr_head, - skr_tail, - skr); + GNUNET_CONTAINER_DLL_remove (skr_head, skr_tail, skr); MHD_resume_connection (skr->connection); TALER_MHD_daemon_trigger (); GNUNET_free (skr); } if (NULL == skr) return; - keys_tt = GNUNET_SCHEDULER_add_at (skr->timeout, - &keys_timeout_cb, + keys_tt = GNUNET_SCHEDULER_add_at (skr->timeout, &keys_timeout_cb, NULL); } @@ -208,6 +223,11 @@ struct HelperDonationUnit struct DONAU_DonationUnitPublicKey donation_unit_pub; /** + * Signature over this key from the security module's key. + */ + struct TALER_SecurityModuleSignatureP sm_sig; + + /** * Details depend on the @e donation_unit_pub.cipher type. */ union @@ -230,7 +250,6 @@ struct HelperDonationUnit */ char *section_name; - }; /** @@ -262,18 +281,15 @@ static uint64_t key_generation; * RSA security module public key, all zero if not known. */ // static struct TALER_SecurityModulePublicKeyP donation_unit_rsa_sm_pub; - /** * CS security module public key, all zero if not known. */ // static struct TALER_SecurityModulePublicKeyP donation_unit_cs_sm_pub; - /** * EdDSA security module public key, all zero if not known. */ // static struct TALER_SecurityModulePublicKeyP esign_sm_pub; - /** * When do we forcefully timeout a /keys request? */ @@ -310,7 +326,7 @@ struct DH_KeyStateHandle * Mapping from donation unit keys to donation unit key issue struct. * Used to lookup the key by hash. */ - struct GNUNET_CONTAINER_MultiHashMap *denomkey_map; + struct GNUNET_CONTAINER_MultiHashMap *donation_unit_key_map; /** * Map from `struct DONAU_DonauPublicKey` to `struct SigningKey` @@ -411,30 +427,30 @@ struct HelperState /** * Handle for the esign/EdDSA helper. */ - struct TALER_CRYPTO_ExchangeSignHelper *esh; + struct DONAU_CRYPTO_DonauSignHelper *esh; /** * Handle for the donation_unit/RSA helper. */ - struct TALER_CRYPTO_RsaDenominationHelper *rsadh; + struct DONAU_CRYPTO_RsaDonationUnitHelper *rsadh; /** * Handle for the donation_unit/CS helper. */ - struct TALER_CRYPTO_CsDenominationHelper *csdh; + struct DONAU_CRYPTO_CsDonationUnitHelper *csdh; /** - * Map from H(donation_unit_pub) to `struct HelperDenomination` entries. + * Map from H(donation_unit_pub) to `struct HelperDonationUnit` entries. */ struct GNUNET_CONTAINER_MultiHashMap *donation_unit_keys; /** - * Map from H(rsa_pub) to `struct HelperDenomination` entries. + * Map from H(rsa_pub) to `struct HelperDonationUnit` entries. */ struct GNUNET_CONTAINER_MultiHashMap *rsa_keys; /** - * Map from H(cs_pub) to `struct HelperDenomination` entries. + * Map from H(cs_pub) to `struct HelperDonationUnit` entries. */ struct GNUNET_CONTAINER_MultiHashMap *cs_keys; @@ -506,21 +522,17 @@ add_sign_key_cb (void *cls, // sk->meta.start.abs_time, // sk->meta.expire_sign.abs_time)); // } - GNUNET_assert ( - 0 == - json_array_append_new ( - ctx->signkeys, - GNUNET_JSON_PACK ( - // GNUNET_JSON_pack_timestamp ("stamp_start", - // sk->meta.start), - // GNUNET_JSON_pack_timestamp ("stamp_expire", - // sk->meta.expire_sign), - // GNUNET_JSON_pack_timestamp ("stamp_end", - // sk->meta.expire_legal), - // GNUNET_JSON_pack_data_auto ("master_sig", - // &sk->master_sig), - GNUNET_JSON_pack_data_auto ("key", - &sk->donau_pub)))); + GNUNET_assert (0 == json_array_append_new (ctx->signkeys, GNUNET_JSON_PACK ( + // GNUNET_JSON_pack_timestamp ("stamp_start", + // sk->meta.start), + // GNUNET_JSON_pack_timestamp ("stamp_expire", + // sk->meta.expire_sign), + // GNUNET_JSON_pack_timestamp ("stamp_end", + // sk->meta.expire_legal), + // GNUNET_JSON_pack_data_auto ("master_sig", + // &sk->master_sig), + GNUNET_JSON_pack_data_auto ( + "key", &sk->donau_pub)))); return GNUNET_OK; } @@ -539,26 +551,21 @@ setup_general_response_headers (void *cls, char dat[128]; TALER_MHD_add_global_headers (response); - GNUNET_break (MHD_YES == - MHD_add_response_header (response, - MHD_HTTP_HEADER_CONTENT_TYPE, - "application/json")); - TALER_MHD_get_date_string (ksh->reload_time.abs_time, - dat); - GNUNET_break (MHD_YES == - MHD_add_response_header (response, - MHD_HTTP_HEADER_LAST_MODIFIED, - dat)); + GNUNET_break ( + MHD_YES == MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE, + "application/json")); + TALER_MHD_get_date_string (ksh->reload_time.abs_time, dat); + GNUNET_break ( + MHD_YES == MHD_add_response_header (response, MHD_HTTP_HEADER_LAST_MODIFIED, + dat)); /* Set cache control headers: our response varies depending on these headers */ - GNUNET_break (MHD_YES == - MHD_add_response_header (response, - MHD_HTTP_HEADER_VARY, - MHD_HTTP_HEADER_ACCEPT_ENCODING)); + GNUNET_break ( + MHD_YES == MHD_add_response_header (response, MHD_HTTP_HEADER_VARY, + MHD_HTTP_HEADER_ACCEPT_ENCODING)); /* Information is always public, revalidate after 1 hour */ - GNUNET_break (MHD_YES == - MHD_add_response_header (response, - MHD_HTTP_HEADER_CACHE_CONTROL, - "public,max-age=3600")); + GNUNET_break ( + MHD_YES == MHD_add_response_header (response, MHD_HTTP_HEADER_CACHE_CONTROL, + "public,max-age=3600")); } @@ -586,8 +593,7 @@ finish_keys_response (struct DH_KeyStateHandle *ksh) sctx.signkeys = json_array (); GNUNET_assert (NULL != sctx.signkeys); sctx.min_sk_frequency = GNUNET_TIME_UNIT_FOREVER_REL; - GNUNET_CONTAINER_multipeermap_iterate (ksh->signkey_map, - &add_sign_key_cb, + GNUNET_CONTAINER_multipeermap_iterate (ksh->signkey_map, &add_sign_key_cb, &sctx); recoup = json_array (); GNUNET_assert (NULL != recoup); @@ -598,8 +604,8 @@ finish_keys_response (struct DH_KeyStateHandle *ksh) // .min_dk_frequency = GNUNET_TIME_UNIT_FOREVER_REL, // }; - // GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map, - // &add_denom_key_cb, + // GNUNET_CONTAINER_multihashmap_iterate (ksh->donation_unit_key_map, + // &add_donation_unit_key_cb, // &dkc); // ksh->rekey_frequency // = GNUNET_TIME_relative_min (dkc.min_dk_frequency, @@ -618,15 +624,14 @@ finish_keys_response (struct DH_KeyStateHandle *ksh) { struct GNUNET_HashCode hc; - GNUNET_CRYPTO_hash_context_finish (hash_context, - &hc); + GNUNET_CRYPTO_hash_context_finish (hash_context, &hc); // if (GNUNET_OK != // create_krd (ksh, // &hc, // last_cherry_pick_date, // sctx.signkeys, // recoup, - // grouped_denominations, + // grouped_donation_units, // &grouped_hash_xor)) // { // GNUNET_log (GNUNET_ERROR_TYPE_WARNING, @@ -638,8 +643,9 @@ finish_keys_response (struct DH_KeyStateHandle *ksh) } else { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "No donation unit keys available. Refusing to generate /keys response.\n"); + GNUNET_log ( + GNUNET_ERROR_TYPE_WARNING, + "No donation unit keys available. Refusing to generate /keys response.\n"); GNUNET_CRYPTO_hash_context_abort (hash_context); } @@ -670,7 +676,7 @@ clear_donation_unit_cb (void *cls, (void) cls; (void) h_donation_unit_pub; - // TALER_denom_pub_free (&dk->denom_pub); + // TALER_donation_unit_pub_free (&dk->donation_unit_pub); GNUNET_free (dk); return GNUNET_OK; } @@ -706,7 +712,7 @@ clear_signkey_cb (void *cls, static void clear_response_cache (struct DH_KeyStateHandle *ksh) { - for (unsigned int i = 0; i<ksh->krd_array_length; i++) + for (unsigned int i = 0; i < ksh->krd_array_length; i++) { struct KeysResponseData *krd = &ksh->krd_array[i]; @@ -714,9 +720,7 @@ clear_response_cache (struct DH_KeyStateHandle *ksh) MHD_destroy_response (krd->response_uncompressed); GNUNET_free (krd->etag); } - GNUNET_array_grow (ksh->krd_array, - ksh->krd_array_length, - 0); + GNUNET_array_grow (ksh->krd_array, ksh->krd_array_length, 0); } @@ -728,9 +732,151 @@ clear_response_cache (struct DH_KeyStateHandle *ksh) static void sync_key_helpers (struct HelperState *hs) { - TALER_CRYPTO_helper_rsa_poll (hs->rsadh); - TALER_CRYPTO_helper_cs_poll (hs->csdh); - TALER_CRYPTO_helper_esign_poll (hs->esh); + DONAU_CRYPTO_helper_rsa_poll (hs->rsadh); + DONAU_CRYPTO_helper_cs_poll (hs->csdh); +// DONAU_CRYPTO_helper_esign_poll (hs->esh); +} + + +void +DH_resume_keys_requests (bool do_shutdown) +{ + struct SuspendedKeysRequests *skr; + + if (do_shutdown) + terminating = true; + while (NULL != (skr = skr_head)) + { + GNUNET_CONTAINER_DLL_remove (skr_head, + skr_tail, + skr); + skr_size--; + MHD_resume_connection (skr->connection); + TALER_MHD_daemon_trigger (); + GNUNET_free (skr); + } +} + + +/** + * Check that the given RSA security module's public key is the one + * we have pinned. If it does not match, we die hard. + * + * @param sm_pub RSA security module public key to check + */ +static void +check_donation_unit_rsa_sm_pub (const struct + TALER_SecurityModulePublicKeyP *sm_pub) +{ + if (0 != + GNUNET_memcmp (sm_pub, + &donation_unit_rsa_sm_pub)) + { + if (! GNUNET_is_zero (&donation_unit_rsa_sm_pub)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Our RSA security module changed its key. This must not happen.\n"); + GNUNET_assert (0); + } + donation_unit_rsa_sm_pub = *sm_pub; /* TOFU ;-) */ + } +} + + +/** + * Check that the given CS security module's public key is the one + * we have pinned. If it does not match, we die hard. + * + * @param sm_pub RSA security module public key to check + */ +static void +check_donation_unit_cs_sm_pub (const struct + TALER_SecurityModulePublicKeyP *sm_pub) +{ + if (0 != + GNUNET_memcmp (sm_pub, + &donation_unit_cs_sm_pub)) + { + if (! GNUNET_is_zero (&donation_unit_cs_sm_pub)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Our CS security module changed its key. This must not happen.\n"); + GNUNET_assert (0); + } + donation_unit_cs_sm_pub = *sm_pub; /* TOFU ;-) */ + } +} + + +/** + * Check that the given EdDSA security module's public key is the one + * we have pinned. If it does not match, we die hard. + * + * @param sm_pub EdDSA security module public key to check + */ +static void +check_esign_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub) +{ + if (0 != + GNUNET_memcmp (sm_pub, + &esign_sm_pub)) + { + if (! GNUNET_is_zero (&esign_sm_pub)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Our EdDSA security module changed its key. This must not happen.\n"); + GNUNET_assert (0); + } + esign_sm_pub = *sm_pub; /* TOFU ;-) */ + } +} + + +/** + * Helper function for #destroy_key_helpers to free all entries + * in the `donation_unit_keys` map. + * + * @param cls the `struct HelperDonationUnit` + * @param h_donation_unit_pub hash of the donation unit public key + * @param value the `struct HelperDonationUnit` to release + * @return #GNUNET_OK (continue to iterate) + */ +static enum GNUNET_GenericReturnValue +free_donation_unit_cb (void *cls, + const struct GNUNET_HashCode *h_donation_unit_pub, + void *value) +{ + struct HelperDonationUnit *hd = value; + + (void) cls; + (void) h_donation_unit_pub; + DONAU_donation_unit_pub_free (&hd->donation_unit_pub); + GNUNET_free (hd->section_name); + GNUNET_free (hd); + return GNUNET_OK; +} + + +/** + * Helper function for #destroy_key_helpers to free all entries + * in the `esign_keys` map. + * + * @param cls the `struct HelperSignkey` + * @param pid unused, matches the exchange public key + * @param value the `struct HelperSignkey` to release + * @return #GNUNET_OK (continue to iterate) + */ +static enum GNUNET_GenericReturnValue +free_esign_cb (void *cls, + const struct GNUNET_PeerIdentity *pid, + void *value) +{ + struct HelperSignkey *hsk = value; + + (void) cls; + (void) pid; + GNUNET_free (hsk); + return GNUNET_OK; } @@ -743,15 +889,15 @@ sync_key_helpers (struct HelperState *hs) static void destroy_key_helpers (struct HelperState *hs) { - // GNUNET_CONTAINER_multihashmap_iterate (hs->denom_keys, - // &free_denom_cb, + // GNUNET_CONTAINER_multihashmap_iterate (hs->donation_unit_keys, + // &free_donation_unit_cb, // hs); // GNUNET_CONTAINER_multihashmap_destroy (hs->rsa_keys); // hs->rsa_keys = NULL; // GNUNET_CONTAINER_multihashmap_destroy (hs->cs_keys); // hs->cs_keys = NULL; - // GNUNET_CONTAINER_multihashmap_destroy (hs->denom_keys); - // hs->denom_keys = NULL; + // GNUNET_CONTAINER_multihashmap_destroy (hs->donation_unit_keys); + // hs->donation_unit_keys = NULL; // GNUNET_CONTAINER_multipeermap_iterate (hs->esign_keys, // &free_esign_cb, // hs); @@ -759,17 +905,17 @@ destroy_key_helpers (struct HelperState *hs) hs->esign_keys = NULL; if (NULL != hs->rsadh) { - TALER_CRYPTO_helper_rsa_disconnect (hs->rsadh); + DONAU_CRYPTO_helper_rsa_disconnect (hs->rsadh); hs->rsadh = NULL; } if (NULL != hs->csdh) { - TALER_CRYPTO_helper_cs_disconnect (hs->csdh); + DONAU_CRYPTO_helper_cs_disconnect (hs->csdh); hs->csdh = NULL; } if (NULL != hs->esh) { - TALER_CRYPTO_helper_esign_disconnect (hs->esh); + DONAU_CRYPTO_helper_esign_disconnect (hs->esh); hs->esh = NULL; } } @@ -796,12 +942,10 @@ destroy_key_state (struct DH_KeyStateHandle *ksh, // gf); // GNUNET_free (gf); // } - GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map, - &clear_donation_unit_cb, - ksh); - GNUNET_CONTAINER_multihashmap_destroy (ksh->denomkey_map); - GNUNET_CONTAINER_multipeermap_iterate (ksh->signkey_map, - &clear_signkey_cb, + GNUNET_CONTAINER_multihashmap_iterate (ksh->donation_unit_key_map, + &clear_donation_unit_cb, ksh); + GNUNET_CONTAINER_multihashmap_destroy (ksh->donation_unit_key_map); + GNUNET_CONTAINER_multipeermap_iterate (ksh->signkey_map, &clear_signkey_cb, ksh); GNUNET_CONTAINER_multipeermap_destroy (ksh->signkey_map); // json_decref (ksh->auditors); @@ -823,6 +967,218 @@ destroy_key_state (struct DH_KeyStateHandle *ksh, /** + * Function called with information about available keys for signing. Usually + * only called once per key upon connect. Also called again in case a key is + * being revoked, in that case with an @a end_time of zero. + * + * @param cls closure with the `struct HelperState *` + * @param section_name name of the denomination type in the configuration; + * NULL if the key has been revoked or purged + * @param start_time when does the key become available for signing; + * zero if the key has been revoked or purged + * @param validity_duration how long does the key remain available for signing; + * zero if the key has been revoked or purged + * @param h_rsa hash of the @a denom_pub that is available (or was purged) + * @param bs_pub the public key itself, NULL if the key was revoked or purged + * @param sm_pub public key of the security module, NULL if the key was revoked or purged + * @param sm_sig signature from the security module, NULL if the key was revoked or purged + * The signature was already verified against @a sm_pub. + */ +static void +helper_rsa_cb ( + void *cls, + const char *section_name, + struct GNUNET_TIME_Timestamp start_time, + struct GNUNET_TIME_Relative validity_duration, + const struct TALER_RsaPubHashP *h_rsa, + struct GNUNET_CRYPTO_BlindSignPublicKey *bs_pub, + const struct TALER_SecurityModulePublicKeyP *sm_pub, + const struct TALER_SecurityModuleSignatureP *sm_sig) +{ + struct HelperState *hs = cls; + struct HelperDonationUnit *hd; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "RSA helper announces key %s for denomination type %s with validity %s\n", + GNUNET_h2s (&h_rsa->hash), + section_name, + GNUNET_STRINGS_relative_time_to_string (validity_duration, + GNUNET_NO)); + key_generation++; + DH_resume_keys_requests (false); + hd = GNUNET_CONTAINER_multihashmap_get (hs->rsa_keys, + &h_rsa->hash); + if (NULL != hd) + { + /* should be just an update (revocation!), so update existing entry */ + hd->validity_duration = validity_duration; + return; + } + GNUNET_assert (NULL != sm_pub); + check_donation_unit_rsa_sm_pub (sm_pub); + hd = GNUNET_new (struct HelperDonationUnit); + hd->start_time = start_time; + hd->validity_duration = validity_duration; + hd->h_details.h_rsa = *h_rsa; + hd->sm_sig = *sm_sig; + GNUNET_assert (GNUNET_CRYPTO_BSA_RSA == bs_pub->cipher); + hd->donation_unit_pub.bsign_pub_key = + GNUNET_CRYPTO_bsign_pub_incref (bs_pub); +// DONAU_Donation_unit_pub_hash(&hd->donation_unit_pub, +// &hd->h_donation_unit_pub); +// hd->section_name = GNUNET_strdup (section_name); +// GNUNET_assert ( +// GNUNET_OK == +// GNUNET_CONTAINER_multihashmap_put ( +// hs->donation_unit_keys, +// &hd->h_donation_unit_pub, +// hd, +// GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); +// GNUNET_assert ( +// GNUNET_OK == +// GNUNET_CONTAINER_multihashmap_put ( +// hs->rsa_keys, +// &hd->h_details.h_rsa.hash, +// hd, +// GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); +} + + +/** + * Function called with information about available CS keys for signing. Usually + * only called once per key upon connect. Also called again in case a key is + * being revoked, in that case with an @a end_time of zero. + * + * @param cls closure with the `struct HelperState *` + * @param section_name name of the donation unit type in the configuration; + * NULL if the key has been revoked or purged + * @param start_time when does the key become available for signing; + * zero if the key has been revoked or purged + * @param validity_duration how long does the key remain available for signing; + * zero if the key has been revoked or purged + * @param h_cs hash of the @a donation_unit_pub that is available (or was purged) + * @param bs_pub the public key itself, NULL if the key was revoked or purged + */ +static void +helper_cs_cb ( + void *cls, + const char *section_name, + struct GNUNET_TIME_Timestamp start_time, + struct GNUNET_TIME_Relative validity_duration, + const struct TALER_CsPubHashP *h_cs, + struct GNUNET_CRYPTO_BlindSignPublicKey *bs_pub, + const struct TALER_SecurityModulePublicKeyP *sm_pub, + const struct TALER_SecurityModuleSignatureP *sm_sig) +{ + struct HelperState *hs = cls; + struct HelperDonationUnit *hd; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "CS helper announces key %s for donation unit type %s with validity %s\n", + GNUNET_h2s (&h_cs->hash), + section_name, + GNUNET_STRINGS_relative_time_to_string (validity_duration, + GNUNET_NO)); + key_generation++; + DH_resume_keys_requests (false); + hd = GNUNET_CONTAINER_multihashmap_get (hs->cs_keys, + &h_cs->hash); + if (NULL != hd) + { + /* should be just an update (revocation!), so update existing entry */ + hd->validity_duration = validity_duration; + return; + } + GNUNET_assert (NULL != sm_pub); + check_donation_unit_cs_sm_pub (sm_pub); + hd = GNUNET_new (struct HelperDonationUnit); + hd->start_time = start_time; + hd->validity_duration = validity_duration; + hd->h_details.h_cs = *h_cs; + GNUNET_assert (GNUNET_CRYPTO_BSA_CS == bs_pub->cipher); + hd->donation_unit_pub.bsign_pub_key + = GNUNET_CRYPTO_bsign_pub_incref (bs_pub); +// DONAU_donation_unit_pub_hash (&hd->donation_unit_pub, +// &hd->h_donation_unit_pub); +// hd->section_name = GNUNET_strdup (section_name); +// GNUNET_assert ( +// GNUNET_OK == +// GNUNET_CONTAINER_multihashmap_put ( +// hs->donation_unit_keys, +// &hd->h_donation_unit_pub.hash, +// hd, +// GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); +// GNUNET_assert ( +// GNUNET_OK == +// GNUNET_CONTAINER_multihashmap_put ( +// hs->cs_keys, +// &hd->h_details.h_cs.hash, +// hd, +// GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); +} + + +/** + * Function called with information about available keys for signing. Usually + * only called once per key upon connect. Also called again in case a key is + * being revoked, in that case with an @a end_time of zero. + * + * @param cls closure with the `struct HelperState *` + * @param start_time when does the key become available for signing; + * zero if the key has been revoked or purged + * @param validity_duration how long does the key remain available for signing; + * zero if the key has been revoked or purged + * @param exchange_pub the public key itself, NULL if the key was revoked or purged + * @param sm_pub public key of the security module, NULL if the key was revoked or purged + * @param sm_sig signature from the security module, NULL if the key was revoked or purged + * The signature was already verified against @a sm_pub. + */ +static void +helper_esign_cb ( + void *cls, + struct GNUNET_TIME_Timestamp start_time, + struct GNUNET_TIME_Relative validity_duration, + const struct DONAU_DonauPublicKeyP *donau_pub, + const struct TALER_SecurityModulePublicKeyP *sm_pub, + const struct TALER_SecurityModuleSignatureP *sm_sig) +{ + struct HelperState *hs = cls; + struct HelperSignkey *hsk; + struct GNUNET_PeerIdentity pid; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "EdDSA helper announces signing key %s with validity %s\n", + TALER_B2S (donau_pub), + GNUNET_STRINGS_relative_time_to_string (validity_duration, + GNUNET_NO)); + key_generation++; + DH_resume_keys_requests (false); + pid.public_key = donau_pub->eddsa_pub; + hsk = GNUNET_CONTAINER_multipeermap_get (hs->esign_keys, + &pid); +// if (NULL != hsk) +// { +// /* should be just an update (revocation!), so update existing entry */ +// hsk->validity_duration = validity_duration; +// return; +// } + GNUNET_assert (NULL != sm_pub); + check_esign_sm_pub (sm_pub); + hsk = GNUNET_new (struct HelperSignkey); +// hsk->start_time = start_time; +// hsk->validity_duration = validity_duration; + hsk->donau_pub = *donau_pub; + GNUNET_assert ( + GNUNET_OK == + GNUNET_CONTAINER_multipeermap_put ( + hs->esign_keys, + &pid, + hsk, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); +} + + +/** * Setup helper state. * * @param[out] hs helper state to initialize @@ -831,9 +1187,9 @@ destroy_key_state (struct DH_KeyStateHandle *ksh, static enum GNUNET_GenericReturnValue setup_key_helpers (struct HelperState *hs) { - // hs->denom_keys - // = GNUNET_CONTAINER_multihashmap_create (1024, - // GNUNET_YES); + hs->donation_unit_keys + = GNUNET_CONTAINER_multihashmap_create (1024, + GNUNET_YES); hs->rsa_keys = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_YES); @@ -843,30 +1199,33 @@ setup_key_helpers (struct HelperState *hs) hs->esign_keys = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_NO /* MUST BE NO! */); - // hs->rsadh = TALER_CRYPTO_helper_rsa_connect (DH_cfg, - // &helper_rsa_cb, - // hs); - // if (NULL == hs->rsadh) - // { - // destroy_key_helpers (hs); - // return GNUNET_SYSERR; - // } - // hs->csdh = TALER_CRYPTO_helper_cs_connect (DH_cfg, - // &helper_cs_cb, - // hs); - // if (NULL == hs->csdh) - // { - // destroy_key_helpers (hs); - // return GNUNET_SYSERR; - // } - // hs->esh = TALER_CRYPTO_helper_esign_connect (DH_cfg, - // &helper_esign_cb, - // hs); - // if (NULL == hs->esh) - // { - // destroy_key_helpers (hs); - // return GNUNET_SYSERR; - // } + hs->rsadh = DONAU_CRYPTO_helper_rsa_connect (DH_cfg, + "donau", + &helper_rsa_cb, + hs); + if (NULL == hs->rsadh) + { + destroy_key_helpers (hs); + return GNUNET_SYSERR; + } + hs->csdh = DONAU_CRYPTO_helper_cs_connect (DH_cfg, + "donau", + &helper_cs_cb, + hs); + if (NULL == hs->csdh) + { + destroy_key_helpers (hs); + return GNUNET_SYSERR; + } + hs->esh = DONAU_CRYPTO_helper_esign_connect (DH_cfg, + "donau", + &helper_esign_cb, + hs); + if (NULL == hs->esh) + { + destroy_key_helpers (hs); + return GNUNET_SYSERR; + } return GNUNET_OK; } @@ -875,16 +1234,13 @@ setup_key_helpers (struct HelperState *hs) * Create a key state. * * @param[in] hs helper state to (re)use, NULL if not available - * @param management_only if we should NOT run 'finish_keys_response()' - * because we only need the state for the /management/keys API * @return NULL on error (i.e. failed to access database) */ -static struct DH_KeyStateHandle * -build_key_state (struct HelperState *hs /*, - bool management_only*/) +static struct DH_KeyStateHandle* +build_key_state (struct HelperState *hs) { struct DH_KeyStateHandle *ksh; - // enum GNUNET_DB_QueryStatus qs; + enum GNUNET_DB_QueryStatus qs; ksh = GNUNET_new (struct DH_KeyStateHandle); ksh->signature_expires = GNUNET_TIME_UNIT_FOREVER_TS; @@ -894,8 +1250,7 @@ build_key_state (struct HelperState *hs /*, if (NULL == hs) { ksh->helpers = GNUNET_new (struct HelperState); - if (GNUNET_OK != - setup_key_helpers (ksh->helpers)) + if (GNUNET_OK != setup_key_helpers (ksh->helpers)) { GNUNET_free (ksh->helpers); GNUNET_assert (NULL == ksh->management_keys_reply); @@ -907,56 +1262,49 @@ build_key_state (struct HelperState *hs /*, { ksh->helpers = hs; } - ksh->denomkey_map = GNUNET_CONTAINER_multihashmap_create (1024, - true); + ksh->donation_unit_key_map = GNUNET_CONTAINER_multihashmap_create (1024, + true); ksh->signkey_map = GNUNET_CONTAINER_multipeermap_create (32, false /* MUST be false! */ ); /* NOTE: fetches master-signed signkeys, but ALSO those that were revoked! */ - // GNUNET_break (GNUNET_OK == - // DH_plugin->preflight (DH_plugin->cls)); - // if (qs < 0) - // { - // GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); - // GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs); - // destroy_key_state (ksh, - // true); - // return NULL; - // } - // qs = DH_plugin->iterate_denominations (DH_plugin->cls, - // &denomination_info_cb, - // ksh); - // if (qs < 0) - // { - // GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); - // GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs); - // destroy_key_state (ksh, - // true); - // return NULL; - // } + GNUNET_break (GNUNET_OK == + DH_plugin->preflight (DH_plugin->cls)); + if (qs < 0) + { + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs); + destroy_key_state (ksh, + true); + return NULL; + } +// qs = DH_plugin->iterate_donation_units (DH_plugin->cls, +// &donation_unit_info_cb, +// ksh); + if (qs < 0) + { + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR != qs); + destroy_key_state (ksh, + true); + return NULL; + } /* NOTE: ONLY fetches non-revoked AND master-signed signkeys! */ - // qs = DH_plugin->iterate_active_signkeys (DH_plugin->cls, - // &signkey_info_cb, - // ksh); - // if (qs < 0) - // { - // GNUNET_break (0); - // destroy_key_state (ksh, - // true); - // return NULL; - // } - - // if (management_only) - // { - // ksh->management_only = true; - // return ksh; - // } - - if (GNUNET_OK != - finish_keys_response (ksh)) +// qs = DH_plugin->iterate_active_signkeys (DH_plugin->cls, +// &signkey_info_cb, +// ksh); + if (qs < 0) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Could not finish /keys response (likely no signing keys available yet)\n"); + GNUNET_break (0); + destroy_key_state (ksh, + true); + return NULL; + } + if (GNUNET_OK != finish_keys_response (ksh)) + { + GNUNET_log ( + GNUNET_ERROR_TYPE_WARNING, + "Could not finish /keys response (likely no signing keys available yet)\n"); destroy_key_state (ksh, true); return NULL; @@ -969,13 +1317,12 @@ build_key_state (struct HelperState *hs /*, void DH_keys_update_states () { - struct GNUNET_DB_EventHeaderP es = { - .size = htons (sizeof (es)), + struct GNUNET_DB_EventHeaderP es = + { .size = htons (sizeof(es)), // .type = htons (TALER_DBEVENT_DONAU_KEYS_UPDATED), }; - DH_plugin->event_notify (DH_plugin->cls, - &es, + DH_plugin->event_notify (DH_plugin->cls, &es, NULL, 0); key_generation++; @@ -983,7 +1330,7 @@ DH_keys_update_states () } -static struct DH_KeyStateHandle * +static struct DH_KeyStateHandle* DH_keys_get_state (/*bool management_only*/) { struct DH_KeyStateHandle *old_ksh; @@ -998,15 +1345,15 @@ DH_keys_get_state (/*bool management_only*/) key_state = ksh; return ksh; } - if ( (old_ksh->key_generation < key_generation) || - (GNUNET_TIME_absolute_is_past (old_ksh->signature_expires.abs_time)) ) + if ((old_ksh->key_generation < key_generation) + || (GNUNET_TIME_absolute_is_past (old_ksh->signature_expires.abs_time))) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Rebuilding /keys, generation upgrade from %llu to %llu\n", - (unsigned long long) old_ksh->key_generation, - (unsigned long long) key_generation); + (unsigned long long ) old_ksh->key_generation, + (unsigned long long ) key_generation); ksh = build_key_state (old_ksh->helpers /*, - management_only*/); + management_only*/ ); key_state = ksh; old_ksh->helpers = NULL; destroy_key_state (old_ksh, @@ -1048,7 +1395,7 @@ struct FutureBuilderContext * * @param cls the `struct FutureBuilderContext *` * @param h_donation_unit_pub hash of the donation unit public key - * @param value a `struct HelperDenomination` + * @param value a `struct HelperDonationUnit` * @return #GNUNET_OK (continue to iterate) */ static enum GNUNET_GenericReturnValue @@ -1059,29 +1406,30 @@ add_donation_unitkey_cb (void *cls, struct FutureBuilderContext *fbc = cls; struct HelperDonationUnit *helper_donation_unit = value; struct DH_DonationUnitKey *donation_unit_key; - struct DONAUDB_DonationUnitKeyMetaData meta = {0}; + struct DONAUDB_DonationUnitKeyMetaData meta = + { 0 }; - donation_unit_key = GNUNET_CONTAINER_multihashmap_get (fbc->ksh->denomkey_map, - h_donation_unit_pub); + donation_unit_key = GNUNET_CONTAINER_multihashmap_get ( + fbc->ksh->donation_unit_key_map, + h_donation_unit_pub); if (NULL != donation_unit_key) return GNUNET_OK; /* skip: this key is already active! */ // if (GNUNET_TIME_relative_is_zero (hd->validity_duration)) // return GNUNET_OK; /* this key already expired! */ GNUNET_assert ( - 0 == - json_array_append_new ( - fbc->donation_units, - GNUNET_JSON_PACK ( - TALER_JSON_pack_amount ("value", - &meta.value), - GNUNET_JSON_pack_uint64 ("year", - meta.validity_year), - GNUNET_JSON_pack_data_auto ("donation_unit_pub", - &helper_donation_unit->donation_unit_pub) - // GNUNET_JSON_pack_string ("section_name", - // helper_donation_unit->section_name) - ))); + 0 == json_array_append_new (fbc->donation_units, GNUNET_JSON_PACK ( + TALER_JSON_pack_amount ("value", &meta.value), + GNUNET_JSON_pack_uint64 ( + "year", meta.validity_year), + GNUNET_JSON_pack_data_auto ( + "donation_unit_pub", + & + helper_donation_unit + ->donation_unit_pub) + // GNUNET_JSON_pack_string ("section_name", + // helper_donation_unit->section_name) + ))); return GNUNET_OK; } @@ -1094,7 +1442,7 @@ add_donation_unitkey_cb (void *cls, * * @param cls the `struct FutureBuilderContext *` * @param pid actually the exchange public key (type disguised) - * @param value a `struct HelperDenomination` + * @param value a `struct HelperDonationUnit` * @return #GNUNET_OK (continue to iterate) */ static enum GNUNET_GenericReturnValue @@ -1108,8 +1456,7 @@ add_signkey_cb (void *cls, // struct GNUNET_TIME_Timestamp stamp_expire; // struct GNUNET_TIME_Timestamp legal_end; - sk = GNUNET_CONTAINER_multipeermap_get (fbc->ksh->signkey_map, - pid); + sk = GNUNET_CONTAINER_multipeermap_get (fbc->ksh->signkey_map, pid); if (NULL != sk) return GNUNET_OK; /* skip: this key is already active */ // if (GNUNET_TIME_relative_is_zero (hsk->validity_duration)) @@ -1120,31 +1467,31 @@ add_signkey_cb (void *cls, // legal_end = GNUNET_TIME_absolute_to_timestamp ( // GNUNET_TIME_absolute_add (stamp_expire.abs_time, // signkey_legal_duration)); - GNUNET_assert (0 == - json_array_append_new ( - fbc->signkeys, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_data_auto ("key", - &hsk->donau_pub), - // GNUNET_JSON_pack_timestamp ("stamp_end", - // legal_end), - GNUNET_JSON_pack_data_auto ("year", - &hsk->year) - // GNUNET_JSON_pack_data_auto ("signkey_secmod_sig", - // &hsk->sm_sig) - ))); + GNUNET_assert ( + 0 == json_array_append_new (fbc->signkeys, GNUNET_JSON_PACK ( + GNUNET_JSON_pack_data_auto ("key", + &hsk->donau_pub), + // GNUNET_JSON_pack_timestamp ("stamp_end", + // legal_end), + GNUNET_JSON_pack_data_auto ( + "year", &hsk->year) + // GNUNET_JSON_pack_data_auto ("signkey_secmod_sig", + // &hsk->sm_sig) + ))); return GNUNET_OK; } MHD_RESULT -DH_keys_get_handler (const struct DH_RequestHandler *rh, - struct MHD_Connection *connection) +DH_handler_keys (struct DH_RequestContext *rc, + const char *const args[]) { struct DH_KeyStateHandle *ksh; json_t *reply; - (void) rh; + // connection is always initialised + struct MHD_Connection *connection = rc->connection; + ksh = DH_keys_get_state (true); if (NULL == ksh) { @@ -1156,11 +1503,9 @@ DH_keys_get_handler (const struct DH_RequestHandler *rh, sync_key_helpers (ksh->helpers); if (NULL == ksh->management_keys_reply) { - struct FutureBuilderContext fbc = { - .ksh = ksh, - .donation_units = json_array (), - .signkeys = json_array () - }; + struct FutureBuilderContext fbc = + { .ksh = ksh, .donation_units = json_array (), .signkeys = + json_array () }; // if ( (GNUNET_is_zero (&donation_unit_rsa_sm_pub)) && // (GNUNET_is_zero (&donation_unit_cs_sm_pub)) ) // { @@ -1180,16 +1525,13 @@ DH_keys_get_handler (const struct DH_RequestHandler *rh, GNUNET_assert (NULL != fbc.donation_units); GNUNET_assert (NULL != fbc.signkeys); GNUNET_CONTAINER_multihashmap_iterate (ksh->helpers->donation_unit_keys, - &add_donation_unitkey_cb, - &fbc); + &add_donation_unitkey_cb, &fbc); GNUNET_CONTAINER_multipeermap_iterate (ksh->helpers->esign_keys, - &add_signkey_cb, - &fbc); + &add_signkey_cb, &fbc); reply = GNUNET_JSON_PACK ( GNUNET_JSON_pack_array_steal ("future_donation_units", fbc.donation_units), - GNUNET_JSON_pack_array_steal ("future_signkeys", - fbc.signkeys) + GNUNET_JSON_pack_array_steal ("future_signkeys", fbc.signkeys) // GNUNET_JSON_pack_data_auto ("donation_unit_secmod_public_key", // &donation_unit_rsa_sm_pub), // GNUNET_JSON_pack_data_auto ("donation_unit_secmod_cs_public_key", @@ -1197,13 +1539,13 @@ DH_keys_get_handler (const struct DH_RequestHandler *rh, // GNUNET_JSON_pack_data_auto ("signkey_secmod_public_key", // &esign_sm_pub)); ); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Returning GET /keys response:\n"); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Returning GET /keys response:\n"); if (NULL == reply) - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE, - NULL); + return TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE, + NULL); GNUNET_assert (NULL == ksh->management_keys_reply); ksh->management_keys_reply = reply; } @@ -1211,9 +1553,9 @@ DH_keys_get_handler (const struct DH_RequestHandler *rh, { reply = ksh->management_keys_reply; } - return TALER_MHD_reply_json (connection, - reply, + return TALER_MHD_reply_json (connection, reply, MHD_HTTP_OK); + } @@ -1232,13 +1574,9 @@ krd_search_comparator (const void *key, const struct GNUNET_TIME_Timestamp *kd = key; const struct KeysResponseData *krd = value; - if (GNUNET_TIME_timestamp_cmp (*kd, - >, - krd->cherry_pick_date)) + if (GNUNET_TIME_timestamp_cmp (*kd, >, krd->cherry_pick_date)) return -1; - if (GNUNET_TIME_timestamp_cmp (*kd, - <, - krd->cherry_pick_date)) + if (GNUNET_TIME_timestamp_cmp (*kd, <, krd->cherry_pick_date)) return 1; return 0; } @@ -1251,16 +1589,14 @@ krd_search_comparator (const void *key, * @param[in,out] resp response to modify */ typedef void -(*TEH_RESPONSE_SetHeaders)(void *cls, +(*DH_RESPONSE_SetHeaders) (void *cls, struct MHD_Response *resp); - MHD_RESULT -DH_RESPONSE_reply_not_modified ( - struct MHD_Connection *connection, - const char *etags, - TEH_RESPONSE_SetHeaders cb, - void *cb_cls) +DH_RESPONSE_reply_not_modified (struct MHD_Connection *connection, + const char *etags, + DH_RESPONSE_SetHeaders cb, + void *cb_cls) { MHD_RESULT ret; struct MHD_Response *resp; @@ -1268,12 +1604,9 @@ DH_RESPONSE_reply_not_modified ( resp = MHD_create_response_from_buffer (0, NULL, MHD_RESPMEM_PERSISTENT); - cb (cb_cls, - resp); - GNUNET_break (MHD_YES == - MHD_add_response_header (resp, - MHD_HTTP_HEADER_ETAG, - etags)); + cb (cb_cls, resp); + GNUNET_break ( + MHD_YES == MHD_add_response_header (resp, MHD_HTTP_HEADER_ETAG, etags)); ret = MHD_queue_response (connection, MHD_HTTP_NOT_MODIFIED, resp); @@ -1391,5 +1724,4 @@ DH_RESPONSE_reply_not_modified ( // } // } - /* end of donau-httpd_keys.c */ diff --git a/src/donau/donau-httpd_keys.h b/src/donau/donau-httpd_keys.h @@ -166,8 +166,8 @@ TEH_resume_keys_requests (bool do_shutdown); * @return MHD result code */ MHD_RESULT -DH_keys_get_handler (const struct DH_RequestHandler *, struct MHD_Connection *); - +DH_handler_keys (struct DH_RequestContext *rc, + const char *const args[]); /** * Initialize keys subsystem. diff --git a/src/donau/donau-httpd_post-submit-receipt.c b/src/donau/donau-httpd_post-submit-receipt.c @@ -0,0 +1,155 @@ +/* + This file is part of TALER + Copyright (C) 2024 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file donau-httpd_post-submit-receipt.c + * @brief Handle request to insert a submitted receipt. + * @author Johannes Casaburi + */ +#include "taler/platform.h" +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_json_lib.h> +#include <jansson.h> +#include <microhttpd.h> +#include <pthread.h> +#include "taler/taler_json_lib.h" +#include "taler/taler_mhd_lib.h" +#include "taler/taler_signatures.h" +#include "donaudb_plugin.h" +#include "donau-httpd_receipt.h" +#include "donau-httpd_db.h" +#include "donau-httpd_metrics.h" + + +/** + * Closure for #insert_submitted_receipt() + */ +struct InsertReceiptContext +{ + struct DONAU_HashDonorTaxId *h_tax_number; + union GNUNET_CRYPTO_BlindSessionNonce *nonce; + struct DONAU_DonationUnitPublicKey *donation_unit_pub; + struct DONAU_DonauSignatureP *donau_sig; + uint64_t donation_year; +}; + + +/** + * Function implementing insert submit-receipt transaction. + * + * Runs the transaction logic; IF it returns a non-error code, the + * transaction logic MUST NOT queue a MHD response. IF it returns an hard + * error, the transaction logic MUST queue a MHD response and set @a mhd_ret. + * IF it returns the soft error code, the function MAY be called again to + * retry and MUST not queue a MHD response. + * + * @param cls closure with a `struct InsertReceiptContext` + * @param connection MHD request which triggered the transaction + * @param[out] mhd_ret set to MHD response status for @a connection, + * if transaction failed (!) + * @return transaction status + */ +static enum GNUNET_DB_QueryStatus +insert_submitted_receipt (void *cls, + struct MHD_Connection *connection, + MHD_RESULT *mhd_ret) +{ + struct InsertReceiptContext *icc = cls; + enum GNUNET_DB_QueryStatus qs; + + qs = DH_plugin->insert_submitted_receipt (DH_plugin->cls, + icc->h_tax_number, + icc->nonce, + icc->donation_unit_pub, + icc->donau_sig, + icc->donation_year); + if (qs <= 0) + { + if (GNUNET_DB_STATUS_SOFT_ERROR != qs) + { + GNUNET_break (0); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_STORE_FAILED, + "insert_submitted_receipt"); + return GNUNET_DB_STATUS_HARD_ERROR; + } + return qs; + } + + return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; +} + + +MHD_RESULT +DH_handler_submit_receipt_post (struct DH_RequestContext *rc, + const json_t *root, + const char *const args[]) +{ + struct InsertReceiptContext icc; + + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("h_tax_number", + &icc.h_tax_number), + GNUNET_JSON_spec_fixed_auto ("nonce", + &icc.nonce), + GNUNET_JSON_spec_fixed_auto ("donation_unit_pub", + &icc.donation_unit_pub), + GNUNET_JSON_spec_fixed_auto ("donau_sig", + &icc.donau_sig), + GNUNET_JSON_spec_uint64 ("donation_year", + &icc.donation_year), + GNUNET_JSON_spec_end () + }; + + { + enum GNUNET_GenericReturnValue res; + + res = TALER_MHD_parse_json_data (rc->connection, + root, + spec); + if (GNUNET_SYSERR == res) + return MHD_NO; /* hard failure */ + if (GNUNET_NO == res) + { + GNUNET_break_op (0); + return MHD_YES; /* failure */ + } + } + + { + MHD_RESULT mhd_ret; + + if (GNUNET_OK != + DH_DB_run_transaction (rc->connection, + "insert_submitted_receipt", + DH_MT_REQUEST_OTHER, + &mhd_ret, + &insert_submitted_receipt, + &icc)) + { + return mhd_ret; + } + } + return TALER_MHD_reply_static ( + rc->connection, + MHD_HTTP_NO_CONTENT, + NULL, + NULL, + 0); +} + + +/* end of donau-httpd_post-submit-receipt.c */ diff --git a/src/donau/donau-httpd_receipt.h b/src/donau/donau-httpd_receipt.h @@ -0,0 +1,41 @@ +/* + This file is part of TALER + Copyright (C) 2024 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file donau-httpd_receipt.h + * @brief Handle /submit requests + * @author Johannes Casaburi + */ +#ifndef DONAU_HTTPD_RECEIPT_H +#define DONAU_HTTPD_RECEIPT_H + +#include <microhttpd.h> +#include "donau-httpd.h" + + +/** + * Handle a POST "/submit" request. + * + * @param connection the MHD connection to handle + * @param root uploaded JSON data + * @return MHD result code + */ +MHD_RESULT +DH_handler_submit_receipt_post ( + struct DH_RequestContext *rc, + const json_t *root, + const char *const args[]); + +#endif diff --git a/src/donaudb/0002-donation_units.sql b/src/donaudb/0002-donation_units.sql @@ -23,7 +23,7 @@ CREATE TABLE donation_units ); COMMENT ON TABLE donation_units IS 'Main donation_unit table. All the valid donation units the Donau knows about.'; -COMMENT ON COLUMN donation_units.donation_unit +COMMENT ON COLUMN donation_units.value IS 'Value the donation unit has in Taler amount'; CREATE INDEX donation_units_by_validity_year diff --git a/src/donaudb/pg_insert_submitted_receipt.c b/src/donaudb/pg_insert_submitted_receipt.c @@ -29,9 +29,11 @@ enum GNUNET_DB_QueryStatus DH_PG_insert_submitted_receipt (void *cls, const struct DONAU_HashDonorTaxId *h_tax_number, - const union GNUNET_CRYPTO_BlindSessionNonce *nonce, - const struct DONAU_DonationUnitPublicKey *donation_unit_pub, - const struct TALER_DonauSignatureP *donau_sig, + const union GNUNET_CRYPTO_BlindSessionNonce * + nonce, + const struct + DONAU_DonationUnitPublicKey *donation_unit_pub, + const struct DONAU_DonauSignatureP *donau_sig, const uint64_t donation_year) { struct PostgresClosure *pg = cls; diff --git a/src/donaudb/pg_insert_submitted_receipt.h b/src/donaudb/pg_insert_submitted_receipt.h @@ -40,9 +40,11 @@ enum GNUNET_DB_QueryStatus DH_PG_insert_submitted_receipt (void *cls, const struct DONAU_HashDonorTaxId *h_tax_number, - const union GNUNET_CRYPTO_BlindSessionNonce *nonce, - const struct DONAU_DonationUnitPublicKey *donation_unit_pub, - const struct TALER_DonauSignatureP *donau_sig, + const union GNUNET_CRYPTO_BlindSessionNonce * + nonce, + const struct + DONAU_DonationUnitPublicKey *donation_unit_pub, + const struct DONAU_DonauSignatureP *donau_sig, const uint64_t donation_year); #endif diff --git a/src/include/donau_crypto_lib.h b/src/include/donau_crypto_lib.h @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2023 Taler Systems SA + Copyright (C) 2023-2024 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -21,6 +21,7 @@ * @author Christian Grothoff <christian@grothoff.org> * @author Özgür Kesim <oec-taler@kesim.org> * @author Lukas Matyja + * @author Pius Loosli */ #if ! defined (__DONAU_UTIL_LIB_H_INSIDE__) #error "Only <donau_util.h> can be included directly." @@ -126,8 +127,10 @@ struct DONAU_DonationUnitHashP * @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); +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 @@ -137,8 +140,12 @@ DONAU_donation_unit_pub_cmp (const struct DONAU_DonationUnitPublicKey *donation_ * @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); +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. @@ -146,7 +153,8 @@ DONAU_donation_unit_pub_deep_copy (struct DONAU_DonationUnitPublicKey *donation_ * @param[in] donation_unit_pub key to free */ void -DONAU_donation_unit_pub_free (struct DONAU_DonationUnitPublicKey *donation_unit_pub); +DONAU_donation_unit_pub_free (struct + DONAU_DonationUnitPublicKey *donation_unit_pub); /** * Hash used to represent a Donation Receipt @@ -174,9 +182,9 @@ struct DONAU_HashDonorTaxId struct DONAU_BlindedDonationUnitSignature { /** - * The blinded signature + * Donation Units use blind signatures. */ - struct TALER_DenominationSignature b_sig; + struct GNUNET_CRYPTO_BlindedSignature *blinded_sig; }; @@ -324,10 +332,135 @@ DONAU_donation_statement_verify ( const struct DONAU_DonauSignatureP *statement_sig); -/* ********************* helper ************************** */ +///* ********************* donau blind signing ************************** */ /** + * Free internals of @a donation_unit_sig, but not @a donation_unit_sig itself. + * + * @param[in] donation_unit_sig signature to free +// */ +void +DONAU_blinded_donation_unit_sig_free ( + struct DONAU_BlindedDonationUnitSignature *donation_unit_sig); + +// FIXME: Copied from taler_crypto_lib.h, is anything of this necessary? +///** +// * Compute the hash of the given @a donation_unit_pub. +// * +// * @param donation_unit_pub public key to hash +// * @param[out] donation_unit_hash resulting hash value +// */ +// void +// TALER_donation_unit_pub_hash (const struct DONAU_DonationUnitPublicKey *donation_unit_pub, +// struct DONAU_DonationUnitHashP *donation_unit_hash); +// +// +///** +// * 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 +// TALER_donation_unit_pub_deep_copy (struct DONAU_DonationUnitPublicKey *donation_unit_dst, +// const struct DONAU_DonationUnitPublicKey *donation_unit_src); +// +// +///** +// * 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 +// TALER_donation_unit_sig_deep_copy (struct DONAU_DonationUnitSignature *donation_unit_dst, +// const struct DONAU_DonationUnitSignature *donation_unit_src); +// +// +///** +// * 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 +// TALER_blinded_donation_unit_sig_deep_copy ( +// struct DONAU_BlindedDonationUnitSignature *donation_unit_dst, +// const struct DONAU_BlindedDonationUnitSignature *donation_unit_src); +// +// +///** +// * 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 +// TALER_donation_unit_pub_cmp (const struct DONAU_DonationUnitPublicKey *donation_unit1, +// const struct DONAU_DonationUnitPublicKey *donation_unit2); +// +// +///** +// * Compare two donation unit signatures. +// * +// * @param sig1 first signature +// * @param sig2 second signature +// * @return 0 if the keys are equal, otherwise -1 or 1 +// */ +// int +// TALER_donation_unit_sig_cmp (const struct DONAU_DonationUnitSignature *sig1, +// const struct DONAU_DonationUnitSignature *sig2); +// +// +///** +// * Compare two blinded donation unit signatures. +// * +// * @param sig1 first signature +// * @param sig2 second signature +// * @return 0 if the keys are equal, otherwise -1 or 1 +// */ +// int +// TALER_blinded_donation_unit_sig_cmp ( +// const struct DONAU_BlindedDonationUnitSignature *sig1, +// const struct DONAU_BlindedDonationUnitSignature *sig2); +// +// +///** +// * Compare two blinded planchets. +// * +// * @param bp1 first blinded planchet +// * @param bp2 second blinded planchet +// * @return 0 if the keys are equal, otherwise -1 or 1 +// */ +// int +// TALER_blinded_planchet_cmp ( +// const struct DONAU_BlindedPlanchet *bp1, +// const struct DONAU_BlindedPlanchet *bp2); +// +// +///** +// * Verify signature made with a donation unit public key +// * over a donation receipt. +// * +// * @param donation_unit_pub public donation unit key +// * @param donation_unit_sig signature made with the private key +// * @param c_hash hash over the coin +// * @return #GNUNET_OK if the signature is valid +// */ +// enum GNUNET_GenericReturnValue +// TALER_donation_unit_pub_verify (const struct DONAU_DonationUnitPublicKey *donation_unit_pub, +// const struct DONAU_DonationUnitSignature *donation_unit_sig, +// const struct DONAU_ *c_hash); +// + + +/*********************** helpers ************************************************/ +/** * Group of donation units. These are the common fields of an array of * donation units. */ @@ -369,4 +502,418 @@ struct TALER_DonauBatchIssueValues }; +/* ********************* Helper-based RSA operations ************************** */ +/** + * Function called with information about available keys for signing. Usually + * only called once per key upon connect. Also called again in case a key is + * being revoked, in that case with an @a end_time of zero. + * + * @param cls closure + * @param section_name name of the donation unit type in the configuration; + * NULL if the key has been revoked or purged + * @param start_time when does the key become available for signing; + * zero if the key has been revoked or purged + * @param validity_duration how long does the key remain available for signing; + * zero if the key has been revoked or purged + * @param h_rsa hash of the RSA @a donation_unit_pub that is available (or was purged) + * @param bs_pub the public key itself, NULL if the key was revoked or purged + * @param sm_pub public key of the security module, NULL if the key was revoked or purged + * @param sm_sig signature from the security module, NULL if the key was revoked or purged + * The signature was already verified against @a sm_pub. + */ +typedef void +(*DONAU_CRYPTO_RsaDonationUnitKeyStatusCallback)( + void *cls, + const char *section_name, + struct GNUNET_TIME_Timestamp start_time, + struct GNUNET_TIME_Relative validity_duration, + const struct TALER_RsaPubHashP *h_rsa, + struct GNUNET_CRYPTO_BlindSignPublicKey *bs_pub, + const struct TALER_SecurityModulePublicKeyP *sm_pub, + const struct TALER_SecurityModuleSignatureP *sm_sig); + +/** + * Handle for talking to an Donation unit key signing helper. + */ +struct DONAU_CRYPTO_RsaDonationUnitHelper; + + +/** + * Initiate connection to an donation unit key helper. + * + * @param cfg configuration to use + * @param section configuration section prefix to use, usually 'taler' or 'donau' + * @param dkc function to call with key information + * @param dkc_cls closure for @a dkc + * @return NULL on error (such as bad @a cfg). + */ +struct DONAU_CRYPTO_RsaDonationUnitHelper * +DONAU_CRYPTO_helper_rsa_connect ( + const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, + DONAU_CRYPTO_RsaDonationUnitKeyStatusCallback dkc, + void *dkc_cls); + + +/** + * Function to call to 'poll' for updates to the available key material. + * Should be called whenever it is important that the key material status is + * current, like when handling a "/keys" request. This function basically + * briefly checks if there are messages from the helper announcing changes to + * donation unit keys. + * + * @param dh helper process connection + */ +void +DONAU_CRYPTO_helper_rsa_poll (struct DONAU_CRYPTO_RsaDonationUnitHelper *dh); + +/** + * Close connection to @a dh. + * + * @param[in] dh connection to close + */ +void +DONAU_CRYPTO_helper_rsa_disconnect ( + struct DONAU_CRYPTO_RsaDonationUnitHelper *dh); + + +/* **************** Helper-based CS operations **************** */ + +/** + * Handle for talking to an DonationUnit key signing helper. + */ +struct DONAU_CRYPTO_CsDonationUnitHelper; + +/** + * Function called with information about available keys for signing. Usually + * only called once per key upon connect. Also called again in case a key is + * being revoked, in that case with an @a end_time of zero. + * + * @param cls closure + * @param section_name name of the donation unit type in the configuration; + * NULL if the key has been revoked or purged + * @param start_time when does the key become available for signing; + * zero if the key has been revoked or purged + * @param validity_duration how long does the key remain available for signing; + * zero if the key has been revoked or purged + * @param h_cs hash of the CS @a donation_unit_pub that is available (or was purged) + * @param bsign_pub the public key itself, NULL if the key was revoked or purged + * @param sm_pub public key of the security module, NULL if the key was revoked or purged + * @param sm_sig signature from the security module, NULL if the key was revoked or purged + * The signature was already verified against @a sm_pub. + */ +typedef void +(*DONAU_CRYPTO_CsDonationUnitKeyStatusCallback)( + void *cls, + const char *section_name, + struct GNUNET_TIME_Timestamp start_time, + struct GNUNET_TIME_Relative validity_duration, + const struct TALER_CsPubHashP *h_cs, + struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub, + const struct TALER_SecurityModulePublicKeyP *sm_pub, + const struct TALER_SecurityModuleSignatureP *sm_sig); + + +/** + * Initiate connection to an donation unit key helper. + * + * @param cfg configuration to use + * @param section configuration section prefix to use, usually 'taler' or 'donau' + * @param dkc function to call with key information + * @param dkc_cls closure for @a dkc + * @return NULL on error (such as bad @a cfg). + */ +struct DONAU_CRYPTO_CsDonationUnitHelper * +DONAU_CRYPTO_helper_cs_connect ( + const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, + DONAU_CRYPTO_CsDonationUnitKeyStatusCallback dkc, + void *dkc_cls); + + +/** + * Function to call to 'poll' for updates to the available key material. + * Should be called whenever it is important that the key material status is + * current, like when handling a "/keys" request. This function basically + * briefly checks if there are messages from the helper announcing changes to + * donation unit keys. + * + * @param dh helper process connection + */ +void +DONAU_CRYPTO_helper_cs_poll (struct DONAU_CRYPTO_CsDonationUnitHelper *dh); + + +/** + * Request helper @a dh to sign @a req. + * + * This operation will block until the signature has been obtained. Should + * this process receive a signal (that is not ignored) while the operation is + * pending, the operation will fail. Note that the helper may still believe + * that it created the signature. Thus, signals may result in a small + * differences in the signature counters. Retrying in this case may work. + * + * @param dh helper process connection + * @param req information about the key to sign with and the value to sign + * @param for_melt true if for melt operation + * @param[out] bs set to the blind signature + * @return #TALER_EC_NONE on success + */ +enum TALER_ErrorCode +DONAU_CRYPTO_helper_cs_sign ( + struct DONAU_CRYPTO_CsDonationUnitHelper *dh, + const struct TALER_CRYPTO_CsSignRequest *req, + bool for_melt, + struct DONAU_BlindedDonationUnitSignature *bs); + + +/** + * Request helper @a dh to sign batch of @a reqs requests. + * + * This operation will block until the signature has been obtained. Should + * this process receive a signal (that is not ignored) while the operation is + * pending, the operation will fail. Note that the helper may still believe + * that it created the signature. Thus, signals may result in a small + * differences in the signature counters. Retrying in this case may work. + * + * @param dh helper process connection + * @param reqs information about the keys to sign with and the values to sign + * @param reqs_length length of the @a reqs array + * @param for_melt true if this is for a melt operation + * @param[out] bss array set to the blind signatures, must be of length @a reqs_length! + * @return #TALER_EC_NONE on success + */ +enum TALER_ErrorCode +DONAU_CRYPTO_helper_cs_batch_sign ( + struct DONAU_CRYPTO_CsDonationUnitHelper *dh, + unsigned int reqs_length, + const struct TALER_CRYPTO_CsSignRequest reqs[static reqs_length], + bool for_melt, + struct DONAU_BlindedDonationUnitSignature bss[static reqs_length]); + + +/** + * Ask the helper to revoke the public key associated with @a h_cs. + * Will cause the helper to tell all clients that the key is now unavailable, + * and to create a replacement key. + * + * This operation will block until the revocation request has been + * transmitted. Should this process receive a signal (that is not ignored) + * while the operation is pending, the operation may fail. If the key is + * unknown, this function will also appear to have succeeded. To be sure that + * the revocation worked, clients must watch the donation unit key status + * callback. + * + * @param dh helper to process connection + * @param h_cs hash of the CS public key to revoke + */ +void +DONAU_CRYPTO_helper_cs_revoke ( + struct DONAU_CRYPTO_CsDonationUnitHelper *dh, + const struct TALER_CsPubHashP *h_cs); + + +/** + * Ask the helper to derive R using the information + * from @a cdr. + * + * This operation will block until the R has been obtained. Should + * this process receive a signal (that is not ignored) while the operation is + * pending, the operation will fail. Note that the helper may still believe + * that it created the signature. Thus, signals may result in a small + * differences in the signature counters. Retrying in this case may work. + * + * @param dh helper to process connection + * @param cdr derivation input data + * @param for_melt true if this is for a melt operation + * @param[out] crp set to the pair of R values + * @return set to the error code (or #TALER_EC_NONE on success) + */ +enum TALER_ErrorCode +DONAU_CRYPTO_helper_cs_r_derive ( + struct DONAU_CRYPTO_CsDonationUnitHelper *dh, + const struct TALER_CRYPTO_CsDeriveRequest *cdr, + bool for_melt, + struct GNUNET_CRYPTO_CSPublicRPairP *crp); + + +/** + * Ask the helper to derive R using the information from @a cdrs. + * + * This operation will block until the R has been obtained. Should + * this process receive a signal (that is not ignored) while the operation is + * pending, the operation will fail. Note that the helper may still believe + * that it created the signature. Thus, signals may result in a small + * differences in the signature counters. Retrying in this case may work. + * + * @param dh helper to process connection + * @param cdrs_length length of the @a cdrs array + * @param cdrs array with derivation input data + * @param for_melt true if this is for a melt operation + * @param[out] crps array set to the pair of R values, must be of length @a cdrs_length + * @return set to the error code (or #TALER_EC_NONE on success) + */ +enum TALER_ErrorCode +DONAU_CRYPTO_helper_cs_r_batch_derive ( + struct DONAU_CRYPTO_CsDonationUnitHelper *dh, + unsigned int cdrs_length, + const struct TALER_CRYPTO_CsDeriveRequest cdrs[static cdrs_length], + bool for_melt, + struct GNUNET_CRYPTO_CSPublicRPairP crps[static cdrs_length]); + + +/** + * Close connection to @a dh. + * + * @param[in] dh connection to close + */ +void +DONAU_CRYPTO_helper_cs_disconnect ( + struct DONAU_CRYPTO_CsDonationUnitHelper *dh); + + +/*********************** Helper-based EDDSA operations *****************************/ + +/** + * Handle for talking to an online key signing helper. + */ +struct DONAU_CRYPTO_DonauSignHelper; + +/** + * Function called with information about available keys for signing. Usually + * only called once per key upon connect. Also called again in case a key is + * being revoked, in that case with an @a end_time of zero. + * + * @param cls closure + * @param start_time when does the key become available for signing; + * zero if the key has been revoked or purged + * @param validity_duration how long does the key remain available for signing; + * zero if the key has been revoked or purged + * @param exchange_pub the public key itself, NULL if the key was revoked or purged + * @param sm_pub public key of the security module, NULL if the key was revoked or purged + * @param sm_sig signature from the security module, NULL if the key was revoked or purged + * The signature was already verified against @a sm_pub. + */ +typedef void +(*DONAU_CRYPTO_DonauKeyStatusCallback)( + void *cls, + struct GNUNET_TIME_Timestamp start_time, + struct GNUNET_TIME_Relative validity_duration, + const struct DONAU_DonauPublicKeyP *exchange_pub, + const struct TALER_SecurityModulePublicKeyP *sm_pub, + const struct TALER_SecurityModuleSignatureP *sm_sig); + + +/** + * Initiate connection to an online signing key helper. + * + * @param cfg configuration to use + * @param section configuration section prefix to use, usually 'taler' or 'donau' + * @param ekc function to call with key information + * @param ekc_cls closure for @a ekc + * @return NULL on error (such as bad @a cfg). + */ +struct DONAU_CRYPTO_DonauSignHelper * +DONAU_CRYPTO_helper_esign_connect ( + const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, + DONAU_CRYPTO_DonauKeyStatusCallback ekc, + void *ekc_cls); + + +/** + * Function to call to 'poll' for updates to the available key material. + * Should be called whenever it is important that the key material status is + * current, like when handling a "/keys" request. This function basically + * briefly checks if there are messages from the helper announcing changes to + * donau online signing keys. + * + * @param esh helper process connection + */ +void +DONAU_CRYPTO_helper_esign_poll (struct DONAU_CRYPTO_DonauSignHelper *esh); + + +/** + * Request helper @a esh to sign @a msg using the current online + * signing key. + * + * This operation will block until the signature has been obtained. Should + * this process receive a signal (that is not ignored) while the operation is + * pending, the operation will fail. Note that the helper may still believe + * that it created the signature. Thus, signals may result in a small + * differences in the signature counters. Retrying in this case may work. + * + * @param esh helper process connection + * @param purpose message to sign (must extend beyond the purpose) + * @param[out] donau_pub set to the public key used for the signature upon success + * @param[out] donau_sig set to the signature upon success + * @return the error code (or #TALER_EC_NONE on success) + */ +enum TALER_ErrorCode +DONAU_CRYPTO_helper_esign_sign_ ( + struct DONAU_CRYPTO_DonauSignHelper *esh, + const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, + struct DONAU_DonauPublicKeyP *donau_pub, + struct DONAU_DonauSignatureP *donau_sig); + + +/** + * Request helper @a esh to sign @a msg using the current online + * signing key. + * + * This operation will block until the signature has been obtained. Should + * this process receive a signal (that is not ignored) while the operation is + * pending, the operation will fail. Note that the helper may still believe + * that it created the signature. Thus, signals may result in a small + * differences in the signature counters. Retrying in this case may work. + * + * @param esh helper process connection + * @param ps message to sign (MUST begin with a purpose) + * @param[out] epub set to the public key used for the signature upon success + * @param[out] esig set to the signature upon success + * @return the error code (or #TALER_EC_NONE on success) + */ +#define DONAU_CRYPTO_helper_esign_sign(esh,ps,epub,esig) ( \ + /* check size is set correctly */ \ + GNUNET_assert (ntohl ((ps)->purpose.size) == sizeof (*ps)), \ + /* check 'ps' begins with the purpose */ \ + GNUNET_static_assert (((void*) (ps)) == \ + ((void*) &(ps)->purpose)), \ + DONAU_CRYPTO_helper_esign_sign_ (esh, \ + &(ps)->purpose, \ + epub, \ + esig) ) + + +/** + * Ask the helper to revoke the public key @a donau_pub . + * Will cause the helper to tell all clients that the key is now unavailable, + * and to create a replacement key. + * + * This operation will block until the revocation request has been + * transmitted. Should this process receive a signal (that is not ignored) + * while the operation is pending, the operation may fail. If the key is + * unknown, this function will also appear to have succeeded. To be sure that + * the revocation worked, clients must watch the signing key status callback. + * + * @param esh helper to process connection + * @param donau_pub the public key to revoke + */ +void +DONAU_CRYPTO_helper_esign_revoke ( + struct DONAU_CRYPTO_DonauSignHelper *esh, + const struct DONAU_DonauPublicKeyP *donau_pub); + + +/** + * Close connection to @a esh. + * + * @param[in] esh connection to close + */ +void +DONAU_CRYPTO_helper_esign_disconnect ( + struct DONAU_CRYPTO_DonauSignHelper *esh); + + #endif diff --git a/src/include/donau_service.h b/src/include/donau_service.h @@ -129,9 +129,9 @@ struct DONAU_Keys */ unsigned int num_donation_unit_keys; - /** - * Actual length of the @e donation_unit_keys array (size of allocation). - */ + /** + * Actual length of the @e donation_unit_keys array (size of allocation). + */ unsigned int donation_unit_keys_size; /** @@ -552,18 +552,6 @@ struct TALER_DonationUnitSignature }; /** - * Donau signature - */ -struct TALER_DonauSignatureP -{ - /** - * The signature - */ - struct TALER_ExchangeSignatureP sig; - -}; - -/** * Donation Receipt */ struct DONAU_DonationReceipt @@ -621,7 +609,7 @@ struct DONAU_DonorReceiptsToStatementResult * The donation statment for a requested year. Signature over the total amount, * the year, the unique identifier hash */ - struct TALER_DonauSignatureP *sig; + struct DONAU_DonauSignatureP *sig; } ok; diff --git a/src/include/donaudb_plugin.h b/src/include/donaudb_plugin.h @@ -541,7 +541,7 @@ struct DONAUDB_Plugin const struct DONAU_HashDonorTaxId *h_tax_number, const union GNUNET_CRYPTO_BlindSessionNonce *nonce, const struct DONAU_DonationUnitPublicKey *donation_unit_pub, - const struct TALER_DonauSignatureP *donau_sig, + const struct DONAU_DonauSignatureP *donau_sig, const uint64_t donation_year); /** diff --git a/src/util/Makefile.am b/src/util/Makefile.am @@ -15,7 +15,10 @@ lib_LTLIBRARIES = \ libdonauutil_la_SOURCES = \ charity_signatures.c \ donau_signatures.c \ - donau_os_installation.c + donau_os_installation.c \ + crypto_helper_cs.c \ + crypto_helper_rsa.c \ + crypto_helper_esign.c libdonauutil_la_LIBADD = \ -ltalerutil \ diff --git a/src/util/crypto_helper_common.c b/src/util/crypto_helper_common.c @@ -0,0 +1,51 @@ +/* + This file is part of TALER + Copyright (C) 2020, 2021 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file util/crypto_helper_common.c + * @brief Common functions for the exchange security modules + * @author Florian Dold <dold@taler.net> + */ +#include <taler/platform.h> +#include <taler/taler_util.h> +#include <taler/taler_signatures.h> + + +enum GNUNET_GenericReturnValue +TALER_crypto_helper_send_all (int sock, + const void *buf, + size_t buf_size) +{ + size_t off = 0; + + while (off < buf_size) + { + ssize_t ret; + + ret = send (sock, + buf + off, + buf_size - off, + 0); + if (ret < 0) + { + if (EINTR == errno) + continue; + return GNUNET_SYSERR; + } + GNUNET_assert (ret > 0); + off += ret; + } + return GNUNET_OK; +} diff --git a/src/util/crypto_helper_common.h b/src/util/crypto_helper_common.h @@ -0,0 +1,41 @@ +/* + This file is part of GNU Taler + Copyright (C) 2021 Taler Systems SA + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file util/crypto_helper_common.h + * @brief Common functions for the exchange security modules + * @author Florian Dold <dold@taler.net> + */ +#ifndef CRYPTO_HELPER_COMMON_H +#define CRYPTO_HELPER_COMMON_H + +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_network_lib.h> + +/** + * Send all @a buf_size bytes from @a buf to @a sock. + * + * @param sock socket to send on + * @param buf data to send + * @param buf_size number of bytes in @a buf + * @return #GNUNET_OK on success + */ +enum GNUNET_GenericReturnValue +TALER_crypto_helper_send_all (int sock, + const void *buf, + size_t buf_size); + +#endif diff --git a/src/util/crypto_helper_cs.c b/src/util/crypto_helper_cs.c @@ -0,0 +1,1317 @@ +/* + This file is part of TALER + Copyright (C) 2020-2024 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file util/crypto_helper_cs.c + * @brief utility functions for running out-of-process private key operations + * @author Christian Grothoff + * @author Pius Loosli + */ +#include "taler/platform.h" +#include "taler/taler_util.h" +#include "taler/taler_signatures.h" +#include "taler/taler-exchange-secmod-cs.h" +#include <poll.h> +#include "crypto_helper_common.h" +#include "donau_util.h" + +struct DONAU_CRYPTO_CsDonationUnitHelper +{ + /** + * Function to call with updates to available key material. + */ + DONAU_CRYPTO_CsDonationUnitKeyStatusCallback dkc; + + /** + * Closure for @e dkc + */ + void *dkc_cls; + + /** + * Socket address of the donation unit helper process. + * Used to reconnect if the connection breaks. + */ + struct sockaddr_un sa; + + /** + * The UNIX domain socket, -1 if we are currently not connected. + */ + int sock; + + /** + * Have we ever been sync'ed? + */ + bool synced; +}; + + +/** + * Disconnect from the helper process. Updates + * @e sock field in @a dh. + * + * @param[in,out] dh handle to tear down connection of + */ +static void +do_disconnect (struct DONAU_CRYPTO_CsDonationUnitHelper *dh) +{ + GNUNET_break (0 == close (dh->sock)); + dh->sock = -1; + dh->synced = false; +} + + +/** + * Try to connect to the helper process. Updates + * @e sock field in @a dh. + * + * @param[in,out] dh handle to establish connection for + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +try_connect (struct DONAU_CRYPTO_CsDonationUnitHelper *dh) +{ + if (-1 != dh->sock) + return GNUNET_OK; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Establishing connection!\n"); + dh->sock = socket (AF_UNIX, + SOCK_STREAM, + 0); + if (-1 == dh->sock) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "socket"); + return GNUNET_SYSERR; + } + if (0 != + connect (dh->sock, + (const struct sockaddr *) &dh->sa, + sizeof (dh->sa))) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, + "connect", + dh->sa.sun_path); + do_disconnect (dh); + return GNUNET_SYSERR; + } + DONAU_CRYPTO_helper_cs_poll (dh); + return GNUNET_OK; +} + + +struct DONAU_CRYPTO_CsDonationUnitHelper * +DONAU_CRYPTO_helper_cs_connect ( + const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, + DONAU_CRYPTO_CsDonationUnitKeyStatusCallback dkc, + void *dkc_cls) +{ + struct DONAU_CRYPTO_CsDonationUnitHelper *dh; + char *unixpath; + char *secname; + + GNUNET_asprintf (&secname, + "%s-exchange-secmod-cs", + section); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + secname, + "UNIXPATH", + &unixpath)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + secname, + "UNIXPATH"); + GNUNET_free (secname); + return NULL; + } + /* we use >= here because we want the sun_path to always + be 0-terminated */ + if (strlen (unixpath) >= sizeof (dh->sa.sun_path)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + secname, + "UNIXPATH", + "path too long"); + GNUNET_free (unixpath); + GNUNET_free (secname); + return NULL; + } + GNUNET_free (secname); + dh = GNUNET_new (struct DONAU_CRYPTO_CsDonationUnitHelper); + dh->dkc = dkc; + dh->dkc_cls = dkc_cls; + dh->sa.sun_family = AF_UNIX; + strncpy (dh->sa.sun_path, + unixpath, + sizeof (dh->sa.sun_path) - 1); + GNUNET_free (unixpath); + dh->sock = -1; + if (GNUNET_OK != + try_connect (dh)) + { + DONAU_CRYPTO_helper_cs_disconnect (dh); + return NULL; + } + return dh; +} + + +/** + * Handle a #DONAU_HELPER_CS_MT_AVAIL message from the helper. + * + * @param dh helper context + * @param hdr message that we received + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +handle_mt_avail (struct DONAU_CRYPTO_CsDonationUnitHelper *dh, + const struct GNUNET_MessageHeader *hdr) +{ + const struct TALER_CRYPTO_CsKeyAvailableNotification *kan + = (const struct TALER_CRYPTO_CsKeyAvailableNotification *) hdr; + const char *buf = (const char *) &kan[1]; + const char *section_name; + uint16_t snl; + + if (sizeof (*kan) > ntohs (hdr->size)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + snl = ntohs (kan->section_name_len); + if (ntohs (hdr->size) != sizeof (*kan) + snl) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (0 == snl) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + section_name = buf; + if ('\0' != section_name[snl - 1]) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + { + struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub; + struct TALER_CsPubHashP h_cs; + + bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey); + bsign_pub->cipher = GNUNET_CRYPTO_BSA_CS; + bsign_pub->rc = 1; + bsign_pub->details.cs_public_key = kan->denom_pub; + + GNUNET_CRYPTO_hash (&bsign_pub->details.cs_public_key, + sizeof (bsign_pub->details.cs_public_key), + &bsign_pub->pub_key_hash); + h_cs.hash = bsign_pub->pub_key_hash; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Received CS key %s (%s)\n", + GNUNET_h2s (&h_cs.hash), + section_name); + if (GNUNET_OK != + TALER_exchange_secmod_cs_verify ( + &h_cs, + section_name, + GNUNET_TIME_timestamp_ntoh (kan->anchor_time), + GNUNET_TIME_relative_ntoh (kan->duration_withdraw), + &kan->secm_pub, + &kan->secm_sig)) + { + GNUNET_break_op (0); + GNUNET_CRYPTO_blind_sign_pub_decref (bsign_pub); + return GNUNET_SYSERR; + } + dh->dkc (dh->dkc_cls, + section_name, + GNUNET_TIME_timestamp_ntoh (kan->anchor_time), + GNUNET_TIME_relative_ntoh (kan->duration_withdraw), + &h_cs, + bsign_pub, + &kan->secm_pub, + &kan->secm_sig); + GNUNET_CRYPTO_blind_sign_pub_decref (bsign_pub); + } + return GNUNET_OK; +} + + +/** + * Handle a #DONAU_HELPER_CS_MT_PURGE message from the helper. + * + * @param dh helper context + * @param hdr message that we received + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +handle_mt_purge (struct DONAU_CRYPTO_CsDonationUnitHelper *dh, + const struct GNUNET_MessageHeader *hdr) +{ + const struct TALER_CRYPTO_CsKeyPurgeNotification *pn + = (const struct TALER_CRYPTO_CsKeyPurgeNotification *) hdr; + + if (sizeof (*pn) != ntohs (hdr->size)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Received revocation of donation unit key %s\n", + GNUNET_h2s (&pn->h_cs.hash)); + dh->dkc (dh->dkc_cls, + NULL, + GNUNET_TIME_UNIT_ZERO_TS, + GNUNET_TIME_UNIT_ZERO, + &pn->h_cs, + NULL, + NULL, + NULL); + return GNUNET_OK; +} + + +void +DONAU_CRYPTO_helper_cs_poll (struct DONAU_CRYPTO_CsDonationUnitHelper *dh) +{ + char buf[UINT16_MAX]; + size_t off = 0; + unsigned int retry_limit = 3; + const struct GNUNET_MessageHeader *hdr + = (const struct GNUNET_MessageHeader *) buf; + + if (GNUNET_OK != + try_connect (dh)) + return; /* give up */ + while (1) + { + uint16_t msize; + ssize_t ret; + + ret = recv (dh->sock, + buf + off, + sizeof (buf) - off, + (dh->synced && (0 == off)) + ? MSG_DONTWAIT + : 0); + if (ret < 0) + { + if (EINTR == errno) + continue; + if (EAGAIN == errno) + { + GNUNET_assert (dh->synced); + GNUNET_assert (0 == off); + break; + } + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "recv"); + do_disconnect (dh); + if (0 == retry_limit) + return; /* give up */ + if (GNUNET_OK != + try_connect (dh)) + return; /* give up */ + retry_limit--; + continue; + } + if (0 == ret) + { + GNUNET_break (0 == off); + return; + } + off += ret; +more: + if (off < sizeof (struct GNUNET_MessageHeader)) + continue; + msize = ntohs (hdr->size); + if (off < msize) + continue; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Received message of type %u and length %u\n", + (unsigned int) ntohs (hdr->type), + (unsigned int) msize); + switch (ntohs (hdr->type)) + { + case TALER_HELPER_CS_MT_AVAIL: + if (GNUNET_OK != + handle_mt_avail (dh, + hdr)) + { + GNUNET_break_op (0); + do_disconnect (dh); + return; + } + break; + case TALER_HELPER_CS_MT_PURGE: + if (GNUNET_OK != + handle_mt_purge (dh, + hdr)) + { + GNUNET_break_op (0); + do_disconnect (dh); + return; + } + break; + case TALER_HELPER_CS_SYNCED: + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Now synchronized with CS helper\n"); + dh->synced = true; + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Received unexpected message of type %d (len: %u)\n", + (unsigned int) ntohs (hdr->type), + (unsigned int) msize); + GNUNET_break_op (0); + do_disconnect (dh); + return; + } + memmove (buf, + &buf[msize], + off - msize); + off -= msize; + goto more; + } +} + + +enum TALER_ErrorCode +DONAU_CRYPTO_helper_cs_sign ( + struct DONAU_CRYPTO_CsDonationUnitHelper *dh, + const struct TALER_CRYPTO_CsSignRequest *req, + bool for_melt, + struct DONAU_BlindedDonationUnitSignature *bs) +{ + enum TALER_ErrorCode ec = TALER_EC_INVALID; + const struct TALER_CsPubHashP *h_cs = req->h_cs; + + memset (bs, + 0, + sizeof (*bs)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting signature process\n"); + if (GNUNET_OK != + try_connect (dh)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to connect to helper\n"); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Requesting signature\n"); + { + char buf[sizeof (struct TALER_CRYPTO_CsSignRequestMessage)]; + struct TALER_CRYPTO_CsSignRequestMessage *sr + = (struct TALER_CRYPTO_CsSignRequestMessage *) buf; + + sr->header.size = htons (sizeof (buf)); + sr->header.type = htons (TALER_HELPER_CS_MT_REQ_SIGN); + sr->for_melt = htonl (for_melt ? 1 : 0); + sr->h_cs = *h_cs; + sr->message = *req->blinded_planchet; + if (GNUNET_OK != + TALER_crypto_helper_send_all (dh->sock, + buf, + sizeof (buf))) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "send"); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; + } + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Awaiting reply\n"); + { + char buf[UINT16_MAX]; + size_t off = 0; + const struct GNUNET_MessageHeader *hdr + = (const struct GNUNET_MessageHeader *) buf; + bool finished = false; + + while (1) + { + uint16_t msize; + ssize_t ret; + + ret = recv (dh->sock, + &buf[off], + sizeof (buf) - off, + (finished && (0 == off)) + ? MSG_DONTWAIT + : 0); + if (ret < 0) + { + if (EINTR == errno) + continue; + if (EAGAIN == errno) + { + GNUNET_assert (finished); + GNUNET_assert (0 == off); + return ec; + } + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "recv"); + do_disconnect (dh); + ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; + break; + } + if (0 == ret) + { + GNUNET_break (0 == off); + if (! finished) + ec = TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; + return ec; + } + off += ret; +more: + if (off < sizeof (struct GNUNET_MessageHeader)) + continue; + msize = ntohs (hdr->size); + if (off < msize) + continue; + switch (ntohs (hdr->type)) + { + case TALER_HELPER_CS_MT_RES_SIGNATURE: + if (msize != sizeof (struct TALER_CRYPTO_SignResponse)) + { + GNUNET_break_op (0); + do_disconnect (dh); + ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + goto end; + } + if (finished) + { + GNUNET_break_op (0); + do_disconnect (dh); + ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + goto end; + } + { + const struct TALER_CRYPTO_SignResponse *sr = + (const struct TALER_CRYPTO_SignResponse *) buf; + struct GNUNET_CRYPTO_BlindedSignature *blinded_sig; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received signature\n"); + ec = TALER_EC_NONE; + finished = true; + blinded_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature); + blinded_sig->cipher = GNUNET_CRYPTO_BSA_CS; + blinded_sig->rc = 1; + blinded_sig->details.blinded_cs_answer.b = ntohl (sr->b); + blinded_sig->details.blinded_cs_answer.s_scalar = sr->cs_answer; + bs->blinded_sig = blinded_sig; + break; + } + case TALER_HELPER_CS_MT_RES_SIGN_FAILURE: + if (msize != sizeof (struct TALER_CRYPTO_SignFailure)) + { + GNUNET_break_op (0); + do_disconnect (dh); + ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + goto end; + } + { + const struct TALER_CRYPTO_SignFailure *sf = + (const struct TALER_CRYPTO_SignFailure *) buf; + + ec = (enum TALER_ErrorCode) ntohl (sf->ec); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Signing failed with status %d!\n", + ec); + finished = true; + break; + } + case TALER_HELPER_CS_MT_AVAIL: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received new key!\n"); + if (GNUNET_OK != + handle_mt_avail (dh, + hdr)) + { + GNUNET_break_op (0); + do_disconnect (dh); + ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + goto end; + } + break; /* while(1) loop ensures we recvfrom() again */ + case TALER_HELPER_CS_MT_PURGE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received revocation!\n"); + if (GNUNET_OK != + handle_mt_purge (dh, + hdr)) + { + GNUNET_break_op (0); + do_disconnect (dh); + ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + goto end; + } + break; /* while(1) loop ensures we recvfrom() again */ + case TALER_HELPER_CS_SYNCED: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Synchronized add odd time with CS helper!\n"); + dh->synced = true; + break; + default: + GNUNET_break_op (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Received unexpected message of type %u\n", + ntohs (hdr->type)); + do_disconnect (dh); + ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + goto end; + } + memmove (buf, + &buf[msize], + off - msize); + off -= msize; + goto more; + } /* while(1) */ +end: + if (finished) +// DONAU_blinded_donation_unit_sig_free (bs); + return ec; + } +} + + +void +DONAU_CRYPTO_helper_cs_revoke ( + struct DONAU_CRYPTO_CsDonationUnitHelper *dh, + const struct TALER_CsPubHashP *h_cs) +{ + struct TALER_CRYPTO_CsRevokeRequest rr = { + .header.size = htons (sizeof (rr)), + .header.type = htons (TALER_HELPER_CS_MT_REQ_REVOKE), + .h_cs = *h_cs + }; + + if (GNUNET_OK != + try_connect (dh)) + return; /* give up */ + if (GNUNET_OK != + TALER_crypto_helper_send_all (dh->sock, + &rr, + sizeof (rr))) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "send"); + do_disconnect (dh); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Requested revocation of donation unit key %s\n", + GNUNET_h2s (&h_cs->hash)); +} + + +enum TALER_ErrorCode +DONAU_CRYPTO_helper_cs_r_derive (struct DONAU_CRYPTO_CsDonationUnitHelper *dh, + const struct TALER_CRYPTO_CsDeriveRequest *cdr, + bool for_melt, + struct GNUNET_CRYPTO_CSPublicRPairP *crp) +{ + enum TALER_ErrorCode ec = TALER_EC_INVALID; + const struct TALER_CsPubHashP *h_cs = cdr->h_cs; + const struct GNUNET_CRYPTO_CsSessionNonce *nonce = cdr->nonce; + + memset (crp, + 0, + sizeof (*crp)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting R derivation process\n"); + if (GNUNET_OK != + try_connect (dh)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to connect to helper\n"); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Requesting R\n"); + { + struct TALER_CRYPTO_CsRDeriveRequest rdr = { + .header.size = htons (sizeof (rdr)), + .header.type = htons (TALER_HELPER_CS_MT_REQ_RDERIVE), + .for_melt = htonl (for_melt ? 1 : 0), + .h_cs = *h_cs, + .nonce = *nonce + }; + + if (GNUNET_OK != + TALER_crypto_helper_send_all (dh->sock, + &rdr, + sizeof (rdr))) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "send"); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; + } + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Awaiting reply\n"); + { + char buf[UINT16_MAX]; + size_t off = 0; + const struct GNUNET_MessageHeader *hdr + = (const struct GNUNET_MessageHeader *) buf; + bool finished = false; + + while (1) + { + uint16_t msize; + ssize_t ret; + + ret = recv (dh->sock, + &buf[off], + sizeof (buf) - off, + (finished && (0 == off)) + ? MSG_DONTWAIT + : 0); + if (ret < 0) + { + if (EINTR == errno) + continue; + if (EAGAIN == errno) + { + GNUNET_assert (finished); + GNUNET_assert (0 == off); + return ec; + } + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "recv"); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; + } + if (0 == ret) + { + GNUNET_break (0 == off); + if (! finished) + return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; + return ec; + } + off += ret; +more: + if (off < sizeof (struct GNUNET_MessageHeader)) + continue; + msize = ntohs (hdr->size); + if (off < msize) + continue; + switch (ntohs (hdr->type)) + { + case TALER_HELPER_CS_MT_RES_RDERIVE: + if (msize != sizeof (struct TALER_CRYPTO_RDeriveResponse)) + { + GNUNET_break_op (0); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + if (finished) + { + GNUNET_break_op (0); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + { + const struct TALER_CRYPTO_RDeriveResponse *rdr = + (const struct TALER_CRYPTO_RDeriveResponse *) buf; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received R\n"); + finished = true; + ec = TALER_EC_NONE; + *crp = rdr->r_pub; + break; + } + case TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE: + if (msize != sizeof (struct TALER_CRYPTO_RDeriveFailure)) + { + GNUNET_break_op (0); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + { + const struct TALER_CRYPTO_RDeriveFailure *rdf = + (const struct TALER_CRYPTO_RDeriveFailure *) buf; + + ec = (enum TALER_ErrorCode) ntohl (rdf->ec); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "R derivation failed!\n"); + finished = true; + break; + } + case TALER_HELPER_CS_MT_AVAIL: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received new key!\n"); + if (GNUNET_OK != + handle_mt_avail (dh, + hdr)) + { + GNUNET_break_op (0); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + break; /* while(1) loop ensures we recvfrom() again */ + case TALER_HELPER_CS_MT_PURGE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received revocation!\n"); + if (GNUNET_OK != + handle_mt_purge (dh, + hdr)) + { + GNUNET_break_op (0); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + break; /* while(1) loop ensures we recvfrom() again */ + case TALER_HELPER_CS_SYNCED: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Synchronized add odd time with CS helper!\n"); + dh->synced = true; + break; + default: + GNUNET_break_op (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Received unexpected message of type %u\n", + ntohs (hdr->type)); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + memmove (buf, + &buf[msize], + off - msize); + off -= msize; + goto more; + } /* while(1) */ + } +} + + +enum TALER_ErrorCode +DONAU_CRYPTO_helper_cs_batch_sign ( + struct DONAU_CRYPTO_CsDonationUnitHelper *dh, + unsigned int reqs_length, + const struct TALER_CRYPTO_CsSignRequest reqs[static reqs_length], + bool for_melt, + struct DONAU_BlindedDonationUnitSignature bss[static reqs_length]) +{ + enum TALER_ErrorCode ec = TALER_EC_INVALID; + unsigned int rpos; + unsigned int rend; + unsigned int wpos; + + memset (bss, + 0, + sizeof (*bss) * reqs_length); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting signature process\n"); + if (GNUNET_OK != + try_connect (dh)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to connect to helper\n"); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Requesting %u signatures\n", + reqs_length); + rpos = 0; + rend = 0; + wpos = 0; + while (rpos < reqs_length) + { + unsigned int mlen = sizeof (struct TALER_CRYPTO_BatchSignRequest); + + while ( (rend < reqs_length) && + (mlen + sizeof (struct TALER_CRYPTO_CsSignRequestMessage) + < UINT16_MAX) ) + { + mlen += sizeof (struct TALER_CRYPTO_CsSignRequestMessage); + rend++; + } + { + char obuf[mlen] GNUNET_ALIGN; + struct TALER_CRYPTO_BatchSignRequest *bsr + = (struct TALER_CRYPTO_BatchSignRequest *) obuf; + void *wbuf; + + bsr->header.type = htons (TALER_HELPER_CS_MT_REQ_BATCH_SIGN); + bsr->header.size = htons (mlen); + bsr->batch_size = htonl (rend - rpos); + wbuf = &bsr[1]; + for (unsigned int i = rpos; i<rend; i++) + { + struct TALER_CRYPTO_CsSignRequestMessage *csm = wbuf; + const struct TALER_CRYPTO_CsSignRequest *csr = &reqs[i]; + + csm->header.size = htons (sizeof (*csm)); + csm->header.type = htons (TALER_HELPER_CS_MT_REQ_SIGN); + csm->for_melt = htonl (for_melt ? 1 : 0); + csm->h_cs = *csr->h_cs; + csm->message = *csr->blinded_planchet; + wbuf += sizeof (*csm); + } + GNUNET_assert (wbuf == &obuf[mlen]); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending batch request [%u-%u)\n", + rpos, + rend); + if (GNUNET_OK != + TALER_crypto_helper_send_all (dh->sock, + obuf, + sizeof (obuf))) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "send"); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; + } + } /* end of obuf scope */ + rpos = rend; + { + char buf[UINT16_MAX]; + size_t off = 0; + const struct GNUNET_MessageHeader *hdr + = (const struct GNUNET_MessageHeader *) buf; + bool finished = false; + + while (1) + { + uint16_t msize; + ssize_t ret; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Awaiting reply at %u (up to %u)\n", + wpos, + rend); + ret = recv (dh->sock, + &buf[off], + sizeof (buf) - off, + (finished && (0 == off)) + ? MSG_DONTWAIT + : 0); + if (ret < 0) + { + if (EINTR == errno) + continue; + if (EAGAIN == errno) + { + GNUNET_assert (finished); + GNUNET_assert (0 == off); + break; + } + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "recv"); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; + } + if (0 == ret) + { + GNUNET_break (0 == off); + if (! finished) + return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; + if (TALER_EC_NONE == ec) + break; + return ec; + } + off += ret; +more: + if (off < sizeof (struct GNUNET_MessageHeader)) + continue; + msize = ntohs (hdr->size); + if (off < msize) + continue; + switch (ntohs (hdr->type)) + { + case TALER_HELPER_CS_MT_RES_SIGNATURE: + if (msize != sizeof (struct TALER_CRYPTO_SignResponse)) + { + GNUNET_break_op (0); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + if (finished) + { + GNUNET_break_op (0); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + { + const struct TALER_CRYPTO_SignResponse *sr = + (const struct TALER_CRYPTO_SignResponse *) buf; + struct GNUNET_CRYPTO_BlindedSignature *blinded_sig; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received %u signature\n", + wpos); + blinded_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature); + blinded_sig->cipher = GNUNET_CRYPTO_BSA_CS; + blinded_sig->rc = 1; + blinded_sig->details.blinded_cs_answer.b = ntohl (sr->b); + blinded_sig->details.blinded_cs_answer.s_scalar = sr->cs_answer; + + bss[wpos].blinded_sig = blinded_sig; + wpos++; + if (wpos == rend) + { + if (TALER_EC_INVALID == ec) + ec = TALER_EC_NONE; + finished = true; + } + break; + } + + case TALER_HELPER_CS_MT_RES_SIGN_FAILURE: + if (msize != sizeof (struct TALER_CRYPTO_SignFailure)) + { + GNUNET_break_op (0); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + { + const struct TALER_CRYPTO_SignFailure *sf = + (const struct TALER_CRYPTO_SignFailure *) buf; + + ec = (enum TALER_ErrorCode) ntohl (sf->ec); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Signing %u failed with status %d!\n", + wpos, + ec); + wpos++; + if (wpos == rend) + { + finished = true; + } + break; + } + case TALER_HELPER_CS_MT_AVAIL: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received new key!\n"); + if (GNUNET_OK != + handle_mt_avail (dh, + hdr)) + { + GNUNET_break_op (0); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + break; /* while(1) loop ensures we recvfrom() again */ + case TALER_HELPER_CS_MT_PURGE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received revocation!\n"); + if (GNUNET_OK != + handle_mt_purge (dh, + hdr)) + { + GNUNET_break_op (0); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + break; /* while(1) loop ensures we recvfrom() again */ + case TALER_HELPER_CS_SYNCED: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Synchronized add odd time with CS helper!\n"); + dh->synced = true; + break; + default: + GNUNET_break_op (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Received unexpected message of type %u\n", + ntohs (hdr->type)); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + memmove (buf, + &buf[msize], + off - msize); + off -= msize; + goto more; + } /* while(1) */ + } /* scope */ + } /* while (rpos < cdrs_length) */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Existing with %u signatures and status %d\n", + wpos, + ec); + return ec; +} + + +enum TALER_ErrorCode +DONAU_CRYPTO_helper_cs_r_batch_derive ( + struct DONAU_CRYPTO_CsDonationUnitHelper *dh, + unsigned int cdrs_length, + const struct TALER_CRYPTO_CsDeriveRequest cdrs[static cdrs_length], + bool for_melt, + struct GNUNET_CRYPTO_CSPublicRPairP crps[static cdrs_length]) +{ + enum TALER_ErrorCode ec = TALER_EC_INVALID; + unsigned int rpos; + unsigned int rend; + unsigned int wpos; + + memset (crps, + 0, + sizeof (*crps) * cdrs_length); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting R derivation process\n"); + if (GNUNET_OK != + try_connect (dh)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to connect to helper\n"); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Requesting %u R pairs\n", + cdrs_length); + rpos = 0; + rend = 0; + wpos = 0; + while (rpos < cdrs_length) + { + unsigned int mlen = sizeof (struct TALER_CRYPTO_BatchDeriveRequest); + + while ( (rend < cdrs_length) && + (mlen + sizeof (struct TALER_CRYPTO_CsRDeriveRequest) + < UINT16_MAX) ) + { + mlen += sizeof (struct TALER_CRYPTO_CsRDeriveRequest); + rend++; + } + { + char obuf[mlen] GNUNET_ALIGN; + struct TALER_CRYPTO_BatchDeriveRequest *bdr + = (struct TALER_CRYPTO_BatchDeriveRequest *) obuf; + void *wbuf; + + bdr->header.type = htons (TALER_HELPER_CS_MT_REQ_BATCH_RDERIVE); + bdr->header.size = htons (mlen); + bdr->batch_size = htonl (rend - rpos); + wbuf = &bdr[1]; + for (unsigned int i = rpos; i<rend; i++) + { + struct TALER_CRYPTO_CsRDeriveRequest *rdr = wbuf; + const struct TALER_CRYPTO_CsDeriveRequest *cdr = &cdrs[i]; + + rdr->header.size = htons (sizeof (*rdr)); + rdr->header.type = htons (TALER_HELPER_CS_MT_REQ_RDERIVE); + rdr->for_melt = htonl (for_melt ? 1 : 0); + rdr->h_cs = *cdr->h_cs; + rdr->nonce = *cdr->nonce; + wbuf += sizeof (*rdr); + } + GNUNET_assert (wbuf == &obuf[mlen]); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending batch request [%u-%u)\n", + rpos, + rend); + if (GNUNET_OK != + TALER_crypto_helper_send_all (dh->sock, + obuf, + sizeof (obuf))) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "send"); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; + } + } /* end of obuf scope */ + rpos = rend; + { + char buf[UINT16_MAX]; + size_t off = 0; + const struct GNUNET_MessageHeader *hdr + = (const struct GNUNET_MessageHeader *) buf; + bool finished = false; + + while (1) + { + uint16_t msize; + ssize_t ret; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Awaiting reply at %u (up to %u)\n", + wpos, + rend); + ret = recv (dh->sock, + &buf[off], + sizeof (buf) - off, + (finished && (0 == off)) + ? MSG_DONTWAIT + : 0); + if (ret < 0) + { + if (EINTR == errno) + continue; + if (EAGAIN == errno) + { + GNUNET_assert (finished); + GNUNET_assert (0 == off); + break; + } + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "recv"); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; + } + if (0 == ret) + { + GNUNET_break (0 == off); + if (! finished) + return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; + if (TALER_EC_NONE == ec) + break; + return ec; + } + off += ret; +more: + if (off < sizeof (struct GNUNET_MessageHeader)) + continue; + msize = ntohs (hdr->size); + if (off < msize) + continue; + switch (ntohs (hdr->type)) + { + case TALER_HELPER_CS_MT_RES_RDERIVE: + if (msize != sizeof (struct TALER_CRYPTO_RDeriveResponse)) + { + GNUNET_break_op (0); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + if (finished) + { + GNUNET_break_op (0); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + { + const struct TALER_CRYPTO_RDeriveResponse *rdr = + (const struct TALER_CRYPTO_RDeriveResponse *) buf; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received %u R pair\n", + wpos); + crps[wpos] = rdr->r_pub; + wpos++; + if (wpos == rend) + { + if (TALER_EC_INVALID == ec) + ec = TALER_EC_NONE; + finished = true; + } + break; + } + case TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE: + if (msize != sizeof (struct TALER_CRYPTO_RDeriveFailure)) + { + GNUNET_break_op (0); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + { + const struct TALER_CRYPTO_RDeriveFailure *rdf = + (const struct TALER_CRYPTO_RDeriveFailure *) buf; + + ec = (enum TALER_ErrorCode) ntohl (rdf->ec); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "R derivation %u failed with status %d!\n", + wpos, + ec); + wpos++; + if (wpos == rend) + { + finished = true; + } + break; + } + case TALER_HELPER_CS_MT_AVAIL: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received new key!\n"); + if (GNUNET_OK != + handle_mt_avail (dh, + hdr)) + { + GNUNET_break_op (0); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + break; /* while(1) loop ensures we recvfrom() again */ + case TALER_HELPER_CS_MT_PURGE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received revocation!\n"); + if (GNUNET_OK != + handle_mt_purge (dh, + hdr)) + { + GNUNET_break_op (0); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + break; /* while(1) loop ensures we recvfrom() again */ + case TALER_HELPER_CS_SYNCED: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Synchronized add odd time with CS helper!\n"); + dh->synced = true; + break; + default: + GNUNET_break_op (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Received unexpected message of type %u\n", + ntohs (hdr->type)); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + memmove (buf, + &buf[msize], + off - msize); + off -= msize; + goto more; + } /* while(1) */ + } /* scope */ + } /* while (rpos < cdrs_length) */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Existing with %u signatures and status %d\n", + wpos, + ec); + return ec; +} + + +void +DONAU_CRYPTO_helper_cs_disconnect ( + struct DONAU_CRYPTO_CsDonationUnitHelper *dh) +{ + if (-1 != dh->sock) + do_disconnect (dh); + GNUNET_free (dh); +} + + +/* end of crypto_helper_cs.c */ diff --git a/src/util/crypto_helper_esign.c b/src/util/crypto_helper_esign.c @@ -0,0 +1,557 @@ +/* + This file is part of TALER + Copyright (C) 2020-2024 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file util/crypto_helper_esign.c + * @brief utility functions for running out-of-process private key operations + * @author Christian Grothoff + * @author Pius Loosli + */ +#include <taler/platform.h> +#include <taler/taler_util.h> +#include <taler/taler_signatures.h> +#include <taler/taler-exchange-secmod-eddsa.h> +#include <poll.h> +#include <crypto_helper_common.h> +#include "donau_util.h" + +struct DONAU_CRYPTO_DonauSignHelper +{ + /** + * Function to call with updates to available key material. + */ + DONAU_CRYPTO_DonauKeyStatusCallback dkc; + + /** + * Closure for @e dkc + */ + void *dkc_cls; + + /** + * Socket address of the denomination helper process. + * Used to reconnect if the connection breaks. + */ + struct sockaddr_un sa; + + /** + * The UNIX domain socket, -1 if we are currently not connected. + */ + int sock; + + /** + * Have we reached the sync'ed state? + */ + bool synced; + +}; + + +/** + * Disconnect from the helper process. Updates + * @e sock field in @a dsh. + * + * @param[in,out] dsh handle to tear down connection of + */ +static void +do_disconnect (struct DONAU_CRYPTO_DonauSignHelper *dsh) +{ + GNUNET_break (0 == close (dsh->sock)); + dsh->sock = -1; + dsh->synced = false; +} + + +/** + * Try to connect to the helper process. Updates + * @e sock field in @a dsh. + * + * @param[in,out] dsh handle to establish connection for + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +try_connect (struct DONAU_CRYPTO_DonauSignHelper *dsh) +{ + if (-1 != dsh->sock) + return GNUNET_OK; + dsh->sock = socket (AF_UNIX, + SOCK_STREAM, + 0); + if (-1 == dsh->sock) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "socket"); + return GNUNET_SYSERR; + } + if (0 != + connect (dsh->sock, + (const struct sockaddr *) &dsh->sa, + sizeof (dsh->sa))) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, + "connect", + dsh->sa.sun_path); + do_disconnect (dsh); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +struct DONAU_CRYPTO_DonauSignHelper * +DONAU_CRYPTO_helper_esign_connect ( + const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, + DONAU_CRYPTO_DonauKeyStatusCallback dkc, + void *dkc_cls) +{ + struct DONAU_CRYPTO_DonauSignHelper *dsh; + char *unixpath; + char *secname; + + GNUNET_asprintf (&secname, + "%s-exchange-secmod-eddsa", + section); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + secname, + "UNIXPATH", + &unixpath)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + secname, + "UNIXPATH"); + GNUNET_free (secname); + return NULL; + } + /* we use >= here because we want the sun_path to always + be 0-terminated */ + if (strlen (unixpath) >= sizeof (dsh->sa.sun_path)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + secname, + "UNIXPATH", + "path too long"); + GNUNET_free (unixpath); + GNUNET_free (secname); + return NULL; + } + GNUNET_free (secname); + dsh = GNUNET_new (struct DONAU_CRYPTO_DonauSignHelper); + dsh->dkc = dkc; + dsh->dkc_cls = dkc_cls; + dsh->sa.sun_family = AF_UNIX; + strncpy (dsh->sa.sun_path, + unixpath, + sizeof (dsh->sa.sun_path) - 1); + GNUNET_free (unixpath); + dsh->sock = -1; + if (GNUNET_OK != + try_connect (dsh)) + { + DONAU_CRYPTO_helper_esign_disconnect (dsh); + return NULL; + } + +// DONAU_CRYPTO_helper_esign_poll (dsh); + return dsh; +} + + +/** + * Handle a #TALER_HELPER_EDDSA_MT_AVAIL message from the helper. + * + * @param dsh helper context + * @param hdr message that we received + * @return #GNUNET_OK on success + */ +// static enum GNUNET_GenericReturnValue +// handle_mt_avail (struct DONAU_CRYPTO_DonauSignHelper *dsh, +// const struct GNUNET_MessageHeader *hdr) +// { +// const struct TALER_CRYPTO_EddsaKeyAvailableNotification *kan +// = (const struct TALER_CRYPTO_EddsaKeyAvailableNotification *) hdr; +// +// if (sizeof (*kan) != ntohs (hdr->size)) +// { +// GNUNET_break_op (0); +// return GNUNET_SYSERR; +// } +// +// if (GNUNET_OK != +// TALER_exchange_secmod_eddsa_verify ( +// &kan->exchange_pub, +// GNUNET_TIME_timestamp_ntoh (kan->anchor_time), +// GNUNET_TIME_relative_ntoh (kan->duration), +// &kan->secm_pub, +// &kan->secm_sig)) +// { +// GNUNET_break_op (0); +// return GNUNET_SYSERR; +// } +// dsh->dkc (dsh->dkc_cls, +// GNUNET_TIME_timestamp_ntoh (kan->anchor_time), +// GNUNET_TIME_relative_ntoh (kan->duration), +// &kan->donau_pub, +// &kan->secm_pub, +// &kan->secm_sig); +// return GNUNET_OK; +// } + + +/** + * Handle a #TALER_HELPER_EDDSA_MT_PURGE message from the helper. + * + * @param dsh helper context + * @param hdr message that we received + * @return #GNUNET_OK on success + */ +// static enum GNUNET_GenericReturnValue +// handle_mt_purge (struct DONAU_CRYPTO_DonauSignHelper *dsh, +// const struct GNUNET_MessageHeader *hdr) +// { +// const struct TALER_CRYPTO_EddsaKeyPurgeNotification *pn +// = (const struct TALER_CRYPTO_EddsaKeyPurgeNotification *) hdr; +// +// if (sizeof (*pn) != ntohs (hdr->size)) +// { +// GNUNET_break_op (0); +// return GNUNET_SYSERR; +// } +// dsh->dkc (dsh->dkc_cls, +// GNUNET_TIME_UNIT_ZERO_TS, +// GNUNET_TIME_UNIT_ZERO, +// &pn->exchange_pub, +// NULL, +// NULL); +// return GNUNET_OK; +// } + + +// void +// DONAU_CRYPTO_helper_esign_poll (struct DONAU_CRYPTO_DonauSignHelper *dsh) +// { +// char buf[UINT16_MAX]; +// size_t off = 0; +// unsigned int retry_limit = 3; +// const struct GNUNET_MessageHeader *hdr +// = (const struct GNUNET_MessageHeader *) buf; +// +// if (GNUNET_OK != +// try_connect (dsh)) +// return; /* give up */ +// while (1) +// { +// uint16_t msize; +// ssize_t ret; +// +// ret = recv (dsh->sock, +// buf + off, +// sizeof (buf) - off, +// (dsh->synced && (0 == off)) +// ? MSG_DONTWAIT +// : 0); +// if (ret < 0) +// { +// if (EINTR == errno) +// continue; +// if (EAGAIN == errno) +// { +// GNUNET_assert (dsh->synced); +// GNUNET_assert (0 == off); +// break; +// } +// GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, +// "recv"); +// do_disconnect (dsh); +// if (0 == retry_limit) +// return; /* give up */ +// if (GNUNET_OK != +// try_connect (dsh)) +// return; /* give up */ +// retry_limit--; +// continue; +// } +// if (0 == ret) +// { +// GNUNET_break (0 == off); +// return; +// } +// off += ret; +// more: +// if (off < sizeof (struct GNUNET_MessageHeader)) +// continue; +// msize = ntohs (hdr->size); +// if (off < msize) +// continue; +// switch (ntohs (hdr->type)) +// { +// case TALER_HELPER_EDDSA_MT_AVAIL: +// if (GNUNET_OK != +// handle_mt_avail (dsh, +// hdr)) +// { +// GNUNET_break_op (0); +// do_disconnect (dsh); +// return; +// } +// break; +// case TALER_HELPER_EDDSA_MT_PURGE: +// if (GNUNET_OK != +// handle_mt_purge (dsh, +// hdr)) +// { +// GNUNET_break_op (0); +// do_disconnect (dsh); +// return; +// } +// break; +// case TALER_HELPER_EDDSA_SYNCED: +// GNUNET_log (GNUNET_ERROR_TYPE_INFO, +// "Now synchronized with EdDSA helper\n"); +// dsh->synced = true; +// break; +// default: +// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +// "Received unexpected message of type %d (len: %u)\n", +// (unsigned int) ntohs (hdr->type), +// (unsigned int) msize); +// GNUNET_break_op (0); +// do_disconnect (dsh); +// return; +// } +// memmove (buf, +// &buf[msize], +// off - msize); +// off -= msize; +// goto more; +// } +// } + + +// enum TALER_ErrorCode +// DONAU_CRYPTO_helper_esign_sign_ ( +// struct DONAU_CRYPTO_DonauSignHelper *dsh, +// const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, +// struct DONAU_DonauPublicKeyP *exchange_pub, +// struct DONAU_DonauSignatureP *exchange_sig) +// { +// uint32_t purpose_size = ntohl (purpose->size); +// +// if (GNUNET_OK != +// try_connect (dsh)) +// { +// GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +// "Failed to connect to helper\n"); +// return TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE; +// } +// GNUNET_assert (purpose_size < +// UINT16_MAX - sizeof (struct TALER_CRYPTO_EddsaSignRequest)); +// { +// char buf[sizeof (struct TALER_CRYPTO_EddsaSignRequest) + purpose_size +// - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose)]; +// struct TALER_CRYPTO_EddsaSignRequest *sr +// = (struct TALER_CRYPTO_EddsaSignRequest *) buf; +// +// sr->header.size = htons (sizeof (buf)); +// sr->header.type = htons (TALER_HELPER_EDDSA_MT_REQ_SIGN); +// sr->reserved = htonl (0); +// GNUNET_memcpy (&sr->purpose, +// purpose, +// purpose_size); +// if (GNUNET_OK != +// TALER_crypto_helper_send_all (dsh->sock, +// buf, +// sizeof (buf))) +// { +// GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, +// "send", +// dsh->sa.sun_path); +// do_disconnect (dsh); +// return TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE; +// } +// } +// +// { +// char buf[UINT16_MAX]; +// size_t off = 0; +// const struct GNUNET_MessageHeader *hdr +// = (const struct GNUNET_MessageHeader *) buf; +// bool finished = false; +// enum TALER_ErrorCode ec = TALER_EC_INVALID; +// +// while (1) +// { +// ssize_t ret; +// uint16_t msize; +// +// ret = recv (dsh->sock, +// &buf[off], +// sizeof (buf) - off, +// (finished && (0 == off)) +// ? MSG_DONTWAIT +// : 0); +// if (ret < 0) +// { +// if (EINTR == errno) +// continue; +// if (EAGAIN == errno) +// { +// GNUNET_assert (finished); +// GNUNET_assert (0 == off); +// break; +// } +// GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, +// "recv"); +// do_disconnect (dsh); +// return TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE; +// } +// if (0 == ret) +// { +// GNUNET_break (0 == off); +// if (finished) +// return TALER_EC_NONE; +// return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; +// } +// off += ret; +// more: +// if (off < sizeof (struct GNUNET_MessageHeader)) +// continue; +// msize = ntohs (hdr->size); +// if (off < msize) +// continue; +// switch (ntohs (hdr->type)) +// { +// case TALER_HELPER_EDDSA_MT_RES_SIGNATURE: +// if (msize != sizeof (struct TALER_CRYPTO_EddsaSignResponse)) +// { +// GNUNET_break_op (0); +// do_disconnect (dsh); +// return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; +// } +// if (finished) +// { +// GNUNET_break_op (0); +// do_disconnect (dsh); +// return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; +// } +// { +// const struct TALER_CRYPTO_EddsaSignResponse *sr = +// (const struct TALER_CRYPTO_EddsaSignResponse *) buf; +// *exchange_sig = sr->exchange_sig; +// *exchange_pub = sr->exchange_pub; +// finished = true; +// ec = TALER_EC_NONE; +// break; +// } +// case TALER_HELPER_EDDSA_MT_RES_SIGN_FAILURE: +// if (msize != sizeof (struct TALER_CRYPTO_EddsaSignFailure)) +// { +// GNUNET_break_op (0); +// do_disconnect (dsh); +// return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; +// } +// { +// const struct TALER_CRYPTO_EddsaSignFailure *sf = +// (const struct TALER_CRYPTO_EddsaSignFailure *) buf; +// +// finished = true; +// ec = (enum TALER_ErrorCode) ntohl (sf->ec); +// break; +// } +// case TALER_HELPER_EDDSA_MT_AVAIL: +// if (GNUNET_OK != +// handle_mt_avail (dsh, +// hdr)) +// { +// GNUNET_break_op (0); +// do_disconnect (dsh); +// return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; +// } +// break; /* while(1) loop ensures we recv() again */ +// case TALER_HELPER_EDDSA_MT_PURGE: +// if (GNUNET_OK != +// handle_mt_purge (dsh, +// hdr)) +// { +// GNUNET_break_op (0); +// do_disconnect (dsh); +// return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; +// } +// break; /* while(1) loop ensures we recv() again */ +// case TALER_HELPER_EDDSA_SYNCED: +// GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +// "Synchronized add odd time with EdDSA helper!\n"); +// dsh->synced = true; +// break; +// default: +// GNUNET_break_op (0); +// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +// "Received unexpected message of type %u\n", +// ntohs (hdr->type)); +// do_disconnect (dsh); +// return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; +// } +// memmove (buf, +// &buf[msize], +// off - msize); +// off -= msize; +// goto more; +// } /* while(1) */ +// return ec; +// } +// } + + +// void +// DONAU_CRYPTO_helper_esign_revoke ( +// struct DONAU_CRYPTO_DonauSignHelper *dsh, +// const struct DONAU_DonauPublicKeyP *exchange_pub) +// { +// if (GNUNET_OK != +// try_connect (dsh)) +// return; /* give up */ +// { +// struct TALER_CRYPTO_EddsaRevokeRequest rr = { +// .header.size = htons (sizeof (rr)), +// .header.type = htons (TALER_HELPER_EDDSA_MT_REQ_REVOKE), +// .exchange_pub = *exchange_pub +// }; +// +// if (GNUNET_OK != +// TALER_crypto_helper_send_all (dsh->sock, +// &rr, +// sizeof (rr))) +// { +// GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, +// "send"); +// do_disconnect (dsh); +// return; +// } +// } +// } + + +void +DONAU_CRYPTO_helper_esign_disconnect ( + struct DONAU_CRYPTO_DonauSignHelper *dsh) +{ + if (-1 != dsh->sock) + do_disconnect (dsh); + GNUNET_free (dsh); +} + + +/* end of crypto_helper_esign.c */ diff --git a/src/util/crypto_helper_rsa.c b/src/util/crypto_helper_rsa.c @@ -0,0 +1,917 @@ +/* + This file is part of TALER + Copyright (C) 2020-2024 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file util/crypto_helper_rsa.c + * @brief utility functions for running out-of-process private key operations + * @author Christian Grothoff + * @author Pius Loosli + */ +#include <taler/platform.h> +#include <taler/taler_util.h> +#include <taler/taler_signatures.h> +#include <taler/taler-exchange-secmod-rsa.h> +#include <poll.h> +#include <crypto_helper_common.h> +#include "donau_util.h" + +struct DONAU_CRYPTO_RsaDonationUnitHelper +{ + /** + * Function to call with updates to available key material. + */ + DONAU_CRYPTO_RsaDonationUnitKeyStatusCallback dkc; + + /** + * Closure for @e dkc + */ + void *dkc_cls; + + /** + * Socket address of the donation unitination helper process. + * Used to reconnect if the connection breaks. + */ + struct sockaddr_un sa; + + /** + * The UNIX domain socket, -1 if we are currently not connected. + */ + int sock; + + /** + * Have we ever been sync'ed? + */ + bool synced; +}; + + +/** + * Disconnect from the helper process. Updates + * @e sock field in @a dh. + * + * @param[in,out] dh handle to tear down connection of + */ +static void +do_disconnect (struct DONAU_CRYPTO_RsaDonationUnitHelper *dh) +{ + GNUNET_break (0 == close (dh->sock)); + dh->sock = -1; + dh->synced = false; +} + + +/** + * Try to connect to the helper process. Updates + * @e sock field in @a dh. + * + * @param[in,out] dh handle to establish connection for + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +try_connect (struct DONAU_CRYPTO_RsaDonationUnitHelper *dh) +{ + if (-1 != dh->sock) + return GNUNET_OK; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Establishing connection!\n"); + dh->sock = socket (AF_UNIX, + SOCK_STREAM, + 0); + if (-1 == dh->sock) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "socket"); + return GNUNET_SYSERR; + } + if (0 != + connect (dh->sock, + (const struct sockaddr *) &dh->sa, + sizeof (dh->sa))) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, + "connect", + dh->sa.sun_path); + do_disconnect (dh); + return GNUNET_SYSERR; + } + DONAU_CRYPTO_helper_rsa_poll (dh); + return GNUNET_OK; +} + + +struct DONAU_CRYPTO_RsaDonationUnitHelper * +DONAU_CRYPTO_helper_rsa_connect ( + const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, + DONAU_CRYPTO_RsaDonationUnitKeyStatusCallback dkc, + void *dkc_cls) +{ + struct DONAU_CRYPTO_RsaDonationUnitHelper *dh; + char *unixpath; + char *secname; + + GNUNET_asprintf (&secname, + "%s-exchange-secmod-rsa", + section); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + secname, + "UNIXPATH", + &unixpath)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + secname, + "UNIXPATH"); + GNUNET_free (secname); + return NULL; + } + /* we use >= here because we want the sun_path to always + be 0-terminated */ + if (strlen (unixpath) >= sizeof (dh->sa.sun_path)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + "taler-exchange-secmod-rsa", + "UNIXPATH", + "path too long"); + GNUNET_free (unixpath); + GNUNET_free (secname); + return NULL; + } + GNUNET_free (secname); + dh = GNUNET_new (struct DONAU_CRYPTO_RsaDonationUnitHelper); + dh->dkc = dkc; + dh->dkc_cls = dkc_cls; + dh->sa.sun_family = AF_UNIX; + strncpy (dh->sa.sun_path, + unixpath, + sizeof (dh->sa.sun_path) - 1); + GNUNET_free (unixpath); + dh->sock = -1; + if (GNUNET_OK != + try_connect (dh)) + { + DONAU_CRYPTO_helper_rsa_disconnect (dh); + return NULL; + } + return dh; +} + + +/** + * Handle a #TALER_HELPER_RSA_MT_AVAIL message from the helper. + * + * @param dh helper context + * @param hdr message that we received + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +handle_mt_avail (struct DONAU_CRYPTO_RsaDonationUnitHelper *dh, + const struct GNUNET_MessageHeader *hdr) +{ + const struct TALER_CRYPTO_RsaKeyAvailableNotification *kan + = (const struct TALER_CRYPTO_RsaKeyAvailableNotification *) hdr; + const char *buf = (const char *) &kan[1]; + const char *section_name; + uint16_t ps; + uint16_t snl; + + if (sizeof (*kan) > ntohs (hdr->size)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + ps = ntohs (kan->pub_size); + snl = ntohs (kan->section_name_len); + if (ntohs (hdr->size) != sizeof (*kan) + ps + snl) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (0 == snl) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + section_name = &buf[ps]; + if ('\0' != section_name[snl - 1]) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + { + struct GNUNET_CRYPTO_BlindSignPublicKey *bs_pub; + struct TALER_RsaPubHashP h_rsa; + + bs_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey); + bs_pub->cipher = GNUNET_CRYPTO_BSA_RSA; + bs_pub->details.rsa_public_key + = GNUNET_CRYPTO_rsa_public_key_decode (buf, + ntohs (kan->pub_size)); + if (NULL == bs_pub->details.rsa_public_key) + { + GNUNET_break_op (0); + GNUNET_free (bs_pub); + return GNUNET_SYSERR; + } + bs_pub->rc = 1; + GNUNET_CRYPTO_rsa_public_key_hash (bs_pub->details.rsa_public_key, + &bs_pub->pub_key_hash); + h_rsa.hash = bs_pub->pub_key_hash; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Received RSA key %s (%s)\n", + GNUNET_h2s (&bs_pub->pub_key_hash), + section_name); + if (GNUNET_OK != + TALER_exchange_secmod_rsa_verify ( + &h_rsa, + section_name, + GNUNET_TIME_timestamp_ntoh (kan->anchor_time), + GNUNET_TIME_relative_ntoh (kan->duration_withdraw), + &kan->secm_pub, + &kan->secm_sig)) + { + GNUNET_break_op (0); + GNUNET_CRYPTO_blind_sign_pub_decref (bs_pub); + return GNUNET_SYSERR; + } + dh->dkc (dh->dkc_cls, + section_name, + GNUNET_TIME_timestamp_ntoh (kan->anchor_time), + GNUNET_TIME_relative_ntoh (kan->duration_withdraw), + &h_rsa, + bs_pub, + &kan->secm_pub, + &kan->secm_sig); + GNUNET_CRYPTO_blind_sign_pub_decref (bs_pub); + } + return GNUNET_OK; +} + + +/** + * Handle a #TALER_HELPER_RSA_MT_PURGE message from the helper. + * + * @param dh helper context + * @param hdr message that we received + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +handle_mt_purge (struct DONAU_CRYPTO_RsaDonationUnitHelper *dh, + const struct GNUNET_MessageHeader *hdr) +{ + const struct TALER_CRYPTO_RsaKeyPurgeNotification *pn + = (const struct TALER_CRYPTO_RsaKeyPurgeNotification *) hdr; + + if (sizeof (*pn) != ntohs (hdr->size)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Received revocation of donation unit key %s\n", + GNUNET_h2s (&pn->h_rsa.hash)); + dh->dkc (dh->dkc_cls, + NULL, + GNUNET_TIME_UNIT_ZERO_TS, + GNUNET_TIME_UNIT_ZERO, + &pn->h_rsa, + NULL, + NULL, + NULL); + return GNUNET_OK; +} + + +void +DONAU_CRYPTO_helper_rsa_poll (struct DONAU_CRYPTO_RsaDonationUnitHelper *dh) +{ + char buf[UINT16_MAX]; + size_t off = 0; + unsigned int retry_limit = 3; + const struct GNUNET_MessageHeader *hdr + = (const struct GNUNET_MessageHeader *) buf; + + if (GNUNET_OK != + try_connect (dh)) + return; /* give up */ + while (1) + { + uint16_t msize; + ssize_t ret; + + ret = recv (dh->sock, + buf + off, + sizeof (buf) - off, + (dh->synced && (0 == off)) + ? MSG_DONTWAIT + : 0); + if (ret < 0) + { + if (EINTR == errno) + continue; + if (EAGAIN == errno) + { + GNUNET_assert (dh->synced); + GNUNET_assert (0 == off); + break; + } + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "recv"); + do_disconnect (dh); + if (0 == retry_limit) + return; /* give up */ + if (GNUNET_OK != + try_connect (dh)) + return; /* give up */ + retry_limit--; + continue; + } + if (0 == ret) + { + GNUNET_break (0 == off); + return; + } + off += ret; +more: + if (off < sizeof (struct GNUNET_MessageHeader)) + continue; + msize = ntohs (hdr->size); + if (off < msize) + continue; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Received message of type %u and length %u\n", + (unsigned int) ntohs (hdr->type), + (unsigned int) msize); + switch (ntohs (hdr->type)) + { + case TALER_HELPER_RSA_MT_AVAIL: + if (GNUNET_OK != + handle_mt_avail (dh, + hdr)) + { + GNUNET_break_op (0); + do_disconnect (dh); + return; + } + break; + case TALER_HELPER_RSA_MT_PURGE: + if (GNUNET_OK != + handle_mt_purge (dh, + hdr)) + { + GNUNET_break_op (0); + do_disconnect (dh); + return; + } + break; + case TALER_HELPER_RSA_SYNCED: + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Now synchronized with RSA helper\n"); + dh->synced = true; + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Received unexpected message of type %d (len: %u)\n", + (unsigned int) ntohs (hdr->type), + (unsigned int) msize); + GNUNET_break_op (0); + do_disconnect (dh); + return; + } + memmove (buf, + &buf[msize], + off - msize); + off -= msize; + goto more; + } +} + + +enum TALER_ErrorCode +DONAU_CRYPTO_helper_rsa_sign ( + struct DONAU_CRYPTO_RsaDonationUnitHelper *dh, + const struct TALER_CRYPTO_RsaSignRequest *rsr, + struct DONAU_BlindedDonationUnitSignature *bs) +{ + enum TALER_ErrorCode ec = TALER_EC_INVALID; + + memset (bs, + 0, + sizeof (*bs)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting signature process\n"); + if (GNUNET_OK != + try_connect (dh)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to connect to helper\n"); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Requesting signature\n"); + { + char buf[sizeof (struct TALER_CRYPTO_SignRequest) + rsr->msg_size]; + struct TALER_CRYPTO_SignRequest *sr + = (struct TALER_CRYPTO_SignRequest *) buf; + + sr->header.size = htons (sizeof (buf)); + sr->header.type = htons (TALER_HELPER_RSA_MT_REQ_SIGN); + sr->reserved = htonl (0); + sr->h_rsa = *rsr->h_rsa; + GNUNET_memcpy (&sr[1], + rsr->msg, + rsr->msg_size); + if (GNUNET_OK != + TALER_crypto_helper_send_all (dh->sock, + buf, + sizeof (buf))) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "send"); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; + } + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Awaiting reply\n"); + { + char buf[UINT16_MAX]; + size_t off = 0; + const struct GNUNET_MessageHeader *hdr + = (const struct GNUNET_MessageHeader *) buf; + bool finished = false; + + while (1) + { + uint16_t msize; + ssize_t ret; + + ret = recv (dh->sock, + &buf[off], + sizeof (buf) - off, + (finished && (0 == off)) + ? MSG_DONTWAIT + : 0); + if (ret < 0) + { + if (EINTR == errno) + continue; + if (EAGAIN == errno) + { + GNUNET_assert (finished); + GNUNET_assert (0 == off); + return ec; + } + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "recv"); + do_disconnect (dh); + ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; + break; + } + if (0 == ret) + { + GNUNET_break (0 == off); + if (! finished) + ec = TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; + return ec; + } + off += ret; +more: + if (off < sizeof (struct GNUNET_MessageHeader)) + continue; + msize = ntohs (hdr->size); + if (off < msize) + continue; + switch (ntohs (hdr->type)) + { + case TALER_HELPER_RSA_MT_RES_SIGNATURE: + if (msize < sizeof (struct TALER_CRYPTO_SignResponse)) + { + GNUNET_break_op (0); + do_disconnect (dh); + ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + goto end; + } + if (finished) + { + GNUNET_break_op (0); + do_disconnect (dh); + ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + goto end; + } + { + const struct TALER_CRYPTO_SignResponse *sr = + (const struct TALER_CRYPTO_SignResponse *) buf; + struct GNUNET_CRYPTO_RsaSignature *rsa_signature; + struct GNUNET_CRYPTO_BlindedSignature *blind_sig; + + rsa_signature = GNUNET_CRYPTO_rsa_signature_decode ( + &sr[1], + msize - sizeof (*sr)); + if (NULL == rsa_signature) + { + GNUNET_break_op (0); + do_disconnect (dh); + ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + goto end; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received signature\n"); + ec = TALER_EC_NONE; + finished = true; + blind_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature); + blind_sig->cipher = GNUNET_CRYPTO_BSA_RSA; + blind_sig->rc = 1; + blind_sig->details.blinded_rsa_signature = rsa_signature; + bs->blinded_sig = blind_sig; + break; + } + case TALER_HELPER_RSA_MT_RES_SIGN_FAILURE: + if (msize != sizeof (struct TALER_CRYPTO_SignFailure)) + { + GNUNET_break_op (0); + do_disconnect (dh); + ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + goto end; + } + { + const struct TALER_CRYPTO_SignFailure *sf = + (const struct TALER_CRYPTO_SignFailure *) buf; + + ec = (enum TALER_ErrorCode) ntohl (sf->ec); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Signing failed!\n"); + finished = true; + break; + } + case TALER_HELPER_RSA_MT_AVAIL: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received new key!\n"); + if (GNUNET_OK != + handle_mt_avail (dh, + hdr)) + { + GNUNET_break_op (0); + do_disconnect (dh); + ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + goto end; + } + break; /* while(1) loop ensures we recvfrom() again */ + case TALER_HELPER_RSA_MT_PURGE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received revocation!\n"); + if (GNUNET_OK != + handle_mt_purge (dh, + hdr)) + { + GNUNET_break_op (0); + do_disconnect (dh); + ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + goto end; + } + break; /* while(1) loop ensures we recvfrom() again */ + case TALER_HELPER_RSA_SYNCED: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Synchronized add odd time with RSA helper!\n"); + dh->synced = true; + break; + default: + GNUNET_break_op (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Received unexpected message of type %u\n", + ntohs (hdr->type)); + do_disconnect (dh); + ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + goto end; + } + memmove (buf, + &buf[msize], + off - msize); + off -= msize; + goto more; + } /* while(1) */ +end: + if (finished) +// DONAU_blinded_donation_unit_sig_free(bs); + return ec; + } +} + + +enum TALER_ErrorCode +DONAU_CRYPTO_helper_rsa_batch_sign ( + struct DONAU_CRYPTO_RsaDonationUnitHelper *dh, + unsigned int rsrs_length, + const struct TALER_CRYPTO_RsaSignRequest rsrs[static rsrs_length], + struct DONAU_BlindedDonationUnitSignature bss[static rsrs_length]) +{ + enum TALER_ErrorCode ec = TALER_EC_INVALID; + unsigned int rpos; + unsigned int rend; + unsigned int wpos; + + memset (bss, + 0, + sizeof (*bss) * rsrs_length); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Starting signature process\n"); + if (GNUNET_OK != + try_connect (dh)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to connect to helper\n"); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Requesting %u signatures\n", + rsrs_length); + rpos = 0; + rend = 0; + wpos = 0; + while (rpos < rsrs_length) + { + unsigned int mlen = sizeof (struct TALER_CRYPTO_BatchSignRequest); + + while ( (rend < rsrs_length) && + (mlen + + sizeof (struct TALER_CRYPTO_SignRequest) + + rsrs[rend].msg_size < UINT16_MAX) ) + { + mlen += sizeof (struct TALER_CRYPTO_SignRequest) + rsrs[rend].msg_size; + rend++; + } + { + char obuf[mlen] GNUNET_ALIGN; + struct TALER_CRYPTO_BatchSignRequest *bsr + = (struct TALER_CRYPTO_BatchSignRequest *) obuf; + void *wbuf; + + bsr->header.type = htons (TALER_HELPER_RSA_MT_REQ_BATCH_SIGN); + bsr->header.size = htons (mlen); + bsr->batch_size = htonl (rend - rpos); + wbuf = &bsr[1]; + for (unsigned int i = rpos; i<rend; i++) + { + struct TALER_CRYPTO_SignRequest *sr = wbuf; + const struct TALER_CRYPTO_RsaSignRequest *rsr = &rsrs[i]; + + sr->header.type = htons (TALER_HELPER_RSA_MT_REQ_SIGN); + sr->header.size = htons (sizeof (*sr) + rsr->msg_size); + sr->reserved = htonl (0); + sr->h_rsa = *rsr->h_rsa; + GNUNET_memcpy (&sr[1], + rsr->msg, + rsr->msg_size); + wbuf += sizeof (*sr) + rsr->msg_size; + } + GNUNET_assert (wbuf == &obuf[mlen]); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending batch request [%u-%u)\n", + rpos, + rend); + if (GNUNET_OK != + TALER_crypto_helper_send_all (dh->sock, + obuf, + sizeof (obuf))) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "send"); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; + } + } + rpos = rend; + { + char buf[UINT16_MAX]; + size_t off = 0; + const struct GNUNET_MessageHeader *hdr + = (const struct GNUNET_MessageHeader *) buf; + bool finished = false; + + while (1) + { + uint16_t msize; + ssize_t ret; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Awaiting reply at %u (up to %u)\n", + wpos, + rend); + ret = recv (dh->sock, + &buf[off], + sizeof (buf) - off, + (finished && (0 == off)) + ? MSG_DONTWAIT + : 0); + if (ret < 0) + { + if (EINTR == errno) + continue; + if (EAGAIN == errno) + { + GNUNET_assert (finished); + GNUNET_assert (0 == off); + break; + } + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "recv"); + do_disconnect (dh); + ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; + break; + } + if (0 == ret) + { + GNUNET_break (0 == off); + if (! finished) + ec = TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; + if (TALER_EC_NONE == ec) + break; + return ec; + } + off += ret; +more: + if (off < sizeof (struct GNUNET_MessageHeader)) + continue; + msize = ntohs (hdr->size); + if (off < msize) + continue; + switch (ntohs (hdr->type)) + { + case TALER_HELPER_RSA_MT_RES_SIGNATURE: + if (msize < sizeof (struct TALER_CRYPTO_SignResponse)) + { + GNUNET_break_op (0); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + if (finished) + { + GNUNET_break_op (0); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + { + const struct TALER_CRYPTO_SignResponse *sr = + (const struct TALER_CRYPTO_SignResponse *) buf; + struct GNUNET_CRYPTO_RsaSignature *rsa_signature; + struct GNUNET_CRYPTO_BlindedSignature *blind_sig; + + rsa_signature = GNUNET_CRYPTO_rsa_signature_decode ( + &sr[1], + msize - sizeof (*sr)); + if (NULL == rsa_signature) + { + GNUNET_break_op (0); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received %u signature\n", + wpos); + blind_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature); + blind_sig->cipher = GNUNET_CRYPTO_BSA_RSA; + blind_sig->rc = 1; + blind_sig->details.blinded_rsa_signature = rsa_signature; + bss[wpos].blinded_sig = blind_sig; + wpos++; + if (wpos == rend) + { + if (TALER_EC_INVALID == ec) + ec = TALER_EC_NONE; + finished = true; + } + break; + } + case TALER_HELPER_RSA_MT_RES_SIGN_FAILURE: + if (msize != sizeof (struct TALER_CRYPTO_SignFailure)) + { + GNUNET_break_op (0); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + { + const struct TALER_CRYPTO_SignFailure *sf = + (const struct TALER_CRYPTO_SignFailure *) buf; + + ec = (enum TALER_ErrorCode) ntohl (sf->ec); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Signing %u failed with status %d!\n", + wpos, + ec); + wpos++; + if (wpos == rend) + { + finished = true; + } + break; + } + case TALER_HELPER_RSA_MT_AVAIL: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received new key!\n"); + if (GNUNET_OK != + handle_mt_avail (dh, + hdr)) + { + GNUNET_break_op (0); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + break; /* while(1) loop ensures we recvfrom() again */ + case TALER_HELPER_RSA_MT_PURGE: + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received revocation!\n"); + if (GNUNET_OK != + handle_mt_purge (dh, + hdr)) + { + GNUNET_break_op (0); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + break; /* while(1) loop ensures we recvfrom() again */ + case TALER_HELPER_RSA_SYNCED: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Synchronized add odd time with RSA helper!\n"); + dh->synced = true; + break; + default: + GNUNET_break_op (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Received unexpected message of type %u\n", + ntohs (hdr->type)); + do_disconnect (dh); + return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + } + memmove (buf, + &buf[msize], + off - msize); + off -= msize; + goto more; + } /* while(1) */ + } /* scope */ + } /* while (rpos < rsrs_length) */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Existing with %u signatures and status %d\n", + wpos, + ec); + return ec; +} + + +void +DONAU_CRYPTO_helper_rsa_revoke ( + struct DONAU_CRYPTO_RsaDonationUnitHelper *dh, + const struct TALER_RsaPubHashP *h_rsa) +{ + struct TALER_CRYPTO_RevokeRequest rr = { + .header.size = htons (sizeof (rr)), + .header.type = htons (TALER_HELPER_RSA_MT_REQ_REVOKE), + .h_rsa = *h_rsa + }; + + if (GNUNET_OK != + try_connect (dh)) + return; /* give up */ + if (GNUNET_OK != + TALER_crypto_helper_send_all (dh->sock, + &rr, + sizeof (rr))) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "send"); + do_disconnect (dh); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Requested revocation of donation unit key %s\n", + GNUNET_h2s (&h_rsa->hash)); +} + + +void +DONAU_CRYPTO_helper_rsa_disconnect ( + struct DONAU_CRYPTO_RsaDonationUnitHelper *dh) +{ + if (-1 != dh->sock) + do_disconnect (dh); + GNUNET_free (dh); +} + + +/* end of crypto_helper_donation_unit.c */