donau

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

commit 9576945c47bc685b4efcd3afd860524d0cf8891a
parent ade143d8dcda67578aa3d8479b5ab45fd69303d7
Author: Pius Loosli <loosp2@bfh.ch>
Date:   Sun, 14 Jan 2024 22:47:47 +0100

[donau] Work on donau /keys

Diffstat:
Msrc/donau/donau-httpd.c | 8+++-----
Msrc/donau/donau-httpd_keys.c | 838+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Msrc/donau/donau-httpd_keys.h | 4++--
3 files changed, 590 insertions(+), 260 deletions(-)

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_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.