gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-donau] branch master updated: [donau] restore http-keys adaptions


From: gnunet
Subject: [taler-donau] branch master updated: [donau] restore http-keys adaptions
Date: Fri, 12 Jan 2024 11:41:21 +0100

This is an automated email from the git hooks/post-receive script.

pius-loosli pushed a commit to branch master
in repository donau.

The following commit(s) were added to refs/heads/master by this push:
     new 395fc5e  [donau] restore http-keys adaptions
395fc5e is described below

commit 395fc5e7983a3c6918248bf37ced1f9c7d5d5946
Author: Pius Loosli <loosp2@bfh.ch>
AuthorDate: Fri Jan 12 11:42:18 2024 +0100

    [donau] restore http-keys adaptions
---
 src/donau/donau-httpd_keys.c | 2985 ++++++++++++------------------------------
 src/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
index 545aa63..5c6ecd8 100644
--- 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,15 +198,10 @@ 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.
    */
@@ -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`
@@ -284,12 +353,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
index a6d26c5..203f339 100644
--- 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

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]