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