From 171391057d82c6483ea40d589e2bf89a2064a125 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 22 Nov 2020 22:25:49 +0100 Subject: complete crypto helper denom testing --- contrib/gana | 2 +- src/util/Makefile.am | 2 +- src/util/crypto_helper.c | 527 --------------------------------- src/util/crypto_helper_denom.c | 588 +++++++++++++++++++++++++++++++++++++ src/util/taler-helper-crypto-rsa.c | 49 +++- src/util/test_helper_rsa.c | 171 +++++++++-- 6 files changed, 780 insertions(+), 559 deletions(-) delete mode 100644 src/util/crypto_helper.c create mode 100644 src/util/crypto_helper_denom.c diff --git a/contrib/gana b/contrib/gana index e5ae01eeb..8341d17cd 160000 --- a/contrib/gana +++ b/contrib/gana @@ -1 +1 @@ -Subproject commit e5ae01eeb4dedd8599473e64e098ea97fb7dadde +Subproject commit 8341d17cd88b1e88943f192a47fbc61ce925816c diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 505634381..73edce2cd 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -51,7 +51,7 @@ libtalerutil_la_SOURCES = \ amount.c \ config.c \ crypto.c \ - crypto_helper.c \ + crypto_helper_denom.c \ crypto_wire.c \ getopt.c \ lang.c \ diff --git a/src/util/crypto_helper.c b/src/util/crypto_helper.c deleted file mode 100644 index 20ab61ff4..000000000 --- a/src/util/crypto_helper.c +++ /dev/null @@ -1,527 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2020 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 -*/ -/** - * @file util/crypto_helper.c - * @brief utility functions for running out-of-process private key operations - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_util.h" -#include "taler-helper-crypto-rsa.h" - - -struct TALER_CRYPTO_DenominationHelper -{ - /** - * Function to call with updates to available key material. - */ - TALER_CRYPTO_DenominationKeyStatusCallback 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; - - /** - * Socket address of this process. - */ - struct sockaddr_un my_sa; - - /** - * Template for @e my_sa. - */ - char *template; - - /** - * The UNIX domain socket, -1 if we are currently not connected. - */ - int sock; -}; - - -/** - * 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 TALER_CRYPTO_DenominationHelper *dh) -{ - GNUNET_break (0 == close (dh->sock)); - if (0 != unlink (dh->my_sa.sun_path)) - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, - "unlink", - dh->my_sa.sun_path); - dh->sock = -1; -} - - -/** - * Try to connect to the helper process. Updates - * @e sock field in @a dh. - * - * @param[in,out] dh handle to establish connection for - */ -static void -try_connect (struct TALER_CRYPTO_DenominationHelper *dh) -{ - if (-1 != dh->sock) - return; - dh->sock = socket (AF_UNIX, - SOCK_DGRAM, - 0); - if (-1 == dh->sock) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, - "socket"); - return; - } - { - char *tmpdir; - - tmpdir = GNUNET_DISK_mktemp (dh->template); - if (NULL == tmpdir) - { - do_disconnect (dh); - return; - } - /* we use >= here because we want the sun_path to always - be 0-terminated */ - if (strlen (tmpdir) >= sizeof (dh->sa.sun_path)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "PATHS", - "TALER_RUNTIME_DIR", - "path too long"); - GNUNET_free (tmpdir); - do_disconnect (dh); - return; - } - dh->my_sa.sun_family = AF_UNIX; - strncpy (dh->my_sa.sun_path, - tmpdir, - sizeof (dh->sa.sun_path)); - if (0 != unlink (tmpdir)) - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, - "unlink", - tmpdir); - GNUNET_free (tmpdir); - } - if (0 != bind (dh->sock, - (const struct sockaddr *) &dh->my_sa, - sizeof (dh->my_sa))) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, - "bind"); - do_disconnect (dh); - return; - } - { - struct GNUNET_MessageHeader hdr = { - .size = htons (sizeof (hdr)), - .type = htons (TALER_HELPER_RSA_MT_REQ_INIT) - }; - ssize_t ret; - - ret = sendto (dh->sock, - &hdr, - sizeof (hdr), - 0, - (const struct sockaddr *) &dh->sa, - sizeof (dh->sa)); - if (ret < 0) - { - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, - "sendto", - dh->sa.sun_path); - do_disconnect (dh); - return; - } - /* We are using SOCK_DGRAM, partial writes should not be possible */ - GNUNET_break (((size_t) ret) == sizeof (hdr)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Successfully sent REQ_INIT\n"); - } - -} - - -struct TALER_CRYPTO_DenominationHelper * -TALER_CRYPTO_helper_denom_connect ( - const struct GNUNET_CONFIGURATION_Handle *cfg, - TALER_CRYPTO_DenominationKeyStatusCallback dkc, - void *dkc_cls) -{ - struct TALER_CRYPTO_DenominationHelper *dh; - char *unixpath; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (cfg, - "taler-helper-crypto-rsa", - "UNIXPATH", - &unixpath)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "taler-helper-crypto-rsa", - "UNIXPATH"); - 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-helper-crypto-rsa", - "UNIXPATH", - "path too long"); - GNUNET_free (unixpath); - return NULL; - } - dh = GNUNET_new (struct TALER_CRYPTO_DenominationHelper); - 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)); - dh->sock = -1; - { - char *tmpdir; - char *template; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (cfg, - "PATHS", - "TALER_RUNTIME_DIR", - &tmpdir)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - "PATHS", - "TALER_RUNTIME_DIR"); - tmpdir = GNUNET_strdup ("/tmp"); - } - GNUNET_asprintf (&template, - "%s/crypto-rsa-client/XXXXXX", - tmpdir); - GNUNET_free (tmpdir); - if (GNUNET_OK != - GNUNET_DISK_directory_create_for_file (template)) - { - GNUNET_free (dh); - GNUNET_free (template); - return NULL; - } - dh->template = template; - } - TALER_CRYPTO_helper_poll (dh); - return dh; -} - - -void -TALER_CRYPTO_helper_poll (struct TALER_CRYPTO_DenominationHelper *dh) -{ - char buf[UINT16_MAX]; - ssize_t ret; - const struct GNUNET_MessageHeader *hdr - = (const struct GNUNET_MessageHeader *) buf; - - try_connect (dh); - if (-1 == dh->sock) - return; /* give up */ - while (1) - { - ret = recv (dh->sock, - buf, - sizeof (buf), - MSG_DONTWAIT); - if (ret < 0) - { - if (EAGAIN == errno) - break; - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, - "recv"); - do_disconnect (dh); - return; - } - - if ( (ret < sizeof (struct GNUNET_MessageHeader)) || - (ret != ntohs (hdr->size)) ) - { - GNUNET_break_op (0); - do_disconnect (dh); - return; - } - switch (ntohs (hdr->type)) - { - case TALER_HELPER_RSA_MT_AVAIL: - { - const struct TALER_CRYPTO_RsaKeyAvailableNotification *kan - = (const struct TALER_CRYPTO_RsaKeyAvailableNotification *) buf; - const char *section_name; - struct TALER_DenominationPublicKey denom_pub; - struct GNUNET_HashCode h_denom_pub; - - if (sizeof (*kan) > ret) - { - GNUNET_break_op (0); - do_disconnect (dh); - return; - } - if (ret != - sizeof (*kan) - + ntohs (kan->pub_size) - + ntohs (kan->section_name_len)) - { - GNUNET_break_op (0); - do_disconnect (dh); - return; - } - if ('\0' != buf[ret - 1]) - { - GNUNET_break_op (0); - do_disconnect (dh); - return; - } - denom_pub.rsa_public_key - = GNUNET_CRYPTO_rsa_public_key_decode (&buf[sizeof (*kan)], - ntohs (kan->pub_size)); - if (NULL == denom_pub.rsa_public_key) - { - GNUNET_break_op (0); - do_disconnect (dh); - return; - } - section_name = &buf[sizeof (*kan) + ntohs (kan->pub_size)]; - GNUNET_CRYPTO_rsa_public_key_hash (denom_pub.rsa_public_key, - &h_denom_pub); - dh->dkc (dh->dkc_cls, - section_name, - GNUNET_TIME_absolute_ntoh (kan->anchor_time), - GNUNET_TIME_relative_ntoh (kan->duration_withdraw), - &h_denom_pub, - &denom_pub); - GNUNET_CRYPTO_rsa_public_key_free (denom_pub.rsa_public_key); - } - break; - case TALER_HELPER_RSA_MT_PURGE: - { - const struct TALER_CRYPTO_RsaKeyPurgeNotification *pn - = (const struct TALER_CRYPTO_RsaKeyPurgeNotification *) buf; - - if (sizeof (*pn) != ret) - { - GNUNET_break_op (0); - do_disconnect (dh); - return; - } - - dh->dkc (dh->dkc_cls, - NULL, - GNUNET_TIME_UNIT_ZERO_ABS, - GNUNET_TIME_UNIT_ZERO, - &pn->h_denom_pub, - NULL); - } - break; - default: - GNUNET_break_op (0); - do_disconnect (dh); - return; - } - } -} - - -struct TALER_DenominationSignature -TALER_CRYPTO_helper_denom_sign ( - struct TALER_CRYPTO_DenominationHelper *dh, - const struct GNUNET_HashCode *h_denom_pub, - const void *msg, - size_t msg_size, - enum TALER_ErrorCode *ec) -{ - struct TALER_DenominationSignature ds = { NULL }; - { - char buf[sizeof (struct TALER_CRYPTO_SignRequest) + msg_size]; - struct TALER_CRYPTO_SignRequest *sr - = (struct TALER_CRYPTO_SignRequest *) buf; - ssize_t ret; - - try_connect (dh); - if (-1 == dh->sock) - { - *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; - return ds; - } - sr->header.size = htons (sizeof (buf)); - sr->header.type = htons (TALER_HELPER_RSA_MT_REQ_SIGN); - sr->reserved = htonl (0); - sr->h_denom_pub = *h_denom_pub; - memcpy (&sr[1], - msg, - msg_size); - ret = sendto (dh->sock, - buf, - sizeof (buf), - 0, - &dh->sa, - sizeof (dh->sa)); - if (ret < 0) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, - "sendto"); - do_disconnect (dh); - *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; - return ds; - } - /* We are using SOCK_DGRAM, partial writes should not be possible */ - GNUNET_break (((size_t) ret) == sizeof (buf)); - } - - { - char buf[UINT16_MAX]; - ssize_t ret; - const struct GNUNET_MessageHeader *hdr - = (const struct GNUNET_MessageHeader *) buf; - - ret = recv (dh->sock, - buf, - sizeof (buf), - 0); - if (ret < 0) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, - "recv"); - do_disconnect (dh); - *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; - return ds; - } - if ( (ret < sizeof (struct GNUNET_MessageHeader)) || - (ret != ntohs (hdr->size)) ) - { - GNUNET_break_op (0); - do_disconnect (dh); - *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; - return ds; - } - switch (ntohs (hdr->type)) - { - case TALER_HELPER_RSA_MT_RES_SIGNATURE: - if (ret < sizeof (struct TALER_CRYPTO_SignResponse)) - { - GNUNET_break_op (0); - do_disconnect (dh); - *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; - break; - } - { - const struct TALER_CRYPTO_SignResponse *sr = - (const struct TALER_CRYPTO_SignResponse *) buf; - struct GNUNET_CRYPTO_RsaSignature *rsa_signature; - - rsa_signature = GNUNET_CRYPTO_rsa_signature_decode (&sr[1], - ret - sizeof (*sr)); - if (NULL == rsa_signature) - { - GNUNET_break_op (0); - do_disconnect (dh); - *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; - break; - } - *ec = TALER_EC_NONE; - ds.rsa_signature = rsa_signature; - return ds; - } - case TALER_HELPER_RSA_MT_RES_SIGN_FAILURE: - if (ret != sizeof (struct TALER_CRYPTO_SignFailure)) - { - GNUNET_break_op (0); - do_disconnect (dh); - *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; - break; - } - { - const struct TALER_CRYPTO_SignFailure *sf = - (const struct TALER_CRYPTO_SignFailure *) buf; - - *ec = (enum TALER_ErrorCode) ntohl (sf->ec); - break; - } - // FIXME: *could* also receive change in key status! - // Handle that here, and then try again! - default: - GNUNET_break_op (0); - do_disconnect (dh); - *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; - break; - } - } - return ds; -} - - -void -TALER_CRYPTO_helper_denom_revoke ( - struct TALER_CRYPTO_DenominationHelper *dh, - const struct GNUNET_HashCode *h_denom_pub) -{ - struct TALER_CRYPTO_RevokeRequest rr = { - .header.size = htons (sizeof (rr)), - .header.type = htons (TALER_HELPER_RSA_MT_REQ_REVOKE), - .h_denom_pub = *h_denom_pub - }; - ssize_t ret; - - try_connect (dh); - if (-1 == dh->sock) - return; /* give up */ - ret = sendto (dh->sock, - &rr, - sizeof (rr), - 0, - (const struct sockaddr *) &dh->sa, - sizeof (dh->sa)); - if (ret < 0) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, - "sendto"); - do_disconnect (dh); - return; - } - /* We are using SOCK_DGRAM, partial writes should not be possible */ - GNUNET_break (((size_t) ret) == sizeof (rr)); -} - - -void -TALER_CRYPTO_helper_denom_disconnect ( - struct TALER_CRYPTO_DenominationHelper *dh) -{ - do_disconnect (dh); - GNUNET_free (dh->template); - GNUNET_free (dh); -} - - -/* end of crypto_helper.c */ diff --git a/src/util/crypto_helper_denom.c b/src/util/crypto_helper_denom.c new file mode 100644 index 000000000..b999be02a --- /dev/null +++ b/src/util/crypto_helper_denom.c @@ -0,0 +1,588 @@ +/* + This file is part of TALER + Copyright (C) 2020 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 +*/ +/** + * @file util/crypto_helper_denom.c + * @brief utility functions for running out-of-process private key operations + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_util.h" +#include "taler-helper-crypto-rsa.h" + + +struct TALER_CRYPTO_DenominationHelper +{ + /** + * Function to call with updates to available key material. + */ + TALER_CRYPTO_DenominationKeyStatusCallback 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; + + /** + * Socket address of this process. + */ + struct sockaddr_un my_sa; + + /** + * Template for @e my_sa. + */ + char *template; + + /** + * The UNIX domain socket, -1 if we are currently not connected. + */ + int sock; +}; + + +/** + * 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 TALER_CRYPTO_DenominationHelper *dh) +{ + GNUNET_break (0 == close (dh->sock)); + if (0 != unlink (dh->my_sa.sun_path)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, + "unlink", + dh->my_sa.sun_path); + dh->sock = -1; +} + + +/** + * Try to connect to the helper process. Updates + * @e sock field in @a dh. + * + * @param[in,out] dh handle to establish connection for + */ +static void +try_connect (struct TALER_CRYPTO_DenominationHelper *dh) +{ + if (-1 != dh->sock) + return; + dh->sock = socket (AF_UNIX, + SOCK_DGRAM, + 0); + if (-1 == dh->sock) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "socket"); + return; + } + { + char *tmpdir; + + tmpdir = GNUNET_DISK_mktemp (dh->template); + if (NULL == tmpdir) + { + do_disconnect (dh); + return; + } + /* we use >= here because we want the sun_path to always + be 0-terminated */ + if (strlen (tmpdir) >= sizeof (dh->sa.sun_path)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + "PATHS", + "TALER_RUNTIME_DIR", + "path too long"); + GNUNET_free (tmpdir); + do_disconnect (dh); + return; + } + dh->my_sa.sun_family = AF_UNIX; + strncpy (dh->my_sa.sun_path, + tmpdir, + sizeof (dh->sa.sun_path)); + if (0 != unlink (tmpdir)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, + "unlink", + tmpdir); + GNUNET_free (tmpdir); + } + if (0 != bind (dh->sock, + (const struct sockaddr *) &dh->my_sa, + sizeof (dh->my_sa))) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "bind"); + do_disconnect (dh); + return; + } + { + struct GNUNET_MessageHeader hdr = { + .size = htons (sizeof (hdr)), + .type = htons (TALER_HELPER_RSA_MT_REQ_INIT) + }; + ssize_t ret; + + ret = sendto (dh->sock, + &hdr, + sizeof (hdr), + 0, + (const struct sockaddr *) &dh->sa, + sizeof (dh->sa)); + if (ret < 0) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, + "sendto", + dh->sa.sun_path); + do_disconnect (dh); + return; + } + /* We are using SOCK_DGRAM, partial writes should not be possible */ + GNUNET_break (((size_t) ret) == sizeof (hdr)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Successfully sent REQ_INIT\n"); + } + +} + + +struct TALER_CRYPTO_DenominationHelper * +TALER_CRYPTO_helper_denom_connect ( + const struct GNUNET_CONFIGURATION_Handle *cfg, + TALER_CRYPTO_DenominationKeyStatusCallback dkc, + void *dkc_cls) +{ + struct TALER_CRYPTO_DenominationHelper *dh; + char *unixpath; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + "taler-helper-crypto-rsa", + "UNIXPATH", + &unixpath)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "taler-helper-crypto-rsa", + "UNIXPATH"); + 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-helper-crypto-rsa", + "UNIXPATH", + "path too long"); + GNUNET_free (unixpath); + return NULL; + } + dh = GNUNET_new (struct TALER_CRYPTO_DenominationHelper); + 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)); + dh->sock = -1; + { + char *tmpdir; + char *template; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + "PATHS", + "TALER_RUNTIME_DIR", + &tmpdir)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, + "PATHS", + "TALER_RUNTIME_DIR"); + tmpdir = GNUNET_strdup ("/tmp"); + } + GNUNET_asprintf (&template, + "%s/crypto-rsa-client/XXXXXX", + tmpdir); + GNUNET_free (tmpdir); + if (GNUNET_OK != + GNUNET_DISK_directory_create_for_file (template)) + { + GNUNET_free (dh); + GNUNET_free (template); + return NULL; + } + dh->template = template; + } + TALER_CRYPTO_helper_poll (dh); + 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 int +handle_mt_avail (struct TALER_CRYPTO_DenominationHelper *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; + + if (sizeof (*kan) > ntohs (hdr->size)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (ntohs (hdr->size) != + sizeof (*kan) + + ntohs (kan->pub_size) + + ntohs (kan->section_name_len)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + section_name = &buf[ntohs (kan->pub_size)]; + if ('\0' != section_name[ntohs (kan->section_name_len) - 1]) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + + { + struct TALER_DenominationPublicKey denom_pub; + struct GNUNET_HashCode h_denom_pub; + + denom_pub.rsa_public_key + = GNUNET_CRYPTO_rsa_public_key_decode (buf, + ntohs (kan->pub_size)); + if (NULL == denom_pub.rsa_public_key) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + GNUNET_CRYPTO_rsa_public_key_hash (denom_pub.rsa_public_key, + &h_denom_pub); + dh->dkc (dh->dkc_cls, + section_name, + GNUNET_TIME_absolute_ntoh (kan->anchor_time), + GNUNET_TIME_relative_ntoh (kan->duration_withdraw), + &h_denom_pub, + &denom_pub); + GNUNET_CRYPTO_rsa_public_key_free (denom_pub.rsa_public_key); + } + 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 int +handle_mt_purge (struct TALER_CRYPTO_DenominationHelper *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; + } + dh->dkc (dh->dkc_cls, + NULL, + GNUNET_TIME_UNIT_ZERO_ABS, + GNUNET_TIME_UNIT_ZERO, + &pn->h_denom_pub, + NULL); + return GNUNET_OK; +} + + +void +TALER_CRYPTO_helper_poll (struct TALER_CRYPTO_DenominationHelper *dh) +{ + char buf[UINT16_MAX]; + ssize_t ret; + const struct GNUNET_MessageHeader *hdr + = (const struct GNUNET_MessageHeader *) buf; + + try_connect (dh); + if (-1 == dh->sock) + return; /* give up */ + while (1) + { + ret = recv (dh->sock, + buf, + sizeof (buf), + MSG_DONTWAIT); + if (ret < 0) + { + if (EAGAIN == errno) + break; + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "recv"); + do_disconnect (dh); + return; + } + + if ( (ret < sizeof (struct GNUNET_MessageHeader)) || + (ret != ntohs (hdr->size)) ) + { + GNUNET_break_op (0); + do_disconnect (dh); + return; + } + 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; + default: + GNUNET_break_op (0); + do_disconnect (dh); + return; + } + } +} + + +struct TALER_DenominationSignature +TALER_CRYPTO_helper_denom_sign ( + struct TALER_CRYPTO_DenominationHelper *dh, + const struct GNUNET_HashCode *h_denom_pub, + const void *msg, + size_t msg_size, + enum TALER_ErrorCode *ec) +{ + struct TALER_DenominationSignature ds = { NULL }; + { + char buf[sizeof (struct TALER_CRYPTO_SignRequest) + msg_size]; + struct TALER_CRYPTO_SignRequest *sr + = (struct TALER_CRYPTO_SignRequest *) buf; + ssize_t ret; + + try_connect (dh); + if (-1 == dh->sock) + { + *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; + return ds; + } + sr->header.size = htons (sizeof (buf)); + sr->header.type = htons (TALER_HELPER_RSA_MT_REQ_SIGN); + sr->reserved = htonl (0); + sr->h_denom_pub = *h_denom_pub; + memcpy (&sr[1], + msg, + msg_size); + ret = sendto (dh->sock, + buf, + sizeof (buf), + 0, + &dh->sa, + sizeof (dh->sa)); + if (ret < 0) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "sendto"); + do_disconnect (dh); + *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; + return ds; + } + /* We are using SOCK_DGRAM, partial writes should not be possible */ + GNUNET_break (((size_t) ret) == sizeof (buf)); + } + + while (1) + { + char buf[UINT16_MAX]; + ssize_t ret; + const struct GNUNET_MessageHeader *hdr + = (const struct GNUNET_MessageHeader *) buf; + + ret = recv (dh->sock, + buf, + sizeof (buf), + 0); + if (ret < 0) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "recv"); + do_disconnect (dh); + *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; + return ds; + } + if ( (ret < sizeof (struct GNUNET_MessageHeader)) || + (ret != ntohs (hdr->size)) ) + { + GNUNET_break_op (0); + do_disconnect (dh); + *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + return ds; + } + switch (ntohs (hdr->type)) + { + case TALER_HELPER_RSA_MT_RES_SIGNATURE: + if (ret < sizeof (struct TALER_CRYPTO_SignResponse)) + { + GNUNET_break_op (0); + do_disconnect (dh); + *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + return ds; + } + { + const struct TALER_CRYPTO_SignResponse *sr = + (const struct TALER_CRYPTO_SignResponse *) buf; + struct GNUNET_CRYPTO_RsaSignature *rsa_signature; + + rsa_signature = GNUNET_CRYPTO_rsa_signature_decode (&sr[1], + ret - sizeof (*sr)); + if (NULL == rsa_signature) + { + GNUNET_break_op (0); + do_disconnect (dh); + *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + return ds; + } + *ec = TALER_EC_NONE; + ds.rsa_signature = rsa_signature; + return ds; + } + case TALER_HELPER_RSA_MT_RES_SIGN_FAILURE: + if (ret != sizeof (struct TALER_CRYPTO_SignFailure)) + { + GNUNET_break_op (0); + do_disconnect (dh); + *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + return ds; + } + { + const struct TALER_CRYPTO_SignFailure *sf = + (const struct TALER_CRYPTO_SignFailure *) buf; + + *ec = (enum TALER_ErrorCode) ntohl (sf->ec); + return ds; + } + case TALER_HELPER_RSA_MT_AVAIL: + if (GNUNET_OK != + handle_mt_avail (dh, + hdr)) + { + GNUNET_break_op (0); + do_disconnect (dh); + *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + return ds; + } + break; /* while(1) loop ensures we recvfrom() again */ + case TALER_HELPER_RSA_MT_PURGE: + if (GNUNET_OK != + handle_mt_purge (dh, + hdr)) + { + GNUNET_break_op (0); + do_disconnect (dh); + *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + return ds; + } + break; /* while(1) loop ensures we recvfrom() again */ + default: + GNUNET_break_op (0); + do_disconnect (dh); + *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; + return ds; + } + } +} + + +void +TALER_CRYPTO_helper_denom_revoke ( + struct TALER_CRYPTO_DenominationHelper *dh, + const struct GNUNET_HashCode *h_denom_pub) +{ + struct TALER_CRYPTO_RevokeRequest rr = { + .header.size = htons (sizeof (rr)), + .header.type = htons (TALER_HELPER_RSA_MT_REQ_REVOKE), + .h_denom_pub = *h_denom_pub + }; + ssize_t ret; + + try_connect (dh); + if (-1 == dh->sock) + return; /* give up */ + ret = sendto (dh->sock, + &rr, + sizeof (rr), + 0, + (const struct sockaddr *) &dh->sa, + sizeof (dh->sa)); + if (ret < 0) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "sendto"); + do_disconnect (dh); + return; + } + /* We are using SOCK_DGRAM, partial writes should not be possible */ + GNUNET_break (((size_t) ret) == sizeof (rr)); +} + + +void +TALER_CRYPTO_helper_denom_disconnect ( + struct TALER_CRYPTO_DenominationHelper *dh) +{ + do_disconnect (dh); + GNUNET_free (dh->template); + GNUNET_free (dh); +} + + +/* end of crypto_helper_denom.c */ diff --git a/src/util/taler-helper-crypto-rsa.c b/src/util/taler-helper-crypto-rsa.c index 6fda5fec1..abd8014fd 100644 --- a/src/util/taler-helper-crypto-rsa.c +++ b/src/util/taler-helper-crypto-rsa.c @@ -551,6 +551,21 @@ handle_done (void *cls) done_tail, wi); GNUNET_assert (0 == pthread_mutex_unlock (&done_lock)); + if (NULL == wi->rsa_signature) + { + struct TALER_CRYPTO_SignFailure sf = { + .header.size = htons (sizeof (sf)), + .header.type = htons (TALER_HELPER_RSA_MT_RES_SIGN_FAILURE), + .ec = htonl (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE) + }; + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Signing request failed, worker failed to produce signature\n"); + (void) transmit (&wi->addr, + wi->addr_size, + &sf.header); + } + else { struct TALER_CRYPTO_SignResponse *sr; void *buf; @@ -598,7 +613,7 @@ handle_sign_request (const struct sockaddr_un *addr, struct DenominationKey *dk; struct WorkItem *wi; const void *blinded_msg = &sr[1]; - size_t blinded_msg_size = ntohs (sr->header.size) - sizeof (sr); + size_t blinded_msg_size = ntohs (sr->header.size) - sizeof (*sr); dk = GNUNET_CONTAINER_multihashmap_get (keys, &sr->h_denom_pub); @@ -618,9 +633,29 @@ handle_sign_request (const struct sockaddr_un *addr, &sf.header); return; } - // FIXME: check denomination key is valid for signing - // at this time! + if (0 != + GNUNET_TIME_absolute_get_remaining (dk->anchor).rel_value_us) + { + /* it is too early */ + struct TALER_CRYPTO_SignFailure sf = { + .header.size = htons (sizeof (sr)), + .header.type = htons (TALER_HELPER_RSA_MT_RES_SIGN_FAILURE), + .ec = htonl (TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY) + }; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Signing request failed, denomination key %s is not yet valid\n", + GNUNET_h2s (&sr->h_denom_pub)); + (void) transmit (addr, + addr_size, + &sf.header); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Received request to sign over %u bytes with key %s\n", + (unsigned int) blinded_msg_size, + GNUNET_h2s (&sr->h_denom_pub)); wi = GNUNET_new (struct WorkItem); wi->addr = *addr; wi->addr_size = addr_size; @@ -1038,11 +1073,13 @@ create_key (struct Denomination *denom) { struct DenominationKey *dk; struct GNUNET_TIME_Absolute anchor; + struct GNUNET_TIME_Absolute now; + now = GNUNET_TIME_absolute_get (); + (void) GNUNET_TIME_round_abs (&now); if (NULL == denom->keys_tail) { - anchor = GNUNET_TIME_absolute_get (); - (void) GNUNET_TIME_round_abs (&anchor); + anchor = now; } else { @@ -1050,6 +1087,8 @@ create_key (struct Denomination *denom) GNUNET_TIME_relative_subtract ( denom->duration_withdraw, overlap_duration)); + if (now.abs_value_us > anchor.abs_value_us) + anchor = now; } dk = GNUNET_new (struct DenominationKey); dk->denom = denom; diff --git a/src/util/test_helper_rsa.c b/src/util/test_helper_rsa.c index 14b3c4a56..2b6c850f8 100644 --- a/src/util/test_helper_rsa.c +++ b/src/util/test_helper_rsa.c @@ -33,6 +33,11 @@ */ #define NUM_REVOKES 10 +/** + * How many iterations of the successful signing test should we run? + */ +#define NUM_SIGN_TESTS 100 + /** * Number of keys currently in #keys. @@ -189,7 +194,7 @@ test_revocation (struct TALER_CRYPTO_DenominationHelper *dh) GNUNET_h2s (&keys[j].h_denom_pub)); TALER_CRYPTO_helper_denom_revoke (dh, &keys[j].h_denom_pub); - for (unsigned int k = 0; k<80; k++) + for (unsigned int k = 0; k<1000; k++) { TALER_CRYPTO_helper_poll (dh); if (! keys[j].revoked) @@ -205,6 +210,7 @@ test_revocation (struct TALER_CRYPTO_DenominationHelper *dh) TALER_CRYPTO_helper_denom_disconnect (dh); return 2; } + fprintf (stderr, "\n"); break; } } @@ -225,7 +231,11 @@ test_signing (struct TALER_CRYPTO_DenominationHelper *dh) enum TALER_ErrorCode ec; bool success = false; struct GNUNET_HashCode m_hash; + struct GNUNET_CRYPTO_RsaBlindingKeySecret bks; + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, + &bks, + sizeof (bks)); GNUNET_CRYPTO_hash ("Hello", strlen ("Hello"), &m_hash); @@ -233,11 +243,26 @@ test_signing (struct TALER_CRYPTO_DenominationHelper *dh) { if (! keys[i].valid) continue; - ds = TALER_CRYPTO_helper_denom_sign (dh, - &keys[i].h_denom_pub, - &m_hash, - sizeof (m_hash), - &ec); + { + void *buf; + size_t buf_size; + GNUNET_assert (GNUNET_YES == + GNUNET_CRYPTO_rsa_blind (&m_hash, + &bks, + keys[i].denom_pub.rsa_public_key, + &buf, + &buf_size)); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Requesting signature over %u bytes with key %s\n", + (unsigned int) buf_size, + GNUNET_h2s (&keys[i].h_denom_pub)); + ds = TALER_CRYPTO_helper_denom_sign (dh, + &keys[i].h_denom_pub, + buf, + buf_size, + &ec); + GNUNET_free (buf); + } switch (ec) { case TALER_EC_NONE: @@ -255,21 +280,38 @@ test_signing (struct TALER_CRYPTO_DenominationHelper *dh) GNUNET_break (0); return 5; } - if (GNUNET_OK != - GNUNET_CRYPTO_rsa_verify (&m_hash, - ds.rsa_signature, - keys[i].denom_pub.rsa_public_key)) { - /* signature invalid */ - GNUNET_break (0); + struct GNUNET_CRYPTO_RsaSignature *rs; + + rs = GNUNET_CRYPTO_rsa_unblind (ds.rsa_signature, + &bks, + keys[i].denom_pub.rsa_public_key); + if (NULL == rs) + { + GNUNET_break (0); + return 6; + } GNUNET_CRYPTO_rsa_signature_free (ds.rsa_signature); - return 6; + if (GNUNET_OK != + GNUNET_CRYPTO_rsa_verify (&m_hash, + rs, + keys[i].denom_pub.rsa_public_key)) + { + /* signature invalid */ + GNUNET_break (0); + GNUNET_CRYPTO_rsa_signature_free (rs); + return 7; + } + GNUNET_CRYPTO_rsa_signature_free (rs); } - GNUNET_CRYPTO_rsa_signature_free (ds.rsa_signature); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Received valid signature for key %s\n", + GNUNET_h2s (&keys[i].h_denom_pub)); success = true; break; -#if FIXME - case TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_INVALID: + case TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY: + /* This 'failure' is expected, we're testing also for the + error handling! */ if ( (0 == GNUNET_TIME_absolute_get_remaining ( keys[i].start_time).rel_value_us) && @@ -282,7 +324,6 @@ test_signing (struct TALER_CRYPTO_DenominationHelper *dh) return 6; } break; -#endif default: /* unexpected error */ GNUNET_break (0); @@ -313,11 +354,94 @@ test_signing (struct TALER_CRYPTO_DenominationHelper *dh) GNUNET_break (0); return 17; } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Signing with invalid key %s failed as desired\n", + GNUNET_h2s (&rnd)); } return 0; } +/** + * Benchmark signing logic. + * + * @param dh handle to the helper + * @return 0 on success + */ +static int +perf_signing (struct TALER_CRYPTO_DenominationHelper *dh) +{ + struct TALER_DenominationSignature ds; + enum TALER_ErrorCode ec; + bool success = false; + struct GNUNET_HashCode m_hash; + struct GNUNET_CRYPTO_RsaBlindingKeySecret bks; + struct GNUNET_TIME_Relative duration; + + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, + &bks, + sizeof (bks)); + GNUNET_CRYPTO_hash ("Hello", + strlen ("Hello"), + &m_hash); + duration = GNUNET_TIME_UNIT_ZERO; + for (unsigned int j = 0; j + GNUNET_TIME_UNIT_SECONDS.rel_value_us) + continue; + if (GNUNET_TIME_absolute_get_duration (keys[i].start_time).rel_value_us > + keys[i].validity_duration.rel_value_us) + continue; + { + void *buf; + size_t buf_size; + + GNUNET_assert (GNUNET_YES == + GNUNET_CRYPTO_rsa_blind (&m_hash, + &bks, + keys[i].denom_pub.rsa_public_key, + &buf, + &buf_size)); + /* use this key as long as it works */ + while (1) + { + struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get (); + struct GNUNET_TIME_Relative delay; + + ds = TALER_CRYPTO_helper_denom_sign (dh, + &keys[i].h_denom_pub, + buf, + buf_size, + &ec); + if (TALER_EC_NONE != ec) + break; + delay = GNUNET_TIME_absolute_get_duration (start); + duration = GNUNET_TIME_relative_add (duration, + delay); + GNUNET_CRYPTO_rsa_signature_free (ds.rsa_signature); + j++; + if (NUM_SIGN_TESTS == j) + break; + } + GNUNET_free (buf); + } + } /* for i */ + } /* for j */ + fprintf (stderr, + "%u (sequential) signature operations took %s\n", + (unsigned int) NUM_SIGN_TESTS, + GNUNET_STRINGS_relative_time_to_string (duration, + GNUNET_YES)); + return 0; +} + + /** * Main entry point into the test logic with the helper already running. */ @@ -350,7 +474,7 @@ run_test (void) } /* wait for helper to start and give us keys */ fprintf (stderr, "Waiting for helper to start "); - for (unsigned int i = 0; i<80; i++) + for (unsigned int i = 0; i<1000; i++) { TALER_CRYPTO_helper_poll (dh); if (0 != num_keys) @@ -370,15 +494,12 @@ run_test (void) num_keys); ret = 0; -#if 1 if (0 == ret) ret = test_revocation (dh); -#endif -#if 0 if (0 == ret) ret = test_signing (dh); -#endif - + if (0 == ret) + ret = perf_signing (dh); TALER_CRYPTO_helper_denom_disconnect (dh); /* clean up our state */ for (unsigned int i = 0; i