donau

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

commit 395fc5e7983a3c6918248bf37ced1f9c7d5d5946
parent 2ef298fb7df19aca497e446077ec7cba63ce5908
Author: Pius Loosli <loosp2@bfh.ch>
Date:   Fri, 12 Jan 2024 11:42:18 +0100

[donau] restore http-keys adaptions

Diffstat:
Msrc/donau/donau-httpd_keys.c | 2985++++++++++++++++++++++---------------------------------------------------------
Msrc/donau/donau-httpd_keys.h | 417+++++++++++++++++--------------------------------------------------------------
2 files changed, 906 insertions(+), 2496 deletions(-)

diff --git a/src/donau/donau-httpd_keys.c b/src/donau/donau-httpd_keys.c @@ -1,13 +1,13 @@ /* This file is part of TALER - Copyright (C) 2024 Taler Systems SA + 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 distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + WARRANTY; without even the implied warranty of CHARITYABILITY 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 @@ -16,20 +16,16 @@ /** * @file donau-httpd_keys.c * @brief management of our various keys - * @author Johannes Casaburi + * @author Christian Grothoff + * @author Özgür Kesim */ #include "taler/platform.h" #include "taler/taler_json_lib.h" #include "taler/taler_mhd_lib.h" -//#include "taler/taler_kyclogic_lib.h" -#include "taler/taler_dbevents.h" #include "donau-httpd.h" -#include "donau-httpd_config.h" #include "donau-httpd_keys.h" -//#include "donau-httpd_responses.h" +#include "donau-httpd_config.h" #include "donaudb_plugin.h" -//#include "taler/taler_extensions.h" - /** * How many /keys request do we hold in suspension at @@ -37,15 +33,155 @@ */ #define SKR_LIMIT 32 - /** * When do we forcefully timeout a /keys request? */ #define KEYS_TIMEOUT GNUNET_TIME_UNIT_MINUTES +/** + * Number of entries in the @e skr_head DLL. + */ +static unsigned int skr_size; + +/** + * Handle to a connection that should be force-resumed + * with a hard error due to @a skr_size hitting + * #SKR_LIMIT. + */ +static struct MHD_Connection *skr_connection; + +/** + * Entry of /keys requests that are currently suspended because we are + * waiting for /keys to become ready. + */ +struct SuspendedKeysRequests +{ + /** + * Kept in a DLL. + */ + struct SuspendedKeysRequests *next; + + /** + * Kept in a DLL. + */ + struct SuspendedKeysRequests *prev; + + /** + * The suspended connection. + */ + struct MHD_Connection *connection; + + /** + * When does this request timeout? + */ + struct GNUNET_TIME_Absolute timeout; +}; + +/** + * Head of DLL of suspended /keys requests. + */ +static struct SuspendedKeysRequests *skr_head; + +/** + * Tail of DLL of suspended /keys requests. + */ +static struct SuspendedKeysRequests *skr_tail; + +/** + * Task to force timeouts on /keys requests. + */ +static struct GNUNET_SCHEDULER_Task *keys_tt; + +/** + * Are we shutting down? + */ +static bool terminating; + +/** + * Function called to forcefully resume suspended keys requests. + * + * @param cls unused, NULL + */ +static void +keys_timeout_cb (void *cls) +{ + struct SuspendedKeysRequests *skr; + + (void) cls; + keys_tt = NULL; + while (NULL != (skr = skr_head)) + { + if (GNUNET_TIME_absolute_is_future (skr->timeout)) + break; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Resuming /keys request due to timeout\n"); + 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, + NULL); +} + + +/** + * Suspend /keys request while we (hopefully) are waiting to be + * provisioned with key material. + * + * @param[in] connection to suspend + */ +static MHD_RESULT +suspend_request (struct MHD_Connection *connection) +{ + struct SuspendedKeysRequests *skr; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Suspending /keys request until key material changes\n"); + if (terminating) + { + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING, + "Exchange terminating"); + } + skr = GNUNET_new (struct SuspendedKeysRequests); + skr->connection = connection; + MHD_suspend_connection (connection); + GNUNET_CONTAINER_DLL_insert (skr_head, + skr_tail, + skr); + skr->timeout = GNUNET_TIME_relative_to_absolute (KEYS_TIMEOUT); + if (NULL == keys_tt) + { + keys_tt = GNUNET_SCHEDULER_add_at (skr->timeout, + &keys_timeout_cb, + NULL); + } + skr_size++; + if (skr_size > SKR_LIMIT) + { + skr = skr_tail; + GNUNET_CONTAINER_DLL_remove (skr_head, + skr_tail, + skr); + skr_size--; + skr_connection = skr->connection; + MHD_resume_connection (skr->connection); + TALER_MHD_daemon_trigger (); + GNUNET_free (skr); + } + return MHD_YES; +} + /** - * Information about a donation_unit on offer by the donation_unit helper. + * Information about a donation unit on offer by the donation unit helper. */ struct HelperDonationUnit { @@ -62,16 +198,11 @@ struct HelperDonationUnit struct GNUNET_TIME_Relative validity_duration; /** - * Hash of the full donation_unit key. + * Hash of the full donation unit key. */ struct DONAU_DonationUnitHashP h_donation_unit_pub; /** - * Signature over this key from the security module's key. - */ - struct TALER_SecurityModuleSignatureP sm_sig; - - /** * The (full) public key. */ struct DONAU_DonationUnitPublicKey donation_unit_pub; @@ -95,134 +226,73 @@ struct HelperDonationUnit } h_details; /** - * Name in configuration section for this donation_unit type. + * Name in configuration section for this donation unit type. */ char *section_name; }; - /** - * Information about a signing key on offer by the esign helper. + * Information about a signing key on offer by the sign helper. */ struct HelperSignkey { /** * When will the helper start to use this key for signing? */ - struct GNUNET_TIME_Timestamp start_time; - - /** - * For how long will the helper allow signing? 0 if - * the key was revoked or purged. - */ - struct GNUNET_TIME_Relative validity_duration; + // struct GNUNET_TIME_Timestamp start_time; + int year; /** * The public key. */ struct DONAU_DonauPublicKeyP donau_pub; - /** - * Signature over this key from the security module's key. - */ - struct TALER_SecurityModuleSignatureP sm_sig; - }; - /** - * State associated with the crypto helpers / security modules. NOT updated - * when the #key_generation is updated (instead constantly kept in sync - * whenever #DH_keys_get_state() is called). + * Counter incremented whenever we have a reason to re-build the keys because + * something external changed. See #DH_keys_get_state() and + * #DH_keys_update_states() for uses of this variable. */ -struct HelperState -{ - - /** - * Handle for the esign/EdDSA helper. - */ - struct TALER_CRYPTO_DonauSignHelper *esh; - - /** - * Handle for the donation_unit/RSA helper. - */ - struct TALER_CRYPTO_RsaDonationUnitHelper *rsadh; - - /** - * Handle for the donation_unit/CS helper. - */ - struct TALER_CRYPTO_CsDonationUnitHelper *csdh; - - /** - * Map from H(donation_unit_pub) to `struct HelperDonationUnit` entries. - */ - struct GNUNET_CONTAINER_MultiHashMap *donation_unit_keys; - - /** - * Map from H(rsa_pub) to `struct HelperDonationUnit` entries. - */ - struct GNUNET_CONTAINER_MultiHashMap *rsa_keys; - - /** - * Map from H(cs_pub) to `struct HelperDonationUnit` entries. - */ - struct GNUNET_CONTAINER_MultiHashMap *cs_keys; - - /** - * Map from `struct DONAU_DonauPublicKey` to `struct HelperSignkey` - * entries. Based on the fact that a `struct GNUNET_PeerIdentity` is also - * an EdDSA public key. - */ - struct GNUNET_CONTAINER_MultiPeerMap *esign_keys; - -}; - +static uint64_t key_generation; /** - * Entry in (sorted) array with possible pre-build responses for /keys. - * We keep pre-build responses for the various (valid) cherry-picking - * values around. + * RSA security module public key, all zero if not known. */ -struct KeysResponseData -{ - - /** - * Response to return if the client supports (deflate) compression. - */ - struct MHD_Response *response_compressed; +// static struct TALER_SecurityModulePublicKeyP donation_unit_rsa_sm_pub; - /** - * Response to return if the client does not support compression. - */ - struct MHD_Response *response_uncompressed; +/** + * CS security module public key, all zero if not known. + */ +// static struct TALER_SecurityModulePublicKeyP donation_unit_cs_sm_pub; - /** - * ETag for these responses. - */ - char *etag; +/** + * EdDSA security module public key, all zero if not known. + */ +// static struct TALER_SecurityModulePublicKeyP esign_sm_pub; - /** - * Cherry-picking timestamp the client must have set for this - * response to be valid. 0 if this is the "full" response. - * The client's request must include this date or a higher one - * for this response to be applicable. - */ - struct GNUNET_TIME_Timestamp cherry_pick_date; -}; +/** + * When do we forcefully timeout a /keys request? + */ +#define KEYS_TIMEOUT GNUNET_TIME_UNIT_MINUTES +/** + * Stores the latest generation of our key state. + */ +static struct DH_KeyStateHandle *key_state; /** - * @brief All information about an exchange online signing key (which is used to - * sign messages from the exchange). + * @brief All information about an donau online signing key (which is used to + * sign messages from the donau). */ struct SigningKey { /** - * The exchange's (online signing) public key. + * The donau's (online signing) public key. */ struct DONAU_DonauPublicKeyP donau_pub; @@ -231,17 +301,16 @@ struct SigningKey */ struct DONAUDB_SignkeyMetaData meta; - }; struct DH_KeyStateHandle { /** - * Mapping from donation_unit keys to donation_unit key issue struct. + * Mapping from donation unit keys to donation unit key issue struct. * Used to lookup the key by hash. */ - struct GNUNET_CONTAINER_MultiHashMap *donation_unitkey_map; + struct GNUNET_CONTAINER_MultiHashMap *denomkey_map; /** * Map from `struct DONAU_DonauPublicKey` to `struct SigningKey` @@ -285,12 +354,6 @@ struct DH_KeyStateHandle struct GNUNET_TIME_Timestamp reload_time; /** - * What is the period at which we rotate keys - * (signing or donation_unit keys)? - */ - struct GNUNET_TIME_Relative rekey_frequency; - - /** * When does our online signing key expire and we * thus need to re-generate this response? */ @@ -304,981 +367,102 @@ struct DH_KeyStateHandle }; - /** - * Entry of /keys requests that are currently suspended because we are - * waiting for /keys to become ready. + * Entry in (sorted) array with possible pre-build responses for /keys. + * We keep pre-build responses for the various (valid) cherry-picking + * values around. */ -struct SuspendedKeysRequests +struct KeysResponseData { + /** - * Kept in a DLL. + * Response to return if the client supports (deflate) compression. */ - struct SuspendedKeysRequests *next; + struct MHD_Response *response_compressed; /** - * Kept in a DLL. + * Response to return if the client does not support compression. */ - struct SuspendedKeysRequests *prev; + struct MHD_Response *response_uncompressed; /** - * The suspended connection. + * ETag for these responses. */ - struct MHD_Connection *connection; + char *etag; /** - * When does this request timeout? + * Cherry-picking timestamp the client must have set for this + * response to be valid. 0 if this is the "full" response. + * The client's request must include this date or a higher one + * for this response to be applicable. */ - struct GNUNET_TIME_Absolute timeout; -}; - - -/** - * Stores the latest generation of our key state. - */ -static struct DH_KeyStateHandle *key_state; - -/** - * Counter incremented whenever we have a reason to re-build the keys because - * something external changed. See #DH_keys_get_state() and - * #DH_keys_update_states() for uses of this variable. - */ -static uint64_t key_generation; - -/** - * Handler listening for wire updates by other exchange - * services. - */ -static struct GNUNET_DB_EventHandler *keys_eh; - -/** - * Head of DLL of suspended /keys requests. - */ -static struct SuspendedKeysRequests *skr_head; - -/** - * Tail of DLL of suspended /keys requests. - */ -static struct SuspendedKeysRequests *skr_tail; - -/** - * Number of entries in the @e skr_head DLL. - */ -static unsigned int skr_size; - -/** - * Handle to a connection that should be force-resumed - * with a hard error due to @a skr_size hitting - * #SKR_LIMIT. - */ -static struct MHD_Connection *skr_connection; - -/** - * Task to force timeouts on /keys requests. - */ -static struct GNUNET_SCHEDULER_Task *keys_tt; - -/** - * For how long should a signing key be legally retained? - * Configuration value. - */ -static struct GNUNET_TIME_Relative signkey_legal_duration; - -/** - * What type of asset are we dealing with here? - */ -static char *asset_type; - -/** - * 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; - -/** - * Are we shutting down? - */ -static bool terminating; - - - -/** - * Function called to forcefully resume suspended keys requests. - * - * @param cls unused, NULL - */ -static void -keys_timeout_cb (void *cls) -{ - struct SuspendedKeysRequests *skr; - - (void) cls; - keys_tt = NULL; - while (NULL != (skr = skr_head)) - { - if (GNUNET_TIME_absolute_is_future (skr->timeout)) - break; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Resuming /keys request due to timeout\n"); - 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, - NULL); -} - - -/** - * Suspend /keys request while we (hopefully) are waiting to be - * provisioned with key material. - * - * @param[in] connection to suspend - */ -static MHD_RESULT -suspend_request (struct MHD_Connection *connection) -{ - struct SuspendedKeysRequests *skr; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Suspending /keys request until key material changes\n"); - if (terminating) - { - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING, - "Donau terminating"); - } - skr = GNUNET_new (struct SuspendedKeysRequests); - skr->connection = connection; - MHD_suspend_connection (connection); - GNUNET_CONTAINER_DLL_insert (skr_head, - skr_tail, - skr); - skr->timeout = GNUNET_TIME_relative_to_absolute (KEYS_TIMEOUT); - if (NULL == keys_tt) - { - keys_tt = GNUNET_SCHEDULER_add_at (skr->timeout, - &keys_timeout_cb, - NULL); - } - skr_size++; - if (skr_size > SKR_LIMIT) - { - skr = skr_tail; - GNUNET_CONTAINER_DLL_remove (skr_head, - skr_tail, - skr); - skr_size--; - skr_connection = skr->connection; - MHD_resume_connection (skr->connection); - TALER_MHD_daemon_trigger (); - GNUNET_free (skr); - } - return MHD_YES; -} + struct GNUNET_TIME_Timestamp cherry_pick_date; +}; /** - * Called on each donation_unit key. Checks that the key still works. - * - * @param cls NULL - * @param hc donation_unit hash (unused) - * @param value a `struct DH_DonationUnitKey` - * @return #GNUNET_OK + * State associated with the crypto helpers / security modules. NOT updated + * when the #key_generation is updated (instead constantly kept in sync + * whenever #DH_keys_get_state() is called). */ -static enum GNUNET_GenericReturnValue -check_dk (void *cls, - const struct GNUNET_HashCode *hc, - void *value) -{ - struct DH_DonationUnitKey *dk = value; - - (void) cls; - (void) hc; - switch (dk->donation_unit_pub.bsign_pub_key->cipher) - { - case GNUNET_CRYPTO_BSA_INVALID: - break; - case GNUNET_CRYPTO_BSA_RSA: - GNUNET_assert (GNUNET_CRYPTO_rsa_public_key_check ( - dk->donation_unit_pub.bsign_pub_key->details.rsa_public_key)); - return GNUNET_OK; - case GNUNET_CRYPTO_BSA_CS: - /* nothing to do for GNUNET_CRYPTO_BSA_CS */ - return GNUNET_OK; - } - GNUNET_assert (0); - return GNUNET_SYSERR; -} - - -void -DH_check_invariants () -{ - struct DH_KeyStateHandle *ksh; - - //if (0 == DH_check_invariants_flag) - // return; - ksh = DH_keys_get_state (); - if (NULL == ksh) - return; - GNUNET_CONTAINER_multihashmap_iterate (ksh->donation_unitkey_map, - &check_dk, - NULL); -} - - -void -DH_resume_keys_requests (bool do_shutdown) +struct HelperState { - 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); - } -} + /** + * Handle for the esign/EdDSA helper. + */ + struct TALER_CRYPTO_ExchangeSignHelper *esh; -/** - * Clear memory for responses to "/keys" in @a ksh. - * - * @param[in,out] ksh key state to update - */ -static void -clear_response_cache (struct DH_KeyStateHandle *ksh) -{ - for (unsigned int i = 0; i<ksh->krd_array_length; i++) - { - struct KeysResponseData *krd = &ksh->krd_array[i]; + /** + * Handle for the donation_unit/RSA helper. + */ + struct TALER_CRYPTO_RsaDenominationHelper *rsadh; - MHD_destroy_response (krd->response_compressed); - MHD_destroy_response (krd->response_uncompressed); - GNUNET_free (krd->etag); - } - GNUNET_array_grow (ksh->krd_array, - ksh->krd_array_length, - 0); -} + /** + * Handle for the donation_unit/CS helper. + */ + struct TALER_CRYPTO_CsDenominationHelper *csdh; + /** + * Map from H(donation_unit_pub) to `struct HelperDenomination` entries. + */ + struct GNUNET_CONTAINER_MultiHashMap *donation_unit_keys; -/** - * 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 ;-) */ - } -} + /** + * Map from H(rsa_pub) to `struct HelperDenomination` entries. + */ + struct GNUNET_CONTAINER_MultiHashMap *rsa_keys; + /** + * Map from H(cs_pub) to `struct HelperDenomination` entries. + */ + struct GNUNET_CONTAINER_MultiHashMap *cs_keys; -/** - * 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; -} - - -/** - * Destroy helper state. Does NOT call free() on @a hs, as that - * state is not separately allocated! Dual to #setup_key_helpers(). - * - * @param[in] hs helper state to free, but NOT the @a hs pointer itself! - */ -static void -destroy_key_helpers (struct HelperState *hs) -{ - 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->donation_unit_keys); - hs->donation_unit_keys = NULL; - GNUNET_CONTAINER_multipeermap_iterate (hs->esign_keys, - &free_esign_cb, - hs); - GNUNET_CONTAINER_multipeermap_destroy (hs->esign_keys); - hs->esign_keys = NULL; - if (NULL != hs->rsadh) - { - TALER_CRYPTO_helper_rsa_disconnect (hs->rsadh); - hs->rsadh = NULL; - } - if (NULL != hs->csdh) - { - TALER_CRYPTO_helper_cs_disconnect (hs->csdh); - hs->csdh = NULL; - } - if (NULL != hs->esh) - { - TALER_CRYPTO_helper_esign_disconnect (hs->esh); - hs->esh = NULL; - } -} - - -/** - * 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 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 @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. - */ -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 donation_unit 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.hash, - 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 - * @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_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; - hd->sm_sig = *sm_sig; - 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 donau_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; - hsk->sm_sig = *sm_sig; - 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 - * @return #GNUNET_OK on success - */ -static enum GNUNET_GenericReturnValue -setup_key_helpers (struct HelperState *hs) -{ - hs->donation_unit_keys - = GNUNET_CONTAINER_multihashmap_create (1024, - GNUNET_YES); - hs->rsa_keys - = GNUNET_CONTAINER_multihashmap_create (1024, - GNUNET_YES); - hs->cs_keys - = GNUNET_CONTAINER_multihashmap_create (1024, - GNUNET_YES); - hs->esign_keys - = GNUNET_CONTAINER_multipeermap_create (32, - GNUNET_NO /* MUST BE NO! */); - hs->rsadh = TALER_CRYPTO_helper_rsa_connect (DH_cfg, - "taler", - &helper_rsa_cb, - hs); - if (NULL == hs->rsadh) - { - destroy_key_helpers (hs); - return GNUNET_SYSERR; - } - hs->csdh = TALER_CRYPTO_helper_cs_connect (DH_cfg, - "taler", - &helper_cs_cb, - hs); - if (NULL == hs->csdh) - { - destroy_key_helpers (hs); - return GNUNET_SYSERR; - } - hs->esh = TALER_CRYPTO_helper_esign_connect (DH_cfg, - "taler", - &helper_esign_cb, - hs); - if (NULL == hs->esh) - { - destroy_key_helpers (hs); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Synchronize helper state. Polls the key helper for updates. - * - * @param[in,out] hs helper state to synchronize - */ -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); -} - - -/** - * Free donation_unit key data. - * - * @param cls a `struct DH_KeyStateHandle`, unused - * @param h_donation_unit_pub hash of the donation_unit public key, unused - * @param value a `struct DH_DonationUnitKey` to free - * @return #GNUNET_OK (continue to iterate) - */ -static enum GNUNET_GenericReturnValue -clear_donation_unit_cb (void *cls, - const struct GNUNET_HashCode *h_donation_unit_pub, - void *value) -{ - struct DH_DonationUnitKey *dk = value; - - (void) cls; - (void) h_donation_unit_pub; - //DONAU_donation_unit_pub_free (&dk->donation_unit_pub); - - GNUNET_free (dk); - return GNUNET_OK; -} - - -/** - * Free donation_unit key data. - * - * @param cls a `struct DH_KeyStateHandle`, unused - * @param pid the online signing key (type-disguised), unused - * @param value a `struct SigningKey` to free - * @return #GNUNET_OK (continue to iterate) - */ -static enum GNUNET_GenericReturnValue -clear_signkey_cb (void *cls, - const struct GNUNET_PeerIdentity *pid, - void *value) -{ - struct SigningKey *sk = value; - - (void) cls; - (void) pid; - GNUNET_free (sk); - return GNUNET_OK; -} - - -/** - * Free resources associated with @a cls, possibly excluding - * the helper data. - * - * @param[in] ksh key state to release - * @param free_helper true to also release the helper state - */ -static void -destroy_key_state (struct DH_KeyStateHandle *ksh, - bool free_helper) -{ - - clear_response_cache (ksh); - - GNUNET_CONTAINER_multihashmap_iterate (ksh->donation_unitkey_map, - &clear_donation_unit_cb, - ksh); - GNUNET_CONTAINER_multihashmap_destroy (ksh->donation_unitkey_map); - GNUNET_CONTAINER_multipeermap_iterate (ksh->signkey_map, - &clear_signkey_cb, - ksh); - GNUNET_CONTAINER_multipeermap_destroy (ksh->signkey_map); - if (free_helper) - { - destroy_key_helpers (ksh->helpers); - GNUNET_free (ksh->helpers); - } - if (NULL != ksh->management_keys_reply) - { - json_decref (ksh->management_keys_reply); - ksh->management_keys_reply = NULL; - } - GNUNET_free (ksh); -} - - -/** - * Function called whenever another exchange process has updated - * the keys data in the database. - * - * @param cls NULL - * @param extra unused - * @param extra_size number of bytes in @a extra unused - */ -static void -keys_update_event_cb (void *cls, - const void *extra, - size_t extra_size) -{ - (void) cls; - (void) extra; - (void) extra_size; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Received /keys update event\n"); - DH_check_invariants (); - key_generation++; - DH_resume_keys_requests (false); - DH_check_invariants (); -} - - -enum GNUNET_GenericReturnValue -DH_keys_init () -{ - struct GNUNET_DB_EventHeaderP es = { - .size = htons (sizeof (es)), - .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED), - }; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (DH_cfg, - "exchange", - "SIGNKEY_LEGAL_DURATION", - &signkey_legal_duration)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", - "SIGNKEY_LEGAL_DURATION"); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (DH_cfg, - "exchange", - "ASSET_TYPE", - &asset_type)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - "exchange", - "ASSET_TYPE"); - asset_type = GNUNET_strdup ("fiat"); - } - keys_eh = DH_plugin->event_listen (DH_plugin->cls, - GNUNET_TIME_UNIT_FOREVER_REL, - &es, - &keys_update_event_cb, - NULL); - if (NULL == keys_eh) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Fully clean up our state. - */ -void -DH_keys_finished () -{ - if (NULL != keys_tt) - { - GNUNET_SCHEDULER_cancel (keys_tt); - keys_tt = NULL; - } - if (NULL != key_state) - destroy_key_state (key_state, - true); - if (NULL != keys_eh) - { - DH_plugin->event_listen_cancel (DH_plugin->cls, - keys_eh); - keys_eh = NULL; - } -} - - -/** - * Function called with information about the exchange's donation_unit keys. - * - * @param cls closure with a `struct DH_KeyStateHandle *` - * @param donation_unit_pub public key of the donation_unit - * @param h_donation_unit_pub hash of @a donation_unit_pub - * @param meta meta data information about the donation_unit type (value, expirations, fees) - * coins of this donation_unit - */ -static void -donation_unit_info_cb ( - void *cls, - const struct DONAU_DonationUnitPublicKey *donation_unit_pub, - const struct DONAU_DonationUnitHashP *h_donation_unit_pub, - const struct DONAUDB_DonationUnitKeyMetaData *meta) -{ - struct DH_KeyStateHandle *ksh = cls; - struct DH_DonationUnitKey *dk; - - GNUNET_assert (GNUNET_CRYPTO_BSA_INVALID != - donation_unit_pub->bsign_pub_key->cipher); - //if (GNUNET_TIME_absolute_is_zero (meta->start.abs_time) || - // GNUNET_TIME_absolute_is_zero (meta->expire_withdraw.abs_time) || - // GNUNET_TIME_absolute_is_zero (meta->expire_deposit.abs_time) || - // GNUNET_TIME_absolute_is_zero (meta->expire_legal.abs_time) ) - //{ - // GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - // "Database contains invalid donation_unit key %s\n", - // GNUNET_h2s (&h_donation_unit_pub->hash)); - // return; - //} - dk = GNUNET_new (struct DH_DonationUnitKey); - DONAU_donation_unit_pub_deep_copy (&dk->donation_unit_pub, - donation_unit_pub); - dk->h_donation_unit_pub = *h_donation_unit_pub; - //dk->meta = *meta; - - GNUNET_assert ( - GNUNET_OK == - GNUNET_CONTAINER_multihashmap_put (ksh->donation_unitkey_map, - &dk->h_donation_unit_pub.hash, - dk, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); -} + /** + * Map from `struct TALER_ExchangePublicKey` to `struct HelperSignkey` + * entries. Based on the fact that a `struct GNUNET_PeerIdentity` is also + * an EdDSA public key. + */ + struct GNUNET_CONTAINER_MultiPeerMap *esign_keys; +}; /** - * Function called with information about the exchange's online signing keys. - * - * @param cls closure with a `struct DH_KeyStateHandle *` - * @param donau_pub the public key - * @param meta meta data information about the donation_unit type (expirations) + * Closure for #add_donation_unit_key_cb. */ -static void -signkey_info_cb ( - void *cls, - const struct DONAU_DonauPublicKeyP *donau_pub, - const struct DONAUDB_SignkeyMetaData *meta) +struct DonationUnitKeyCtx { - struct DH_KeyStateHandle *ksh = cls; - struct SigningKey *sk; - struct GNUNET_PeerIdentity pid; - - sk = GNUNET_new (struct SigningKey); - sk->donau_pub = *donau_pub; - sk->meta = *meta; - pid.public_key = donau_pub->eddsa_pub; - GNUNET_assert ( - GNUNET_OK == - GNUNET_CONTAINER_multipeermap_put (ksh->signkey_map, - &pid, - sk, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); -} + /** + * Heap for sorting active donation unit keys by start time. + */ + struct GNUNET_CONTAINER_Heap *heap; + /** + * What is the minimum key rotation frequency of + * valid donation unit keys? + */ + struct GNUNET_TIME_Relative min_dk_frequency; +}; /** * Closure for #add_sign_key_cb. @@ -1296,7 +480,6 @@ struct SignKeyCtx json_t *signkeys; }; - /** * Function called for all signing keys, used to build up the * respective JSON response. @@ -1315,91 +498,29 @@ add_sign_key_cb (void *cls, struct SigningKey *sk = value; (void) pid; - //if (GNUNET_TIME_absolute_is_future (sk->meta.expire_sign.abs_time)) - //{ + // if (GNUNET_TIME_absolute_is_future (sk->meta.expire_sign.abs_time)) + // { // ctx->min_sk_frequency = // GNUNET_TIME_relative_min (ctx->min_sk_frequency, // GNUNET_TIME_absolute_get_difference ( // 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 ("key", - // &sk->donau_pub)))); - return GNUNET_OK; -} - - -/** - * Closure for #add_donation_unit_key_cb. - */ -struct DenomKeyCtx -{ - /** - * Heap for sorting active donation_unit keys by start time. - */ - struct GNUNET_CONTAINER_Heap *heap; - - /** - * What is the minimum key rotation frequency of - * valid donation_unit keys? - */ - struct GNUNET_TIME_Relative min_dk_frequency; -}; - - -/** - * Function called for all donation_unit keys, used to build up the - * JSON list of *revoked* donation_unit keys and the - * heap of non-revoked donation_unit keys by timeout. - * - * @param cls a `struct DenomKeyCtx` - * @param h_donation_unit_pub hash of the donation_unit key - * @param value a `struct DH_DonationUnitKey` - * @return #GNUNET_OK (continue to iterate) - */ -static enum GNUNET_GenericReturnValue -add_donation_unit_key_cb (void *cls, - const struct GNUNET_HashCode *h_donation_unit_pub, - void *value) -{ - struct DenomKeyCtx *dkc = cls; - struct DH_DonationUnitKey *dk = value; - - //if (dk->recoup_possible) - //{ - // GNUNET_assert ( - // 0 == - // json_array_append_new ( - // dkc->recoup, - // GNUNET_JSON_PACK ( - // GNUNET_JSON_pack_data_auto ("h_donation_unit_pub", - // h_donation_unit_pub)))); - //} - //else - //{ - // if (GNUNET_TIME_absolute_is_future (dk->meta.start.abs_time)) - // { - // dkc->min_dk_frequency = - // GNUNET_TIME_relative_min (dkc->min_dk_frequency, - // GNUNET_TIME_absolute_get_difference ( - // dk->meta.start.abs_time, - // dk->meta.expire_withdraw.abs_time)); - // } - // (void) GNUNET_CONTAINER_heap_insert (dkc->heap, - // dk, - // dk->meta.start.abs_time.abs_value_us); - //} + // } + 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; } @@ -1428,7 +549,6 @@ setup_general_response_headers (void *cls, 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, @@ -1443,379 +563,311 @@ setup_general_response_headers (void *cls, /** - * Element in the `struct SignatureContext` array. + * Update the "/keys" responses in @a ksh, computing the detailed replies. + * + * This function is to recompute all (including cherry-picked) responses we + * might want to return, based on the state already in @a ksh. + * + * @param[in,out] ksh state handle to update + * @return #GNUNET_OK on success */ -struct SignatureElement +static enum GNUNET_GenericReturnValue +finish_keys_response (struct DH_KeyStateHandle *ksh) { + enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR; + json_t *recoup; + struct SignKeyCtx sctx; + json_t *grouped_donation_units = NULL; + struct GNUNET_TIME_Timestamp last_cherry_pick_date; + struct GNUNET_CONTAINER_Heap *heap; + struct GNUNET_HashContext *hash_context = NULL; + // struct GNUNET_HashCode grouped_hash_xor = {0}; - /** - * Offset of the donation_unit in the group array, - * for sorting (2nd rank, ascending). - */ - unsigned int offset; + 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, + &sctx); + recoup = json_array (); + GNUNET_assert (NULL != recoup); + heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX); + { + // struct DonationUnitKeyCtx dkc = { + // .heap = heap, + // .min_dk_frequency = GNUNET_TIME_UNIT_FOREVER_REL, + // }; + + // GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map, + // &add_denom_key_cb, + // &dkc); + // ksh->rekey_frequency + // = GNUNET_TIME_relative_min (dkc.min_dk_frequency, + // sctx.min_sk_frequency); + } - /** - * Offset of the group in the donation_units array, - * for sorting (2nd rank, ascending). - */ - unsigned int group_offset; + hash_context = GNUNET_CRYPTO_hash_context_start (); -}; + grouped_donation_units = json_array (); + GNUNET_assert (NULL != grouped_donation_units); -/** - * Context for collecting the array of master signatures - * needed to verify the donau_sig online signature. - */ -struct SignatureContext -{ - /** - * Array of signatures to hash over. - */ - struct SignatureElement *elements; + last_cherry_pick_date = GNUNET_TIME_UNIT_ZERO_TS; - /** - * Write offset in the @e elements array. - */ - unsigned int elements_pos; + GNUNET_CONTAINER_heap_destroy (heap); + if (! GNUNET_TIME_absolute_is_zero (last_cherry_pick_date.abs_time)) + { + struct GNUNET_HashCode hc; - /** - * Allocated space for @e elements. - */ - unsigned int elements_size; -}; + 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_hash_xor)) + // { + // GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + // "Failed to generate key response data for %s\n", + // GNUNET_TIME_timestamp2s (last_cherry_pick_date)); + // goto CLEANUP; + // } + ksh->management_only = false; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "No donation unit keys available. Refusing to generate /keys response.\n"); + GNUNET_CRYPTO_hash_context_abort (hash_context); + } + + ret = GNUNET_OK; + +// CLEANUP: + json_decref (grouped_donation_units); + json_decref (sctx.signkeys); + json_decref (recoup); + return ret; +} /** - * Determine order to sort two elements by before - * we hash the master signatures. Used for - * sorting with qsort(). + * Free donation unit key data. * - * @param a pointer to a `struct SignatureElement` - * @param b pointer to a `struct SignatureElement` - * @return 0 if equal, -1 if a < b, 1 if a > b. + * @param cls a `struct DH_KeyStateHandle`, unused + * @param h_donation_unit_pub hash of the donation unit public key, unused + * @param value a `struct DH_DonationUnitKey` to free + * @return #GNUNET_OK (continue to iterate) */ -static int -signature_context_sort_cb (const void *a, - const void *b) +static enum GNUNET_GenericReturnValue +clear_donation_unit_cb (void *cls, + const struct GNUNET_HashCode *h_donation_unit_pub, + void *value) { - const struct SignatureElement *sa = a; - const struct SignatureElement *sb = b; + struct DH_DonationUnitKey *dk = value; - if (sa->group_offset < sb->group_offset) - return -1; - if (sa->group_offset > sb->group_offset) - return 1; - if (sa->offset < sb->offset) - return -1; - if (sa->offset > sb->offset) - return 1; - /* We should never have two disjoint elements - with same time and offset */ - GNUNET_assert (sa == sb); - return 0; + (void) cls; + (void) h_donation_unit_pub; + // TALER_denom_pub_free (&dk->denom_pub); + GNUNET_free (dk); + return GNUNET_OK; } /** - *GroupData is the value we store for each group meta-data */ -struct GroupData + * Free donation unit key data. + * + * @param cls a `struct DH_KeyStateHandle`, unused + * @param pid the online signing key (type-disguised), unused + * @param value a `struct SigningKey` to free + * @return #GNUNET_OK (continue to iterate) + */ +static enum GNUNET_GenericReturnValue +clear_signkey_cb (void *cls, + const struct GNUNET_PeerIdentity *pid, + void *value) { - /** - * The json blob with the group meta-data and list of donation_units - */ - json_t *json; - - /** - * List of donation_units for the group, - * included in @e json, do not free separately! - */ - json_t *list; - - /** - * Offset of the group in the final array. - */ - unsigned int group_off; + struct SigningKey *sk = value; -}; + (void) cls; + (void) pid; + GNUNET_free (sk); + return GNUNET_OK; +} /** - * Helper function called to clean up the group data - * in the donation_units_by_group below. + * Clear memory for responses to "/keys" in @a ksh. * - * @param cls unused - * @param key unused - * @param value a `struct GroupData` to free - * @return #GNUNET_OK + * @param[in,out] ksh key state to update */ -static int -free_group (void *cls, - const struct GNUNET_HashCode *key, - void *value) +static void +clear_response_cache (struct DH_KeyStateHandle *ksh) { - struct GroupData *gd = value; + for (unsigned int i = 0; i<ksh->krd_array_length; i++) + { + struct KeysResponseData *krd = &ksh->krd_array[i]; - (void) cls; - (void) key; - GNUNET_free (gd); - return GNUNET_OK; + MHD_destroy_response (krd->response_compressed); + MHD_destroy_response (krd->response_uncompressed); + GNUNET_free (krd->etag); + } + GNUNET_array_grow (ksh->krd_array, + ksh->krd_array_length, + 0); } /** - * Update the "/keys" responses in @a ksh, computing the detailed replies. - * - * This function is to recompute all (including cherry-picked) responses we - * might want to return, based on the state already in @a ksh. + * Synchronize helper state. Polls the key helper for updates. * - * @param[in,out] ksh state handle to update - * @return #GNUNET_OK on success + * @param[in,out] hs helper state to synchronize */ -static enum GNUNET_GenericReturnValue -finish_keys_response (struct DH_KeyStateHandle *ksh) +static void +sync_key_helpers (struct HelperState *hs) { - enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR; - struct SignKeyCtx sctx = { - .min_sk_frequency = GNUNET_TIME_UNIT_FOREVER_REL - }; - json_t *grouped_donation_units = NULL; - struct GNUNET_TIME_Timestamp last_cherry_pick_date; - struct GNUNET_CONTAINER_Heap *heap; - struct SignatureContext sig_ctx = { 0 }; + TALER_CRYPTO_helper_rsa_poll (hs->rsadh); + TALER_CRYPTO_helper_cs_poll (hs->csdh); + TALER_CRYPTO_helper_esign_poll (hs->esh); +} - sctx.signkeys = json_array (); - GNUNET_assert (NULL != sctx.signkeys); - grouped_donation_units = json_array (); - GNUNET_assert (NULL != grouped_donation_units); - GNUNET_CONTAINER_multipeermap_iterate (ksh->signkey_map, - &add_sign_key_cb, - &sctx); - if (0 == json_array_size (sctx.signkeys)) +/** + * Destroy helper state. Does NOT call free() on @a hs, as that + * state is not separately allocated! Dual to #setup_key_helpers(). + * + * @param[in] hs helper state to free, but NOT the @a hs pointer itself! + */ +static void +destroy_key_helpers (struct HelperState *hs) +{ + // GNUNET_CONTAINER_multihashmap_iterate (hs->denom_keys, + // &free_denom_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_multipeermap_iterate (hs->esign_keys, + // &free_esign_cb, + // hs); + // GNUNET_CONTAINER_multipeermap_destroy (hs->esign_keys); + hs->esign_keys = NULL; + if (NULL != hs->rsadh) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "No online signing keys available. Refusing to generate /keys response.\n"); - ret = GNUNET_NO; - goto CLEANUP; + TALER_CRYPTO_helper_rsa_disconnect (hs->rsadh); + hs->rsadh = NULL; } - heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MAX); + if (NULL != hs->csdh) { - struct DenomKeyCtx dkc = { - .heap = heap, - .min_dk_frequency = GNUNET_TIME_UNIT_FOREVER_REL, - }; - - GNUNET_CONTAINER_multihashmap_iterate (ksh->donation_unitkey_map, - &add_donation_unit_key_cb, - &dkc); - ksh->rekey_frequency - = GNUNET_TIME_relative_min (dkc.min_dk_frequency, - sctx.min_sk_frequency); + TALER_CRYPTO_helper_cs_disconnect (hs->csdh); + hs->csdh = NULL; } - - last_cherry_pick_date = GNUNET_TIME_UNIT_ZERO_TS; - + if (NULL != hs->esh) { - struct DH_DonationUnitKey *dk; - struct GNUNET_CONTAINER_MultiHashMap *donation_units_by_group; - - donation_units_by_group = - GNUNET_CONTAINER_multihashmap_create (1024, - GNUNET_NO /* NO, because keys are only on the stack */); - /* heap = max heap, sorted by start time */ - while (NULL != (dk = GNUNET_CONTAINER_heap_remove_root (heap))) - { - //if (GNUNET_TIME_timestamp_cmp (last_cherry_pick_date, - // !=, - // dk->meta.start) && - // (! GNUNET_TIME_absolute_is_zero (last_cherry_pick_date.abs_time)) ) - //{ - // /* - // * This is not the first entry in the heap (because last_cherry_pick_date != - // * GNUNET_TIME_UNIT_ZERO_TS) and the previous entry had a different - // * start time. Therefore, we create a new entry in ksh. - // */ - // struct GNUNET_HashCode hc; -// - // if (GNUNET_OK != - // create_krd (ksh, - // &hc, - // last_cherry_pick_date, - // sctx.signkeys, - // recoup, - // grouped_donation_units)) - // { - // GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - // "Failed to generate key response data for %s\n", - // GNUNET_TIME_timestamp2s (last_cherry_pick_date)); - // /* drain heap before destroying it */ - // while (NULL != (dk = GNUNET_CONTAINER_heap_remove_root (heap))) - // /* intentionally empty */; - // GNUNET_CONTAINER_heap_destroy (heap); - // goto CLEANUP; - // } - //} - - //last_cherry_pick_date = dk->meta.start; - /* - * Group the donation_units by {cipher, value, fees, age_mask}. - * - * For each group we save the group meta-data and the list of - * donation_units in this group as a json-blob in the multihashmap - * donation_units_by_group. - */ - { - struct GroupData *group; - json_t *entry; - struct GNUNET_HashCode key; - struct DONAU_DonationUnitGroup meta = { - .cipher = dk->donation_unit_pub.bsign_pub_key->cipher, - // .value = dk->meta.value, - }; - - /* Search the group/JSON-blob for the key */ - //DONAU_donation_unit_group_get_key (&meta, - // &key); - group = GNUNET_CONTAINER_multihashmap_get ( - donation_units_by_group, - &key); - if (NULL == group) - { - /* There is no group for this meta-data yet, so we create a new group */ - const char *cipher; - - group = GNUNET_new (struct GroupData); - - /* Create a new array for the donation_units in this group */ - group->list = json_array (); - GNUNET_assert (NULL != group->list); - group->json = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("cipher", - cipher), - GNUNET_JSON_pack_array_steal ("donation_units", - group->list)); - //DONAU_JSON_pack_amount ("value", - // &meta.value)); - GNUNET_assert (NULL != group->json); - - group->group_off - = json_array_size (grouped_donation_units); - GNUNET_assert (0 == - json_array_append_new ( - grouped_donation_units, - group->json)); - GNUNET_assert ( - GNUNET_OK == - GNUNET_CONTAINER_multihashmap_put (donation_units_by_group, - &key, - group, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); - } - - /* Now that we have found/created the right group, add the - donation_unit to the list */ - { - struct HelperDonationUnit *hd; - struct GNUNET_JSON_PackSpec key_spec; - bool private_key_lost; - - hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->donation_unit_keys, - &dk->h_donation_unit_pub.hash); - private_key_lost - = (NULL == hd) || - GNUNET_TIME_absolute_is_past ( - GNUNET_TIME_absolute_add ( - hd->start_time.abs_time, - hd->validity_duration)); - //switch (meta.cipher) - //{ - //case GNUNET_CRYPTO_BSA_RSA: - // key_spec = - // GNUNET_JSON_pack_rsa_public_key ( - // "rsa_pub", - // dk->donation_unit_pub.bsign_pub_key->details.rsa_public_key); - // break; - //case GNUNET_CRYPTO_BSA_CS: - // key_spec = - // GNUNET_JSON_pack_data_varsize ( - // "cs_pub", - // &dk->donation_unit_pub.bsign_pub_key->details.cs_public_key, - // sizeof (dk->donation_unit_pub.bsign_pub_key->details.cs_public_key)); - // break; - //default: - // GNUNET_assert (false); - //} - - entry = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_allow_null ( - private_key_lost - ? GNUNET_JSON_pack_bool ("lost", - true) - : GNUNET_JSON_pack_string ("dummy", - NULL)), - //GNUNET_JSON_pack_timestamp ("stamp_start", - // dk->meta.start), - //GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw", - // dk->meta.expire_withdraw), - //GNUNET_JSON_pack_timestamp ("stamp_expire_deposit", - // dk->meta.expire_deposit), - //GNUNET_JSON_pack_timestamp ("stamp_expire_legal", - // dk->meta.expire_legal), - key_spec - ); - GNUNET_assert (NULL != entry); - } - - /* Finally, add the donation_unit to the list of donation_units in this - group */ - GNUNET_assert (json_is_array (group->list)); - GNUNET_assert (0 == - json_array_append_new (group->list, - entry)); - } - } /* loop over heap ends */ - - GNUNET_CONTAINER_multihashmap_iterate (donation_units_by_group, - &free_group, - NULL); - GNUNET_CONTAINER_multihashmap_destroy (donation_units_by_group); + TALER_CRYPTO_helper_esign_disconnect (hs->esh); + hs->esh = NULL; } - GNUNET_CONTAINER_heap_destroy (heap); +} - if (! GNUNET_TIME_absolute_is_zero (last_cherry_pick_date.abs_time)) - { - struct GNUNET_HashCode hc; - //if (GNUNET_OK != - // create_krd (ksh, - // &hc, - // last_cherry_pick_date, - // sctx.signkeys, - // grouped_donation_units)) - //{ - // GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - // "Failed to generate key response data for %s\n", - // GNUNET_TIME_timestamp2s (last_cherry_pick_date)); - // goto CLEANUP; - //} - ksh->management_only = false; +/** + * Free resources associated with @a cls, possibly excluding + * the helper data. + * + * @param[in] ksh key state to release + * @param free_helper true to also release the helper state + */ +static void +destroy_key_state (struct DH_KeyStateHandle *ksh, + bool free_helper) +{ + // struct DH_GlobalFee *gf; + clear_response_cache (ksh); + // while (NULL != (gf = ksh->gf_head)) + // { + // GNUNET_CONTAINER_DLL_remove (ksh->gf_head, + // ksh->gf_tail, + // 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, + ksh); + GNUNET_CONTAINER_multipeermap_destroy (ksh->signkey_map); + // json_decref (ksh->auditors); + // ksh->auditors = NULL; + // json_decref (ksh->global_fees); + // ksh->global_fees = NULL; + if (free_helper) + { + destroy_key_helpers (ksh->helpers); + GNUNET_free (ksh->helpers); } - else + if (NULL != ksh->management_keys_reply) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "No donation_unit keys available. Refusing to generate /keys response.\n"); + json_decref (ksh->management_keys_reply); + ksh->management_keys_reply = NULL; } - ret = GNUNET_OK; + GNUNET_free (ksh); +} -CLEANUP: - GNUNET_array_grow (sig_ctx.elements, - sig_ctx.elements_size, - 0); - json_decref (grouped_donation_units); - if (NULL != sctx.signkeys) - json_decref (sctx.signkeys); - return ret; + +/** + * Setup helper state. + * + * @param[out] hs helper state to initialize + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +setup_key_helpers (struct HelperState *hs) +{ + // hs->denom_keys + // = GNUNET_CONTAINER_multihashmap_create (1024, + // GNUNET_YES); + hs->rsa_keys + = GNUNET_CONTAINER_multihashmap_create (1024, + GNUNET_YES); + hs->cs_keys + = GNUNET_CONTAINER_multihashmap_create (1024, + GNUNET_YES); + 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; + // } + return GNUNET_OK; } @@ -1828,11 +880,11 @@ CLEANUP: * @return NULL on error (i.e. failed to access database) */ static struct DH_KeyStateHandle * -build_key_state (struct HelperState *hs, - bool management_only) +build_key_state (struct HelperState *hs /*, + bool management_only*/) { 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; @@ -1855,48 +907,56 @@ build_key_state (struct HelperState *hs, { ksh->helpers = hs; } - ksh->donation_unitkey_map = GNUNET_CONTAINER_multihashmap_create (1024, + ksh->denomkey_map = GNUNET_CONTAINER_multihashmap_create (1024, true); ksh->signkey_map = GNUNET_CONTAINER_multipeermap_create (32, - false /* MUST be false! */); + 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)); - - //qs = DH_plugin->iterate_donation_units (DH_plugin->cls, - // &donation_unit_info_cb, - // ksh); - //if (qs < 0) - //{ + // 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; - //} - ///* 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) - //{ + // } + /* 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 (management_only) + // { + // ksh->management_only = true; + // return ksh; + // } if (GNUNET_OK != finish_keys_response (ksh)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Could not finish /keys response (required data not configured yet)\n"); + "Could not finish /keys response (likely no signing keys available yet)\n"); destroy_key_state (ksh, true); return NULL; @@ -1911,29 +971,28 @@ DH_keys_update_states () { struct GNUNET_DB_EventHeaderP es = { .size = htons (sizeof (es)), - .type = htons (TALER_DBEVENT_EXCHANGE_KEYS_UPDATED), + // .type = htons (TALER_DBEVENT_DONAU_KEYS_UPDATED), }; DH_plugin->event_notify (DH_plugin->cls, - &es, - NULL, - 0); + &es, + NULL, + 0); key_generation++; - DH_resume_keys_requests (false); + // DH_resume_keys_requests (false); } static struct DH_KeyStateHandle * -keys_get_state (bool management_only) +DH_keys_get_state (/*bool management_only*/) { struct DH_KeyStateHandle *old_ksh; struct DH_KeyStateHandle *ksh; - old_ksh = key_state; if (NULL == old_ksh) { - ksh = build_key_state (NULL, - management_only); + ksh = build_key_state (NULL /*, management_only*/); + ksh = NULL; if (NULL == ksh) return NULL; key_state = ksh; @@ -1946,8 +1005,8 @@ keys_get_state (bool management_only) "Rebuilding /keys, generation upgrade from %llu to %llu\n", (unsigned long long) old_ksh->key_generation, (unsigned long long) key_generation); - ksh = build_key_state (old_ksh->helpers, - management_only); + ksh = build_key_state (old_ksh->helpers /*, + management_only*/); key_state = ksh; old_ksh->helpers = NULL; destroy_key_state (old_ksh, @@ -1959,578 +1018,8 @@ keys_get_state (bool management_only) } -struct DH_KeyStateHandle * -DH_keys_get_state_for_management_only (void) -{ - return keys_get_state (true); -} - - -struct DH_KeyStateHandle * -DH_keys_get_state (void) -{ - struct DH_KeyStateHandle *ksh; - - ksh = keys_get_state (false); - if (NULL == ksh) - return NULL; - - if (ksh->management_only) - { - if (GNUNET_OK != - finish_keys_response (ksh)) - return NULL; - } - - return ksh; -} - - -struct DH_DonationUnitKey * -DH_keys_donation_unit_by_hash ( - const struct DONAU_DonationUnitHashP *h_donation_unit_pub, - struct MHD_Connection *conn, - MHD_RESULT *mret) -{ - struct DH_KeyStateHandle *ksh; - - ksh = DH_keys_get_state (); - if (NULL == ksh) - { - *mret = TALER_MHD_reply_with_error (conn, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING, - NULL); - return NULL; - } - - return DH_keys_donation_unit_by_hash_from_state (ksh, - h_donation_unit_pub, - conn, - mret); -} - - -struct DH_DonationUnitKey * -DH_keys_donation_unit_by_hash_from_state ( - const struct DH_KeyStateHandle *ksh, - const struct DONAU_DonationUnitHashP *h_donation_unit_pub, - struct MHD_Connection *conn, - MHD_RESULT *mret) -{ - struct DH_DonationUnitKey *dk; - - dk = GNUNET_CONTAINER_multihashmap_get (ksh->donation_unitkey_map, - &h_donation_unit_pub->hash); - if (NULL == dk) - { - if (NULL == conn) - return NULL; - //*mret = DH_RESPONSE_reply_unknown_donation_unit_pub_hash (conn, - // h_donation_unit_pub); - //return NULL; - } - return dk; -} - - -enum TALER_ErrorCode -DH_keys_donation_unit_batch_sign ( - unsigned int csds_length, - const struct DH_CoinSignData csds[static csds_length], - struct DONAU_BlindedDonationUnitSignature bss[static csds_length]) -{ - struct DH_KeyStateHandle *ksh; - struct HelperDonationUnit *hd; - struct TALER_CRYPTO_RsaSignRequest rsrs[csds_length]; - struct TALER_CRYPTO_CsSignRequest csrs[csds_length]; - struct DONAU_BlindedDonationUnitSignature rs[csds_length]; - struct DONAU_BlindedDonationUnitSignature cs[csds_length]; - unsigned int rsrs_pos = 0; - unsigned int csrs_pos = 0; - enum TALER_ErrorCode ec; - - ksh = DH_keys_get_state (); - if (NULL == ksh) - return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING; - for (unsigned int i = 0; i<csds_length; i++) - { - const struct DONAU_DonationUnitHashP *h_donation_unit_pub = csds[i].h_donation_unit_pub; - const struct DONAU_BlindedDonationUnit *bp = csds[i].bp; - - hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->donation_unit_keys, - &h_donation_unit_pub->hash); - if (NULL == hd) - return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN; - //if (bp->blinded_message->cipher != - // hd->donation_unit_pub.bsign_pub_key->cipher) - // return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; - //switch (hd->donation_unit_pub.bsign_pub_key->cipher) - //{ - //case GNUNET_CRYPTO_BSA_RSA: - // rsrs[rsrs_pos].h_rsa = &hd->h_details.h_rsa; - // rsrs[rsrs_pos].msg - // = bp->blinded_message->details.rsa_blinded_message.blinded_msg; - // rsrs[rsrs_pos].msg_size - // = bp->blinded_message->details.rsa_blinded_message.blinded_msg_size; - // rsrs_pos++; - // break; - //case GNUNET_CRYPTO_BSA_CS: - // csrs[csrs_pos].h_cs = &hd->h_details.h_cs; - // csrs[csrs_pos].blinded_donation_unit - // = &bp->blinded_message->details.cs_blinded_message; - // csrs_pos++; - // break; - //default: - // return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; - //} - } - - if ( (0 != csrs_pos) && - (0 != rsrs_pos) ) - { - memset (rs, - 0, - sizeof (rs)); - memset (cs, - 0, - sizeof (cs)); - } - ec = TALER_EC_NONE; - //if (0 != csrs_pos) - //{ - // ec = TALER_CRYPTO_helper_cs_batch_sign ( - // ksh->helpers->csdh, - // csrs_pos, - // csrs, - // (0 == rsrs_pos) ? bss : cs); - // if (TALER_EC_NONE != ec) - // { - // for (unsigned int i = 0; i<csrs_pos; i++) - // DONAU_blinded_donation_unit_sig_free (&cs[i]); - // return ec; - // } - //} - if (0 != rsrs_pos) - { - ec = TALER_CRYPTO_helper_rsa_batch_sign ( - ksh->helpers->rsadh, - rsrs_pos, - rsrs, - (0 == csrs_pos) ? bss : rs); - if (TALER_EC_NONE != ec) - { - for (unsigned int i = 0; i<csrs_pos; i++) - DONAU_blinded_donation_unit_sig_free (&cs[i]); - for (unsigned int i = 0; i<rsrs_pos; i++) - DONAU_blinded_donation_unit_sig_free (&rs[i]); - return ec; - } - } - - if ( (0 != csrs_pos) && - (0 != rsrs_pos) ) - { - rsrs_pos = 0; - csrs_pos = 0; - for (unsigned int i = 0; i<csds_length; i++) - { - const struct DONAU_BlindedDonationUnit *bp = csds[i].bp; - - //switch (bp->blinded_message->cipher) - //{ - //case GNUNET_CRYPTO_BSA_RSA: - // bss[i] = rs[rsrs_pos++]; - // break; - //case GNUNET_CRYPTO_BSA_CS: - // bss[i] = cs[csrs_pos++]; - // break; - //default: - // GNUNET_assert (0); - //} - } - } - return TALER_EC_NONE; -} - - -//enum TALER_ErrorCode -//DH_keys_donation_unit_cs_r_pub ( -// const struct DH_CsDeriveData *cdd, -// struct GNUNET_CRYPTO_CSPublicRPairP *r_pub) -//{ -// const struct DONAU_DonationUnitHashP *h_donation_unit_pub = cdd->h_donation_unit_pub; -// const struct GNUNET_CRYPTO_CsSessionNonce *nonce = cdd->nonce; -// struct DH_KeyStateHandle *ksh; -// struct HelperDonationUnit *hd; -// -// ksh = DH_keys_get_state (); -// if (NULL == ksh) -// { -// return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING; -// } -// hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->donation_unit_keys, -// &h_donation_unit_pub->hash); -// if (NULL == hd) -// { -// return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN; -// } -// if (GNUNET_CRYPTO_BSA_CS != -// hd->donation_unit_pub.bsign_pub_key->cipher) -// { -// return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; -// } -// -// { -// struct TALER_CRYPTO_CsDeriveRequest cdr = { -// .h_cs = &hd->h_details.h_cs, -// .nonce = nonce -// }; -// return TALER_CRYPTO_helper_cs_r_derive (ksh->helpers->csdh, -// &cdr, -// r_pub); -// } -//} - - -//enum TALER_ErrorCode -//DH_keys_donation_unit_cs_batch_r_pub ( -// unsigned int cdds_length, -// const struct DH_CsDeriveData cdds[static cdds_length], -// struct GNUNET_CRYPTO_CSPublicRPairP r_pubs[static cdds_length]) -//{ -// struct DH_KeyStateHandle *ksh; -// struct HelperDonationUnit *hd; -// struct TALER_CRYPTO_CsDeriveRequest cdrs[cdds_length]; -// -// ksh = DH_keys_get_state (); -// if (NULL == ksh) -// { -// return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING; -// } -// for (unsigned int i = 0; i<cdds_length; i++) -// { -// const struct DONAU_DonationUnitHashP *h_donation_unit_pub = cdds[i].h_donation_unit_pub; -// const struct GNUNET_CRYPTO_CsSessionNonce *nonce = cdds[i].nonce; -// -// hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->donation_unit_keys, -// &h_donation_unit_pub->hash); -// if (NULL == hd) -// { -// return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN; -// } -// if (GNUNET_CRYPTO_BSA_CS != -// hd->donation_unit_pub.bsign_pub_key->cipher) -// { -// return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; -// } -// cdrs[i].h_cs = &hd->h_details.h_cs; -// cdrs[i].nonce = nonce; -// } -// -// return TALER_CRYPTO_helper_cs_r_batch_derive (ksh->helpers->csdh, -// cdds_length, -// cdrs, -// r_pubs); -//} - - -void -DH_keys_donation_unit_revoke (const struct DONAU_DonationUnitHashP *h_donation_unit_pub) -{ - struct DH_KeyStateHandle *ksh; - struct HelperDonationUnit *hd; - - ksh = DH_keys_get_state (); - if (NULL == ksh) - { - GNUNET_break (0); - return; - } - hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->donation_unit_keys, - &h_donation_unit_pub->hash); - if (NULL == hd) - { - GNUNET_break (0); - return; - } - switch (hd->donation_unit_pub.bsign_pub_key->cipher) - { - case GNUNET_CRYPTO_BSA_INVALID: - break; - case GNUNET_CRYPTO_BSA_RSA: - TALER_CRYPTO_helper_rsa_revoke (ksh->helpers->rsadh, - &hd->h_details.h_rsa); - DH_keys_update_states (); - return; - case GNUNET_CRYPTO_BSA_CS: - TALER_CRYPTO_helper_cs_revoke (ksh->helpers->csdh, - &hd->h_details.h_cs); - DH_keys_update_states (); - return; - } - GNUNET_break (0); - return; -} - - -//enum TALER_ErrorCode -//DH_keys_donau_sign_ ( -// const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, -// struct DONAU_DonauPublicKeyP *pub, -// struct DONAU_DonauSignatureP *sig) -//{ -// struct DH_KeyStateHandle *ksh; -// -// ksh = DH_keys_get_state (); -// if (NULL == ksh) -// { -// /* This *can* happen if the exchange's crypto helper is not running -// or had some bad error. */ -// GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -// "Cannot sign request, no valid signing keys available.\n"); -// return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING; -// } -// return DH_keys_donau_sign2_ (ksh, -// purpose, -// pub, -// sig); -//} -// -// -//enum TALER_ErrorCode -//DH_keys_donau_sign2_ ( -// void *cls, -// const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, -// struct DONAU_DonauPublicKeyP *pub, -// struct DONAU_DonauSignatureP *sig) -//{ -// struct DH_KeyStateHandle *ksh = cls; -// enum TALER_ErrorCode ec; -// -// ec = TALER_CRYPTO_helper_esign_sign_ (ksh->helpers->esh, -// purpose, -// pub, -// sig); -// if (TALER_EC_NONE != ec) -// return ec; -// { -// /* Here we check here that 'pub' is set to an exchange public key that is -// actually signed by the master key! Otherwise, we happily continue to -// use key material even if the offline signatures have not been made -// yet! */ -// struct GNUNET_PeerIdentity pid; -// struct SigningKey *sk; -// -// pid.public_key = pub->eddsa_pub; -// sk = GNUNET_CONTAINER_multipeermap_get (ksh->signkey_map, -// &pid); -// if (NULL == sk) -// { -// /* just to be safe, zero out the (valid) signature, as the key -// should not or no longer be used */ -// GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -// "Cannot sign, offline key signatures are missing!\n"); -// memset (sig, -// 0, -// sizeof (*sig)); -// return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; -// } -// } -// return ec; -//} - - -void -DH_keys_donau_revoke (const struct DONAU_DonauPublicKeyP *donau_pub) -{ - struct DH_KeyStateHandle *ksh; - - ksh = DH_keys_get_state (); - if (NULL == ksh) - { - GNUNET_break (0); - return; - } - TALER_CRYPTO_helper_esign_revoke (ksh->helpers->esh, - donau_pub); - DH_keys_update_states (); -} - - -/** - * Comparator used for a binary search by cherry_pick_date for @a key in the - * `struct KeysResponseData` array. See libc's qsort() and bsearch() functions. - * - * @param key pointer to a `struct GNUNET_TIME_Timestamp` - * @param value pointer to a `struct KeysResponseData` array entry - * @return 0 if time matches, -1 if key is smaller, 1 if key is larger - */ -static int -krd_search_comparator (const void *key, - const void *value) -{ - const struct GNUNET_TIME_Timestamp *kd = key; - const struct KeysResponseData *krd = value; - - if (GNUNET_TIME_timestamp_cmp (*kd, - >, - krd->cherry_pick_date)) - return -1; - if (GNUNET_TIME_timestamp_cmp (*kd, - <, - krd->cherry_pick_date)) - return 1; - return 0; -} - - -MHD_RESULT -DH_keys_get_handler (struct DH_RequestContext *rc, - const char *const args[]) -{ - struct GNUNET_TIME_Timestamp last_issue_date; - const char *etag; - - etag = MHD_lookup_connection_value (rc->connection, - MHD_HEADER_KIND, - MHD_HTTP_HEADER_IF_NONE_MATCH); - (void) args; - { - const char *have_cherrypick; - - have_cherrypick = MHD_lookup_connection_value (rc->connection, - MHD_GET_ARGUMENT_KIND, - "last_issue_date"); - if (NULL != have_cherrypick) - { - unsigned long long cherrypickn; - - if (1 != - sscanf (have_cherrypick, - "%llu", - &cherrypickn)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - have_cherrypick); - } - /* The following multiplication may overflow; but this should not really - be a problem, as giving back 'older' data than what the client asks for - (given that the client asks for data in the distant future) is not - problematic */ - last_issue_date = GNUNET_TIME_timestamp_from_s (cherrypickn); - } - else - { - last_issue_date = GNUNET_TIME_UNIT_ZERO_TS; - } - } - - { - struct DH_KeyStateHandle *ksh; - const struct KeysResponseData *krd; - - ksh = DH_keys_get_state (); - if ( (NULL == ksh) || - (0 == ksh->krd_array_length) ) - { - if ( ( (SKR_LIMIT == skr_size) && - (rc->connection == skr_connection) ) || - DH_suicide) - { - return TALER_MHD_reply_with_error ( - rc->connection, - MHD_HTTP_SERVICE_UNAVAILABLE, - TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING, - DH_suicide - ? "server terminating" - : "too many connections suspended waiting on /keys"); - } - return suspend_request (rc->connection); - } - krd = bsearch (&last_issue_date, - ksh->krd_array, - ksh->krd_array_length, - sizeof (struct KeysResponseData), - &krd_search_comparator); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Filtering /keys by cherry pick date %s found entry %u/%u\n", - GNUNET_TIME_timestamp2s (last_issue_date), - (unsigned int) (krd - ksh->krd_array), - ksh->krd_array_length); - if ( (NULL == krd) && - (ksh->krd_array_length > 0) ) - { - if (! GNUNET_TIME_absolute_is_zero (last_issue_date.abs_time)) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Client provided invalid cherry picking timestamp %s, returning full response\n", - GNUNET_TIME_timestamp2s (last_issue_date)); - krd = &ksh->krd_array[ksh->krd_array_length - 1]; - } - if (NULL == krd) - { - /* Likely keys not ready *yet*. - Wait until they are. */ - return suspend_request (rc->connection); - } - if ( (NULL != etag) && - (0 == strcmp (etag, - krd->etag)) ) - //return DH_RESPONSE_reply_not_modified (rc->connection, - // krd->etag, - // &setup_general_response_headers, - // ksh); - - return MHD_queue_response (rc->connection, - MHD_HTTP_OK, - (MHD_YES == - TALER_MHD_can_compress (rc->connection)) - ? krd->response_compressed - : krd->response_uncompressed); - } -} - - -enum GNUNET_GenericReturnValue -DH_keys_get_timing (const struct DONAU_DonauPublicKeyP *donau_pub, - struct DONAUDB_SignkeyMetaData *meta) -{ - struct DH_KeyStateHandle *ksh; - struct HelperSignkey *hsk; - struct GNUNET_PeerIdentity pid; - - ksh = DH_keys_get_state_for_management_only (); - if (NULL == ksh) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - - pid.public_key = donau_pub->eddsa_pub; - hsk = GNUNET_CONTAINER_multipeermap_get (ksh->helpers->esign_keys, - &pid); - if (NULL == hsk) - { - GNUNET_break (0); - return GNUNET_NO; - } - meta->start = hsk->start_time; - - //meta->expire_sign = GNUNET_TIME_absolute_to_timestamp ( - // GNUNET_TIME_absolute_add (meta->start.abs_time, - // hsk->validity_duration)); - //meta->expire_legal = GNUNET_TIME_absolute_to_timestamp ( - // GNUNET_TIME_absolute_add (meta->expire_sign.abs_time, - // signkey_legal_duration)); - return GNUNET_OK; -} - - /** - * Closure for #add_future_donation_unitkey_cb and #add_future_signkey_cb. + * Closure for #add_future_donation_unit_cb and #add_future_signkey_cb. */ struct FutureBuilderContext { @@ -2540,7 +1029,7 @@ struct FutureBuilderContext struct DH_KeyStateHandle *ksh; /** - * Array of donation_unit keys. + * Array of donation unit keys. */ json_t *donation_units; @@ -2551,60 +1040,48 @@ struct FutureBuilderContext }; - /** - * Function called on all of our current and future donation_unit keys + * Function called on all of our current and future donation unit keys * known to the helper process. Filters out those that are current - * and adds the remaining donation_unit keys (with their configuration + * and adds the remaining donation unit keys (with their configuration * data) to the JSON array. * * @param cls the `struct FutureBuilderContext *` - * @param h_donation_unit_pub hash of the donation_unit public key - * @param value a `struct HelperDonationUnit` + * @param h_donation_unit_pub hash of the donation unit public key + * @param value a `struct HelperDenomination` * @return #GNUNET_OK (continue to iterate) */ static enum GNUNET_GenericReturnValue -add_future_donation_unitkey_cb (void *cls, - const struct GNUNET_HashCode *h_donation_unit_pub, - void *value) +add_donation_unitkey_cb (void *cls, + const struct GNUNET_HashCode *h_donation_unit_pub, + void *value) { struct FutureBuilderContext *fbc = cls; - struct HelperDonationUnit *hd = value; - struct DH_DonationUnitKey *dk; + struct HelperDonationUnit *helper_donation_unit = value; + struct DH_DonationUnitKey *donation_unit_key; struct DONAUDB_DonationUnitKeyMetaData meta = {0}; - dk = GNUNET_CONTAINER_multihashmap_get (fbc->ksh->donation_unitkey_map, - h_donation_unit_pub); - if (NULL != dk) + donation_unit_key = GNUNET_CONTAINER_multihashmap_get (fbc->ksh->denomkey_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! */ - //meta.start = hd->start_time; - //meta.expire_withdraw = GNUNET_TIME_absolute_to_timestamp ( - // GNUNET_TIME_absolute_add (meta.start.abs_time, - // hd->validity_duration)); - - //GNUNET_assert ( - // 0 == - // json_array_append_new ( - // fbc->donation_units, - // GNUNET_JSON_PACK ( - // //DONAU_JSON_pack_amount ("value", - // // &meta.value), - // //GNUNET_JSON_pack_timestamp ("stamp_start", - // // meta.start), - // //GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw", - // // meta.expire_withdraw), - // //GNUNET_JSON_pack_timestamp ("stamp_expire_deposit", - // // meta.expire_deposit), - // //GNUNET_JSON_pack_timestamp ("stamp_expire_legal", - // // meta.expire_legal), - // DONAU_JSON_pack_donation_unit_pub ("donation_unit_pub", - // &hd->donation_unit_pub), - // GNUNET_JSON_pack_data_auto ("donation_unit_secmod_sig", - // &hd->sm_sig), - // GNUNET_JSON_pack_string ("section_name", - // hd->section_name)))); + // 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) + ))); return GNUNET_OK; } @@ -2617,59 +1094,58 @@ add_future_donation_unitkey_cb (void *cls, * * @param cls the `struct FutureBuilderContext *` * @param pid actually the exchange public key (type disguised) - * @param value a `struct HelperDonationUnit` + * @param value a `struct HelperDenomination` * @return #GNUNET_OK (continue to iterate) */ static enum GNUNET_GenericReturnValue -add_future_signkey_cb (void *cls, - const struct GNUNET_PeerIdentity *pid, - void *value) +add_signkey_cb (void *cls, + const struct GNUNET_PeerIdentity *pid, + void *value) { struct FutureBuilderContext *fbc = cls; struct HelperSignkey *hsk = value; struct SigningKey *sk; - struct GNUNET_TIME_Timestamp stamp_expire; - struct GNUNET_TIME_Timestamp legal_end; + // struct GNUNET_TIME_Timestamp stamp_expire; + // struct GNUNET_TIME_Timestamp legal_end; 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)) - return GNUNET_OK; /* this key already expired! */ - stamp_expire = GNUNET_TIME_absolute_to_timestamp ( - GNUNET_TIME_absolute_add (hsk->start_time.abs_time, - hsk->validity_duration)); - legal_end = GNUNET_TIME_absolute_to_timestamp ( - GNUNET_TIME_absolute_add (stamp_expire.abs_time, - signkey_legal_duration)); + // if (GNUNET_TIME_relative_is_zero (hsk->validity_duration)) + // return GNUNET_OK; /* this key already expired! */ + // stamp_expire = GNUNET_TIME_absolute_to_timestamp ( + // GNUNET_TIME_absolute_add (hsk->start_time.abs_time, + // hsk->validity_duration)); + // 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_start", - hsk->start_time), - GNUNET_JSON_pack_timestamp ("stamp_expire", - stamp_expire), - GNUNET_JSON_pack_timestamp ("stamp_end", - legal_end), - GNUNET_JSON_pack_data_auto ("signkey_secmod_sig", - &hsk->sm_sig)))); + // 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_management_get_keys_handler (const struct DH_RequestHandler *rh, - struct MHD_Connection *connection) +DH_keys_get_handler (const struct DH_RequestHandler *rh, + struct MHD_Connection *connection) { struct DH_KeyStateHandle *ksh; json_t *reply; (void) rh; - ksh = DH_keys_get_state_for_management_only (); + ksh = DH_keys_get_state (true); if (NULL == ksh) { return TALER_MHD_reply_with_error (connection, @@ -2685,44 +1161,44 @@ DH_keys_management_get_keys_handler (const struct DH_RequestHandler *rh, .donation_units = json_array (), .signkeys = json_array () }; - - if ( (GNUNET_is_zero (&donation_unit_rsa_sm_pub)) && - (GNUNET_is_zero (&donation_unit_cs_sm_pub)) ) - { - /* Either IPC failed, or neither helper had any donation_units configured. */ - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_GATEWAY, - TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE, - NULL); - } - if (GNUNET_is_zero (&esign_sm_pub)) - { - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_GATEWAY, - TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE, - NULL); - } + // if ( (GNUNET_is_zero (&donation_unit_rsa_sm_pub)) && + // (GNUNET_is_zero (&donation_unit_cs_sm_pub)) ) + // { + // /* Either IPC failed, or neither helper had any donation_unit configured. */ + // return TALER_MHD_reply_with_error (connection, + // MHD_HTTP_BAD_GATEWAY, + // TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE, + // NULL); + // } + // if (GNUNET_is_zero (&esign_sm_pub)) + // { + // return TALER_MHD_reply_with_error (connection, + // MHD_HTTP_BAD_GATEWAY, + // TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE, + // NULL); + // } GNUNET_assert (NULL != fbc.donation_units); GNUNET_assert (NULL != fbc.signkeys); GNUNET_CONTAINER_multihashmap_iterate (ksh->helpers->donation_unit_keys, - &add_future_donation_unitkey_cb, + &add_donation_unitkey_cb, &fbc); GNUNET_CONTAINER_multipeermap_iterate (ksh->helpers->esign_keys, - &add_future_signkey_cb, + &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_data_auto ("donation_unit_secmod_public_key", - &donation_unit_rsa_sm_pub), - GNUNET_JSON_pack_data_auto ("donation_unit_secmod_cs_public_key", - &donation_unit_cs_sm_pub), - GNUNET_JSON_pack_data_auto ("signkey_secmod_public_key", - &esign_sm_pub)); + 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", + // &donation_unit_cs_sm_pub), + // GNUNET_JSON_pack_data_auto ("signkey_secmod_public_key", + // &esign_sm_pub)); + ); GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Returning GET /management/keys response:\n"); + "Returning GET /keys response:\n"); if (NULL == reply) return TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, @@ -2741,4 +1217,179 @@ DH_keys_management_get_keys_handler (const struct DH_RequestHandler *rh, } +/** + * Comparator used for a binary search by cherry_pick_date for @a key in the + * `struct KeysResponseData` array. See libc's qsort() and bsearch() functions. + * + * @param key pointer to a `struct GNUNET_TIME_Timestamp` + * @param value pointer to a `struct KeysResponseData` array entry + * @return 0 if time matches, -1 if key is smaller, 1 if key is larger + */ +static int +krd_search_comparator (const void *key, + const void *value) +{ + const struct GNUNET_TIME_Timestamp *kd = key; + const struct KeysResponseData *krd = value; + + if (GNUNET_TIME_timestamp_cmp (*kd, + >, + krd->cherry_pick_date)) + return -1; + if (GNUNET_TIME_timestamp_cmp (*kd, + <, + krd->cherry_pick_date)) + return 1; + return 0; +} + + +/** + * Callback used to set headers in a response. + * + * @param cls closure + * @param[in,out] resp response to modify + */ +typedef void +(*TEH_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) +{ + MHD_RESULT ret; + struct MHD_Response *resp; + + 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)); + ret = MHD_queue_response (connection, + MHD_HTTP_NOT_MODIFIED, + resp); + GNUNET_break (MHD_YES == ret); + MHD_destroy_response (resp); + return ret; +} + + +// MHD_RESULT +// DH_keys_get_handler (struct DH_RequestContext *rc, +// const char *const args[]) +// { +// struct GNUNET_TIME_Timestamp last_issue_date; +// const char *etag; + +// etag = MHD_lookup_connection_value (rc->connection, +// MHD_HEADER_KIND, +// MHD_HTTP_HEADER_IF_NONE_MATCH); +// (void) args; +// // { +// // const char *have_cherrypick; + +// // have_cherrypick = MHD_lookup_connection_value (rc->connection, +// // MHD_GET_ARGUMENT_KIND, +// // "last_issue_date"); +// // if (NULL != have_cherrypick) +// // { +// // unsigned long long cherrypickn; + +// // if (1 != +// // sscanf (have_cherrypick, +// // "%llu", +// // &cherrypickn)) +// // { +// // GNUNET_break_op (0); +// // return TALER_MHD_reply_with_error (rc->connection, +// // MHD_HTTP_BAD_REQUEST, +// // TALER_EC_GENERIC_PARAMETER_MALFORMED, +// // have_cherrypick); +// // } +// // /* The following multiplication may overflow; but this should not really +// // be a problem, as giving back 'older' data than what the client asks for +// // (given that the client asks for data in the distant future) is not +// // problematic */ +// // last_issue_date = GNUNET_TIME_timestamp_from_s (cherrypickn); +// // } +// // else +// // { +// // last_issue_date = GNUNET_TIME_UNIT_ZERO_TS; +// // } +// // } + +// { +// struct DH_KeyStateHandle *ksh; +// const struct KeysResponseData *krd; + +// ksh = DH_keys_get_state (); +// if ( (NULL == ksh) || +// (0 == ksh->krd_array_length) ) +// { +// if ( ( (SKR_LIMIT == skr_size) && +// (rc->connection == skr_connection) ) || +// DH_suicide) +// { +// return TALER_MHD_reply_with_error ( +// rc->connection, +// MHD_HTTP_SERVICE_UNAVAILABLE, +// TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING, +// DH_suicide +// ? "server terminating" +// : "too many connections suspended waiting on /keys"); +// } +// return suspend_request (rc->connection); +// } +// krd = bsearch (&last_issue_date, +// ksh->krd_array, +// ksh->krd_array_length, +// sizeof (struct KeysResponseData), +// &krd_search_comparator); +// GNUNET_log (GNUNET_ERROR_TYPE_INFO, +// "Filtering /keys by cherry pick date %s found entry %u/%u\n", +// GNUNET_TIME_timestamp2s (last_issue_date), +// (unsigned int) (krd - ksh->krd_array), +// ksh->krd_array_length); +// if ( (NULL == krd) && +// (ksh->krd_array_length > 0) ) +// { +// if (! GNUNET_TIME_absolute_is_zero (last_issue_date.abs_time)) +// GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +// "Client provided invalid cherry picking timestamp %s, returning full response\n", +// GNUNET_TIME_timestamp2s (last_issue_date)); +// krd = &ksh->krd_array[ksh->krd_array_length - 1]; +// } +// if (NULL == krd) +// { +// /* Likely keys not ready *yet*. +// Wait until they are. */ +// return suspend_request (rc->connection); +// } +// if ( (NULL != etag) && +// (0 == strcmp (etag, +// krd->etag)) ) +// return DH_RESPONSE_reply_not_modified (rc->connection, +// krd->etag, +// &setup_general_response_headers, +// ksh); + +// return MHD_queue_response (rc->connection, +// MHD_HTTP_OK, +// (MHD_YES == +// TALER_MHD_can_compress (rc->connection)) +// ? krd->response_compressed +// : krd->response_uncompressed); +// } +// } + + /* end of donau-httpd_keys.c */ diff --git a/src/donau/donau-httpd_keys.h b/src/donau/donau-httpd_keys.h @@ -1,262 +1,150 @@ /* This file is part of TALER - Copyright (C) 2020-2022 Taler Systems SA + Copyright (C) 2020-2023 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 + WARRANTY; without even the implied warranty of CHARITYABILITY 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 taler-donau-httpd_keys.h + * @file donau-httpd_keys.h * @brief management of our various keys * @author Christian Grothoff */ #include "taler/platform.h" #include "taler/taler_json_lib.h" #include "taler/taler_mhd_lib.h" -//#include "taler/taler-donau-httpd_responses.h" +// #include "donau-httpd_responses.h" #include "donau_util.h" #include "donaudb_plugin.h" #include "donau-httpd.h" + #ifndef DONAU_HTTPD_KEYS_H #define DONAU_HTTPD_KEYS_H /** - * @brief All information about a donation_unit key (which is used to - * sign coins into existence). + * @brief All information about a donation unit key (which is used to + * sign donation receipts into existence). */ struct DH_DonationUnitKey { /** - * Decoded donation_unit public key (the hash of it is in + * Decoded donation unit public key (the hash of it is in * @e issue, but we sometimes need the full public key as well). */ struct DONAU_DonationUnitPublicKey donation_unit_pub; /** - * Hash code of the donation_unit public key. + * Hash code of the donation unit public key. */ struct DONAU_DonationUnitHashP h_donation_unit_pub; /** - * Meta data about the type of the donation_unit, such as fees and validity - * periods. + * Meta data about the type of the donation unit, containing the validity + * year and the value of the donation unit. */ struct DONAUDB_DonationUnitKeyMetaData meta; }; /** - * Snapshot of the (coin and signing) keys (including private keys) of - * the donau. There can be multiple instances of this struct, as it is - * reference counted and only destroyed once the last user is done - * with it. The current instance is acquired using - * #DH_KS_acquire(). Using this function increases the - * reference count. The contents of this structure (except for the - * reference counter) should be considered READ-ONLY until it is - * ultimately destroyed (as there can be many concurrent users). - */ -struct DH_KeyStateHandle; - - -/** - * Run internal invariant checks. For debugging. - */ -void -DH_check_invariants (void); - -/** - * Clean up wire subsystem. - */ -void -DH_wire_done (void); - -/** - * Initialize wire subsystem. - * - * @return #GNUNET_OK on success - */ -enum GNUNET_GenericReturnValue -DH_wire_init (void); - - -/** - * Something changed in the database. Rebuild the wire replies. This function - * should be called if the donau learns about a new signature from our - * master key. - * - * (We do not do so immediately, but merely signal to all threads that they - * need to rebuild their wire state upon the next call to - * #DH_keys_get_state()). - */ -void -DH_wire_update_state (void); - - -/** - * Return the current key state for this thread. Possibly re-builds the key - * state if we have reason to believe that something changed. - * - * The result is ONLY valid until the next call to - * #DH_keys_donation_unit_by_hash() or #DH_keys_get_state() - * or #DH_keys_donau_sign(). - * - * @return NULL on error - */ -struct DH_KeyStateHandle * -DH_keys_get_state (void); - -/** - * Obtain the key state if we should NOT run finish_keys_response() because we - * only need the state for the /management/keys API - */ -struct DH_KeyStateHandle * -DH_keys_get_state_for_management_only (void); - -/** - * Something changed in the database. Rebuild all key states. This function - * should be called if the donau learns about a new signature from an - * auditor or our master key. - * - * (We do not do so immediately, but merely signal to all threads that they - * need to rebuild their key state upon the next call to - * #DH_keys_get_state()). - */ -void -DH_keys_update_states (void); - - -/** - * Look up the issue for a denom public key. Note that the result - * must only be used in this thread and only until another key or - * key state is resolved. - * - * @param h_donation_unit_pub hash of donation_unit public key - * @param[in,out] conn used to return status message if NULL is returned - * @param[out] mret set to the MHD status if NULL is returned - * @return the donation_unit key issue, - * or NULL if @a h_donation_unit_pub could not be found - */ -struct DH_DonationUnitKey * -DH_keys_donation_unit_by_hash ( - const struct DONAU_DonationUnitHashP *h_donation_unit_pub, - struct MHD_Connection *conn, - MHD_RESULT *mret); - - -/** - * Look up the issue for a denom public key using a given @a ksh. This allows - * requesting multiple donation_units with the same @a ksh which thus will - * remain valid until the next call to #DH_keys_donation_unit_by_hash() or - * #DH_keys_get_state() or #DH_keys_donau_sign(). - * - * @param ksh key state state to look in - * @param h_donation_unit_pub hash of donation_unit public key - * @param[in,out] conn connection used to return status message if NULL is returned - * @param[out] mret set to the MHD status if NULL is returned - * @return the donation_unit key issue, - * or NULL if @a h_donation_unit_pub could not be found - */ -struct DH_DonationUnitKey * -DH_keys_donation_unit_by_hash_from_state ( - const struct DH_KeyStateHandle *ksh, - const struct DONAU_DonationUnitHashP *h_donation_unit_pub, - struct MHD_Connection *conn, - MHD_RESULT *mret); - -/** * Information needed to create a blind signature. */ -struct DH_CoinSignData -{ - /** - * Hash of key to sign with. - */ - const struct DONAU_DonationUnitHashP *h_donation_unit_pub; - - /** - * Blinded planchet to sign over. - */ - const struct DONAU_BlindedDonationUnit *bp; -}; - - +// struct DH_CoinSignData +// { /** - * Request to sign @a csds. - * - * @param csds array with data to blindly sign (and keys to sign with) - * @param csds_length length of @a csds array - * @param[out] bss array set to the blind signature on success; must be of length @a csds_length - * @return #TALER_EC_NONE on success - */ -enum TALER_ErrorCode -DH_keys_donation_unit_batch_sign ( - unsigned int csds_length, - const struct DH_CoinSignData csds[static csds_length], - struct DONAU_BlindedDonationUnitSignature bss[static csds_length]); - - -/** - * Information needed to derive the CS r_pub. - */ -struct DH_CsDeriveData -{ - /** * Hash of key to sign with. */ - const struct DONAU_DonationUnitHashP *h_donation_unit_pub; - - /** - * Nonce to use. - */ - const struct GNUNET_CRYPTO_CsSessionNonce *nonce; -}; - - -/** - * Request to derive CS @a r_pub using the donation_unit and nonce from @a cdd. - * - * @param cdd data to compute @a r_pub from - * @param[out] r_pub where to write the result - * @return #TALER_EC_NONE on success - */ -enum TALER_ErrorCode -DH_keys_donation_unit_cs_r_pub ( - const struct DH_CsDeriveData *cdd, - struct GNUNET_CRYPTO_CSPublicRPairP *r_pub); - +// const struct TALER_DenominationHashP *h_denom_pub; /** - * Request to derive a bunch of CS @a r_pubs using the - * donation_units and nonces from @a cdds. - * - * @param cdds array to compute @a r_pubs from - * @param cdds_length length of the @a cdds array - * @param[out] r_pubs array where to write the result; must be of length @a cdds_length - * @return #TALER_EC_NONE on success - */ -enum TALER_ErrorCode -DH_keys_donation_unit_cs_batch_r_pub ( - unsigned int cdds_length, - const struct DH_CsDeriveData cdds[static cdds_length], - struct GNUNET_CRYPTO_CSPublicRPairP r_pubs[static cdds_length]); + * Blinded planchet to sign over. + */ +// const struct TALER_BlindedPlanchet *bp; +// }; + + +// /** +// * Request to sign @a csds. +// * +// * @param csds array with data to blindly sign (and keys to sign with) +// * @param csds_length length of @a csds array +// * @param for_melt true if this is for a melt operation +// * @param[out] bss array set to the blind signature on success; must be of length @a csds_length +// * @return #TALER_EC_NONE on success +// */ +// enum TALER_ErrorCode +// TEH_keys_denomination_batch_sign ( +// unsigned int csds_length, +// const struct TEH_CoinSignData csds[static csds_length], +// bool for_melt, +// struct TALER_BlindedDenominationSignature bss[static csds_length]); + + +// /** +// * Information needed to derive the CS r_pub. +// */ +// struct TEH_CsDeriveData +// { +// /** +// * Hash of key to sign with. +// */ +// const struct TALER_DenominationHashP *h_denom_pub; + +// /** +// * Nonce to use. +// */ +// const struct GNUNET_CRYPTO_CsSessionNonce *nonce; +// }; + + +// /** +// * Request to derive CS @a r_pub using the denomination and nonce from @a cdd. +// * +// * @param cdd data to compute @a r_pub from +// * @param for_melt true if this is for a melt operation +// * @param[out] r_pub where to write the result +// * @return #TALER_EC_NONE on success +// */ +// enum TALER_ErrorCode +// TEH_keys_denomination_cs_r_pub ( +// const struct TEH_CsDeriveData *cdd, +// bool for_melt, +// struct GNUNET_CRYPTO_CSPublicRPairP *r_pub); + +// /** +// * Request to derive a bunch of CS @a r_pubs using the +// * denominations and nonces from @a cdds. +// * +// * @param cdds array to compute @a r_pubs from +// * @param cdds_length length of the @a cdds array +// * @param for_melt true if this is for a melt operation +// * @param[out] r_pubs array where to write the result; must be of length @a cdds_length +// * @return #TALER_EC_NONE on success +// */ +// enum TALER_ErrorCode +// TEH_keys_denomination_cs_batch_r_pub ( +// unsigned int cdds_length, +// const struct TEH_CsDeriveData cdds[static cdds_length], +// bool for_melt, +// struct GNUNET_CRYPTO_CSPublicRPairP r_pubs[static cdds_length]); /** * Fully clean up keys subsystem. */ void -DH_keys_finished (void); +TEH_keys_finished (void); /** @@ -266,110 +154,7 @@ DH_keys_finished (void); * @param do_shutdown are we shutting down? */ void -DH_resume_keys_requests (bool do_shutdown); - - -/** - * Sign the message in @a purpose with the donau's signing key. - * - * The @a purpose data is the beginning of the data of which the signature is - * to be created. The `size` field in @a purpose must correctly indicate the - * number of bytes of the data structure, including its header. Use - * #DH_keys_donau_sign() instead of calling this function directly! - * - * @param purpose the message to sign - * @param[out] pub set to the current public signing key of the donau - * @param[out] sig signature over purpose using current signing key - * @return #TALER_EC_NONE on success - */ -enum TALER_ErrorCode -DH_keys_donau_sign_ ( - const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, - struct DONAU_DonauPublicKeyP *pub, - struct DONAU_DonauSignatureP *sig); - - -/** - * Sign the message in @a purpose with the donau's signing key. - * - * The @a purpose data is the beginning of the data of which the signature is - * to be created. The `size` field in @a purpose must correctly indicate the - * number of bytes of the data structure, including its header. Use - * #DH_keys_donau_sign() instead of calling this function directly! - * - * @param cls key state state to look in - * @param purpose the message to sign - * @param[out] pub set to the current public signing key of the donau - * @param[out] sig signature over purpose using current signing key - * @return #TALER_EC_NONE on success - */ -enum TALER_ErrorCode -DH_keys_donau_sign2_ ( - void *cls, - const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, - struct DONAU_DonauPublicKeyP *pub, - struct DONAU_DonauSignatureP *sig); - - -/** - * @ingroup crypto - * @brief EdDSA sign a given block. - * - * The @a ps data must be a fixed-size struct for which the signature is to be - * created. The `size` field in @a ps->purpose must correctly indicate the - * number of bytes of the data structure, including its header. - * - * @param ps packed struct with what to sign, MUST begin with a purpose - * @param[out] pub where to store the public key to use for the signing - * @param[out] sig where to write the signature - * @return #TALER_EC_NONE on success - */ -#define DH_keys_donau_sign(ps,pub,sig) \ - ({ \ - /* check size is set correctly */ \ - GNUNET_assert (htonl ((ps)->purpose.size) == \ - sizeof (*ps)); \ - /* check 'ps' begins with the purpose */ \ - GNUNET_static_assert (((void*) (ps)) == \ - ((void*) &(ps)->purpose)); \ - DH_keys_donau_sign_ (&(ps)->purpose, \ - pub, \ - sig); \ - }) - - -/** - * @ingroup crypto - * @brief EdDSA sign a given block. - * - * The @a ps data must be a fixed-size struct for which the signature is to be - * created. The `size` field in @a ps->purpose must correctly indicate the - * number of bytes of the data structure, including its header. - * - * This allows requesting multiple donation_units with the same @a ksh which - * thus will remain valid until the next call to - * #DH_keys_donation_unit_by_hash() or #DH_keys_get_state() or - * #DH_keys_donau_sign(). - * - * @param ksh key state to use - * @param ps packed struct with what to sign, MUST begin with a purpose - * @param[out] pub where to store the public key to use for the signing - * @param[out] sig where to write the signature - * @return #TALER_EC_NONE on success - */ -#define DH_keys_donau_sign2(ksh,ps,pub,sig) \ - ({ \ - /* check size is set correctly */ \ - GNUNET_assert (htonl ((ps)->purpose.size) == \ - sizeof (*ps)); \ - /* check 'ps' begins with the purpose */ \ - GNUNET_static_assert (((void*) (ps)) == \ - ((void*) &(ps)->purpose)); \ - DH_keys_donau_sign2_ (ksh, \ - &(ps)->purpose, \ - pub, \ - sig); \ - }) +TEH_resume_keys_requests (bool do_shutdown); /** @@ -381,33 +166,7 @@ DH_keys_donau_sign2_ ( * @return MHD result code */ MHD_RESULT -DH_keys_get_handler (struct DH_RequestContext *rc, - const char *const args[]); - - -/** - * Function to call to handle requests to "/management/keys" by sending - * back our future key material. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @return MHD result code - */ -MHD_RESULT -DH_keys_management_get_keys_handler (const struct DH_RequestHandler *rh, - struct MHD_Connection *connection); - - -/** - * Load expiration times for the given onling signing key. - * - * @param donau_pub the online signing key - * @param[out] meta set to meta data about the key - * @return #GNUNET_OK on success - */ -enum GNUNET_GenericReturnValue -DH_keys_get_timing (const struct DONAU_DonauPublicKeyP *donau_pub, - struct DONAUDB_SignkeyMetaData *meta); +DH_keys_get_handler (const struct DH_RequestHandler *, struct MHD_Connection *); /** @@ -416,7 +175,7 @@ DH_keys_get_timing (const struct DONAU_DonauPublicKeyP *donau_pub, * @return #GNUNET_OK on success */ enum GNUNET_GenericReturnValue -DH_keys_init (void); +TEH_keys_init (void); #endif