LCOV - code coverage report
Current view: top level - util - crypto_helper_cs.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 417 679 61.4 %
Date: 2025-06-05 21:03:14 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2020, 2021, 2022 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU General Public License as published by the Free Software
       7             :   Foundation; either version 3, or (at your option) any later version.
       8             : 
       9             :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10             :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11             :   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU General Public License along with
      14             :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : /**
      17             :  * @file util/crypto_helper_cs.c
      18             :  * @brief utility functions for running out-of-process private key operations
      19             :  * @author Christian Grothoff
      20             :  */
      21             : #include "platform.h"
      22             : #include "taler_util.h"
      23             : #include "taler_signatures.h"
      24             : #include "secmod_cs.h"
      25             : #include <poll.h>
      26             : #include "crypto_helper_common.h"
      27             : 
      28             : 
      29             : struct TALER_CRYPTO_CsDenominationHelper
      30             : {
      31             :   /**
      32             :    * Function to call with updates to available key material.
      33             :    */
      34             :   TALER_CRYPTO_CsDenominationKeyStatusCallback dkc;
      35             : 
      36             :   /**
      37             :    * Closure for @e dkc
      38             :    */
      39             :   void *dkc_cls;
      40             : 
      41             :   /**
      42             :    * Socket address of the denomination helper process.
      43             :    * Used to reconnect if the connection breaks.
      44             :    */
      45             :   struct sockaddr_un sa;
      46             : 
      47             :   /**
      48             :    * The UNIX domain socket, -1 if we are currently not connected.
      49             :    */
      50             :   int sock;
      51             : 
      52             :   /**
      53             :    * Have we ever been sync'ed?
      54             :    */
      55             :   bool synced;
      56             : };
      57             : 
      58             : 
      59             : /**
      60             :  * Disconnect from the helper process.  Updates
      61             :  * @e sock field in @a dh.
      62             :  *
      63             :  * @param[in,out] dh handle to tear down connection of
      64             :  */
      65             : static void
      66          38 : do_disconnect (struct TALER_CRYPTO_CsDenominationHelper *dh)
      67             : {
      68          38 :   GNUNET_break (0 == close (dh->sock));
      69          38 :   dh->sock = -1;
      70          38 :   dh->synced = false;
      71          38 : }
      72             : 
      73             : 
      74             : /**
      75             :  * Try to connect to the helper process.  Updates
      76             :  * @e sock field in @a dh.
      77             :  *
      78             :  * @param[in,out] dh handle to establish connection for
      79             :  * @return #GNUNET_OK on success
      80             :  */
      81             : static enum GNUNET_GenericReturnValue
      82        2062 : try_connect (struct TALER_CRYPTO_CsDenominationHelper *dh)
      83             : {
      84        2062 :   if (-1 != dh->sock)
      85        2024 :     return GNUNET_OK;
      86          38 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
      87             :               "Establishing connection!\n");
      88          38 :   dh->sock = socket (AF_UNIX,
      89             :                      SOCK_STREAM,
      90             :                      0);
      91          38 :   if (-1 == dh->sock)
      92             :   {
      93           0 :     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
      94             :                          "socket");
      95           0 :     return GNUNET_SYSERR;
      96             :   }
      97          38 :   if (0 !=
      98          38 :       connect (dh->sock,
      99          38 :                (const struct sockaddr *) &dh->sa,
     100             :                sizeof (dh->sa)))
     101             :   {
     102           0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
     103             :                               "connect",
     104             :                               dh->sa.sun_path);
     105           0 :     do_disconnect (dh);
     106           0 :     return GNUNET_SYSERR;
     107             :   }
     108          38 :   TALER_CRYPTO_helper_cs_poll (dh);
     109          38 :   return GNUNET_OK;
     110             : }
     111             : 
     112             : 
     113             : struct TALER_CRYPTO_CsDenominationHelper *
     114          38 : TALER_CRYPTO_helper_cs_connect (
     115             :   const struct GNUNET_CONFIGURATION_Handle *cfg,
     116             :   const char *section,
     117             :   TALER_CRYPTO_CsDenominationKeyStatusCallback dkc,
     118             :   void *dkc_cls)
     119             : {
     120             :   struct TALER_CRYPTO_CsDenominationHelper *dh;
     121             :   char *unixpath;
     122             :   char *secname;
     123             : 
     124          38 :   GNUNET_asprintf (&secname,
     125             :                    "%s-secmod-cs",
     126             :                    section);
     127          38 :   if (GNUNET_OK !=
     128          38 :       GNUNET_CONFIGURATION_get_value_filename (cfg,
     129             :                                                secname,
     130             :                                                "UNIXPATH",
     131             :                                                &unixpath))
     132             :   {
     133           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     134             :                                secname,
     135             :                                "UNIXPATH");
     136           0 :     GNUNET_free (secname);
     137           0 :     return NULL;
     138             :   }
     139             :   /* we use >= here because we want the sun_path to always
     140             :      be 0-terminated */
     141          38 :   if (strlen (unixpath) >= sizeof (dh->sa.sun_path))
     142             :   {
     143           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     144             :                                secname,
     145             :                                "UNIXPATH",
     146             :                                "path too long");
     147           0 :     GNUNET_free (unixpath);
     148           0 :     GNUNET_free (secname);
     149           0 :     return NULL;
     150             :   }
     151          38 :   GNUNET_free (secname);
     152          38 :   dh = GNUNET_new (struct TALER_CRYPTO_CsDenominationHelper);
     153          38 :   dh->dkc = dkc;
     154          38 :   dh->dkc_cls = dkc_cls;
     155          38 :   dh->sa.sun_family = AF_UNIX;
     156          38 :   strncpy (dh->sa.sun_path,
     157             :            unixpath,
     158             :            sizeof (dh->sa.sun_path) - 1);
     159          38 :   GNUNET_free (unixpath);
     160          38 :   dh->sock = -1;
     161          38 :   if (GNUNET_OK !=
     162          38 :       try_connect (dh))
     163             :   {
     164           0 :     TALER_CRYPTO_helper_cs_disconnect (dh);
     165           0 :     return NULL;
     166             :   }
     167          38 :   return dh;
     168             : }
     169             : 
     170             : 
     171             : /**
     172             :  * Handle a #TALER_HELPER_CS_MT_AVAIL message from the helper.
     173             :  *
     174             :  * @param dh helper context
     175             :  * @param hdr message that we received
     176             :  * @return #GNUNET_OK on success
     177             :  */
     178             : static enum GNUNET_GenericReturnValue
     179        2744 : handle_mt_avail (struct TALER_CRYPTO_CsDenominationHelper *dh,
     180             :                  const struct GNUNET_MessageHeader *hdr)
     181             : {
     182        2744 :   const struct TALER_CRYPTO_CsKeyAvailableNotification *kan
     183             :     = (const struct TALER_CRYPTO_CsKeyAvailableNotification *) hdr;
     184        2744 :   const char *buf = (const char *) &kan[1];
     185             :   const char *section_name;
     186             :   uint16_t snl;
     187             : 
     188        2744 :   if (sizeof (*kan) > ntohs (hdr->size))
     189             :   {
     190           0 :     GNUNET_break_op (0);
     191           0 :     return GNUNET_SYSERR;
     192             :   }
     193        2744 :   snl = ntohs (kan->section_name_len);
     194        2744 :   if (ntohs (hdr->size) != sizeof (*kan) + snl)
     195             :   {
     196           0 :     GNUNET_break_op (0);
     197           0 :     return GNUNET_SYSERR;
     198             :   }
     199        2744 :   if (0 == snl)
     200             :   {
     201           0 :     GNUNET_break_op (0);
     202           0 :     return GNUNET_SYSERR;
     203             :   }
     204        2744 :   section_name = buf;
     205        2744 :   if ('\0' != section_name[snl - 1])
     206             :   {
     207           0 :     GNUNET_break_op (0);
     208           0 :     return GNUNET_SYSERR;
     209             :   }
     210             : 
     211             :   {
     212             :     struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
     213             :     struct TALER_CsPubHashP h_cs;
     214             : 
     215        2744 :     bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
     216        2744 :     bsign_pub->cipher = GNUNET_CRYPTO_BSA_CS;
     217        2744 :     bsign_pub->rc = 1;
     218        2744 :     bsign_pub->details.cs_public_key = kan->denom_pub;
     219             : 
     220        2744 :     GNUNET_CRYPTO_hash (&bsign_pub->details.cs_public_key,
     221             :                         sizeof (bsign_pub->details.cs_public_key),
     222             :                         &bsign_pub->pub_key_hash);
     223        2744 :     h_cs.hash = bsign_pub->pub_key_hash;
     224        2744 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     225             :                 "Received CS key %s (%s)\n",
     226             :                 GNUNET_h2s (&h_cs.hash),
     227             :                 section_name);
     228        2744 :     if (GNUNET_OK !=
     229        2744 :         TALER_exchange_secmod_cs_verify (
     230             :           &h_cs,
     231             :           section_name,
     232             :           GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
     233             :           GNUNET_TIME_relative_ntoh (kan->duration_withdraw),
     234             :           &kan->secm_pub,
     235             :           &kan->secm_sig))
     236             :     {
     237           0 :       GNUNET_break_op (0);
     238           0 :       GNUNET_CRYPTO_blind_sign_pub_decref (bsign_pub);
     239           0 :       return GNUNET_SYSERR;
     240             :     }
     241        2744 :     dh->dkc (dh->dkc_cls,
     242             :              section_name,
     243             :              GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
     244             :              GNUNET_TIME_relative_ntoh (kan->duration_withdraw),
     245             :              &h_cs,
     246             :              bsign_pub,
     247             :              &kan->secm_pub,
     248             :              &kan->secm_sig);
     249        2744 :     GNUNET_CRYPTO_blind_sign_pub_decref (bsign_pub);
     250             :   }
     251        2744 :   return GNUNET_OK;
     252             : }
     253             : 
     254             : 
     255             : /**
     256             :  * Handle a #TALER_HELPER_CS_MT_PURGE message from the helper.
     257             :  *
     258             :  * @param dh helper context
     259             :  * @param hdr message that we received
     260             :  * @return #GNUNET_OK on success
     261             :  */
     262             : static enum GNUNET_GenericReturnValue
     263           3 : handle_mt_purge (struct TALER_CRYPTO_CsDenominationHelper *dh,
     264             :                  const struct GNUNET_MessageHeader *hdr)
     265             : {
     266           3 :   const struct TALER_CRYPTO_CsKeyPurgeNotification *pn
     267             :     = (const struct TALER_CRYPTO_CsKeyPurgeNotification *) hdr;
     268             : 
     269           3 :   if (sizeof (*pn) != ntohs (hdr->size))
     270             :   {
     271           0 :     GNUNET_break_op (0);
     272           0 :     return GNUNET_SYSERR;
     273             :   }
     274           3 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     275             :               "Received revocation of denomination key %s\n",
     276             :               GNUNET_h2s (&pn->h_cs.hash));
     277           3 :   dh->dkc (dh->dkc_cls,
     278             :            NULL,
     279           3 :            GNUNET_TIME_UNIT_ZERO_TS,
     280           3 :            GNUNET_TIME_UNIT_ZERO,
     281             :            &pn->h_cs,
     282             :            NULL,
     283             :            NULL,
     284             :            NULL);
     285           3 :   return GNUNET_OK;
     286             : }
     287             : 
     288             : 
     289             : void
     290         905 : TALER_CRYPTO_helper_cs_poll (struct TALER_CRYPTO_CsDenominationHelper *dh)
     291             : {
     292             :   char buf[UINT16_MAX];
     293         905 :   size_t off = 0;
     294         905 :   unsigned int retry_limit = 3;
     295         905 :   const struct GNUNET_MessageHeader *hdr
     296             :     = (const struct GNUNET_MessageHeader *) buf;
     297             : 
     298         905 :   if (GNUNET_OK !=
     299         905 :       try_connect (dh))
     300           0 :     return; /* give up */
     301             :   while (1)
     302          49 :   {
     303             :     uint16_t msize;
     304             :     ssize_t ret;
     305             : 
     306         954 :     ret = recv (dh->sock,
     307             :                 buf + off,
     308             :                 sizeof (buf) - off,
     309         954 :                 (dh->synced && (0 == off))
     310             :                 ? MSG_DONTWAIT
     311             :                 : 0);
     312         954 :     if (ret < 0)
     313             :     {
     314         905 :       if (EINTR == errno)
     315           0 :         continue;
     316         905 :       if (EAGAIN == errno)
     317             :       {
     318         905 :         GNUNET_assert (dh->synced);
     319         905 :         GNUNET_assert (0 == off);
     320         905 :         break;
     321             :       }
     322           0 :       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
     323             :                            "recv");
     324           0 :       do_disconnect (dh);
     325           0 :       if (0 == retry_limit)
     326           0 :         return; /* give up */
     327           0 :       if (GNUNET_OK !=
     328           0 :           try_connect (dh))
     329           0 :         return; /* give up */
     330           0 :       retry_limit--;
     331           0 :       continue;
     332             :     }
     333          49 :     if (0 == ret)
     334             :     {
     335           0 :       GNUNET_break (0 == off);
     336           0 :       return;
     337             :     }
     338          49 :     off += ret;
     339        2834 : more:
     340        2834 :     if (off < sizeof (struct GNUNET_MessageHeader))
     341          44 :       continue;
     342        2790 :     msize = ntohs (hdr->size);
     343        2790 :     if (off < msize)
     344           5 :       continue;
     345        2785 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     346             :                 "Received message of type %u and length %u\n",
     347             :                 (unsigned int) ntohs (hdr->type),
     348             :                 (unsigned int) msize);
     349        2785 :     switch (ntohs (hdr->type))
     350             :     {
     351        2744 :     case TALER_HELPER_CS_MT_AVAIL:
     352        2744 :       if (GNUNET_OK !=
     353        2744 :           handle_mt_avail (dh,
     354             :                            hdr))
     355             :       {
     356           0 :         GNUNET_break_op (0);
     357           0 :         do_disconnect (dh);
     358           0 :         return;
     359             :       }
     360        2744 :       break;
     361           3 :     case TALER_HELPER_CS_MT_PURGE:
     362           3 :       if (GNUNET_OK !=
     363           3 :           handle_mt_purge (dh,
     364             :                            hdr))
     365             :       {
     366           0 :         GNUNET_break_op (0);
     367           0 :         do_disconnect (dh);
     368           0 :         return;
     369             :       }
     370           3 :       break;
     371          38 :     case TALER_HELPER_CS_SYNCED:
     372          38 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     373             :                   "Now synchronized with CS helper\n");
     374          38 :       dh->synced = true;
     375          38 :       break;
     376           0 :     default:
     377           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     378             :                   "Received unexpected message of type %d (len: %u)\n",
     379             :                   (unsigned int) ntohs (hdr->type),
     380             :                   (unsigned int) msize);
     381           0 :       GNUNET_break_op (0);
     382           0 :       do_disconnect (dh);
     383           0 :       return;
     384             :     }
     385        2785 :     memmove (buf,
     386        2785 :              &buf[msize],
     387             :              off - msize);
     388        2785 :     off -= msize;
     389        2785 :     goto more;
     390             :   }
     391             : }
     392             : 
     393             : 
     394             : enum TALER_ErrorCode
     395         902 : TALER_CRYPTO_helper_cs_sign (
     396             :   struct TALER_CRYPTO_CsDenominationHelper *dh,
     397             :   const struct TALER_CRYPTO_CsSignRequest *req,
     398             :   bool for_melt,
     399             :   struct TALER_BlindedDenominationSignature *bs)
     400             : {
     401         902 :   enum TALER_ErrorCode ec = TALER_EC_INVALID;
     402         902 :   const struct TALER_CsPubHashP *h_cs = req->h_cs;
     403             : 
     404         902 :   memset (bs,
     405             :           0,
     406             :           sizeof (*bs));
     407         902 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     408             :               "Starting signature process\n");
     409         902 :   if (GNUNET_OK !=
     410         902 :       try_connect (dh))
     411             :   {
     412           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     413             :                 "Failed to connect to helper\n");
     414           0 :     return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
     415             :   }
     416             : 
     417         902 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     418             :               "Requesting signature\n");
     419             :   {
     420             :     char buf[sizeof (struct TALER_CRYPTO_CsSignRequestMessage)];
     421         902 :     struct TALER_CRYPTO_CsSignRequestMessage *sr
     422             :       = (struct TALER_CRYPTO_CsSignRequestMessage *) buf;
     423             : 
     424         902 :     sr->header.size = htons (sizeof (buf));
     425         902 :     sr->header.type = htons (TALER_HELPER_CS_MT_REQ_SIGN);
     426         902 :     sr->for_melt = htonl (for_melt ? 1 : 0);
     427         902 :     sr->h_cs = *h_cs;
     428         902 :     sr->message = *req->blinded_planchet;
     429         902 :     if (GNUNET_OK !=
     430         902 :         TALER_crypto_helper_send_all (dh->sock,
     431             :                                       buf,
     432             :                                       sizeof (buf)))
     433             :     {
     434           0 :       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
     435             :                            "send");
     436           0 :       do_disconnect (dh);
     437           0 :       return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
     438             :     }
     439             :   }
     440             : 
     441         902 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     442             :               "Awaiting reply\n");
     443             :   {
     444             :     char buf[UINT16_MAX];
     445         902 :     size_t off = 0;
     446         902 :     const struct GNUNET_MessageHeader *hdr
     447             :       = (const struct GNUNET_MessageHeader *) buf;
     448         902 :     bool finished = false;
     449             : 
     450             :     while (1)
     451         902 :     {
     452             :       uint16_t msize;
     453             :       ssize_t ret;
     454             : 
     455        2706 :       ret = recv (dh->sock,
     456        1804 :                   &buf[off],
     457             :                   sizeof (buf) - off,
     458         902 :                   (finished && (0 == off))
     459             :                   ? MSG_DONTWAIT
     460             :                   : 0);
     461        1804 :       if (ret < 0)
     462             :       {
     463         902 :         if (EINTR == errno)
     464           0 :           continue;
     465         902 :         if (EAGAIN == errno)
     466             :         {
     467         902 :           GNUNET_assert (finished);
     468         902 :           GNUNET_assert (0 == off);
     469         902 :           return ec;
     470             :         }
     471           0 :         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
     472             :                              "recv");
     473           0 :         do_disconnect (dh);
     474           0 :         ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
     475           0 :         break;
     476             :       }
     477         902 :       if (0 == ret)
     478             :       {
     479           0 :         GNUNET_break (0 == off);
     480           0 :         if (! finished)
     481           0 :           ec = TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
     482           0 :         return ec;
     483             :       }
     484         902 :       off += ret;
     485        1804 : more:
     486        1804 :       if (off < sizeof (struct GNUNET_MessageHeader))
     487         902 :         continue;
     488         902 :       msize = ntohs (hdr->size);
     489         902 :       if (off < msize)
     490           0 :         continue;
     491         902 :       switch (ntohs (hdr->type))
     492             :       {
     493         901 :       case TALER_HELPER_CS_MT_RES_SIGNATURE:
     494         901 :         if (msize != sizeof (struct TALER_CRYPTO_SignResponse))
     495             :         {
     496           0 :           GNUNET_break_op (0);
     497           0 :           do_disconnect (dh);
     498           0 :           ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     499           0 :           goto end;
     500             :         }
     501         901 :         if (finished)
     502             :         {
     503           0 :           GNUNET_break_op (0);
     504           0 :           do_disconnect (dh);
     505           0 :           ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     506           0 :           goto end;
     507             :         }
     508             :         {
     509         901 :           const struct TALER_CRYPTO_SignResponse *sr =
     510             :             (const struct TALER_CRYPTO_SignResponse *) buf;
     511             :           struct GNUNET_CRYPTO_BlindedSignature *blinded_sig;
     512             : 
     513         901 :           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     514             :                       "Received signature\n");
     515         901 :           ec = TALER_EC_NONE;
     516         901 :           finished = true;
     517         901 :           blinded_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
     518         901 :           blinded_sig->cipher = GNUNET_CRYPTO_BSA_CS;
     519         901 :           blinded_sig->rc = 1;
     520         901 :           blinded_sig->details.blinded_cs_answer.b = ntohl (sr->b);
     521         901 :           blinded_sig->details.blinded_cs_answer.s_scalar = sr->cs_answer;
     522         901 :           bs->blinded_sig = blinded_sig;
     523         901 :           break;
     524             :         }
     525           1 :       case TALER_HELPER_CS_MT_RES_SIGN_FAILURE:
     526           1 :         if (msize != sizeof (struct TALER_CRYPTO_SignFailure))
     527             :         {
     528           0 :           GNUNET_break_op (0);
     529           0 :           do_disconnect (dh);
     530           0 :           ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     531           0 :           goto end;
     532             :         }
     533             :         {
     534           1 :           const struct TALER_CRYPTO_SignFailure *sf =
     535             :             (const struct TALER_CRYPTO_SignFailure *) buf;
     536             : 
     537           1 :           ec = (enum TALER_ErrorCode) (int) ntohl (sf->ec);
     538           1 :           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     539             :                       "Signing failed with status %d!\n",
     540             :                       ec);
     541           1 :           finished = true;
     542           1 :           break;
     543             :         }
     544           0 :       case TALER_HELPER_CS_MT_AVAIL:
     545           0 :         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     546             :                     "Received new key!\n");
     547           0 :         if (GNUNET_OK !=
     548           0 :             handle_mt_avail (dh,
     549             :                              hdr))
     550             :         {
     551           0 :           GNUNET_break_op (0);
     552           0 :           do_disconnect (dh);
     553           0 :           ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     554           0 :           goto end;
     555             :         }
     556           0 :         break; /* while(1) loop ensures we recvfrom() again */
     557           0 :       case TALER_HELPER_CS_MT_PURGE:
     558           0 :         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     559             :                     "Received revocation!\n");
     560           0 :         if (GNUNET_OK !=
     561           0 :             handle_mt_purge (dh,
     562             :                              hdr))
     563             :         {
     564           0 :           GNUNET_break_op (0);
     565           0 :           do_disconnect (dh);
     566           0 :           ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     567           0 :           goto end;
     568             :         }
     569           0 :         break; /* while(1) loop ensures we recvfrom() again */
     570           0 :       case TALER_HELPER_CS_SYNCED:
     571           0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     572             :                     "Synchronized add odd time with CS helper!\n");
     573           0 :         dh->synced = true;
     574           0 :         break;
     575           0 :       default:
     576           0 :         GNUNET_break_op (0);
     577           0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     578             :                     "Received unexpected message of type %u\n",
     579             :                     ntohs (hdr->type));
     580           0 :         do_disconnect (dh);
     581           0 :         ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     582           0 :         goto end;
     583             :       }
     584         902 :       memmove (buf,
     585         902 :                &buf[msize],
     586             :                off - msize);
     587         902 :       off -= msize;
     588         902 :       goto more;
     589             :     } /* while(1) */
     590           0 : end:
     591           0 :     if (finished)
     592           0 :       TALER_blinded_denom_sig_free (bs);
     593           0 :     return ec;
     594             :   }
     595             : }
     596             : 
     597             : 
     598             : void
     599           3 : TALER_CRYPTO_helper_cs_revoke (
     600             :   struct TALER_CRYPTO_CsDenominationHelper *dh,
     601             :   const struct TALER_CsPubHashP *h_cs)
     602             : {
     603           3 :   struct TALER_CRYPTO_CsRevokeRequest rr = {
     604           3 :     .header.size = htons (sizeof (rr)),
     605           3 :     .header.type = htons (TALER_HELPER_CS_MT_REQ_REVOKE),
     606             :     .h_cs = *h_cs
     607             :   };
     608             : 
     609           3 :   if (GNUNET_OK !=
     610           3 :       try_connect (dh))
     611           0 :     return; /* give up */
     612           3 :   if (GNUNET_OK !=
     613           3 :       TALER_crypto_helper_send_all (dh->sock,
     614             :                                     &rr,
     615             :                                     sizeof (rr)))
     616             :   {
     617           0 :     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
     618             :                          "send");
     619           0 :     do_disconnect (dh);
     620           0 :     return;
     621             :   }
     622           3 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     623             :               "Requested revocation of denomination key %s\n",
     624             :               GNUNET_h2s (&h_cs->hash));
     625             : }
     626             : 
     627             : 
     628             : enum TALER_ErrorCode
     629          22 : TALER_CRYPTO_helper_cs_r_derive (struct TALER_CRYPTO_CsDenominationHelper *dh,
     630             :                                  const struct TALER_CRYPTO_CsDeriveRequest *cdr,
     631             :                                  bool for_melt,
     632             :                                  struct GNUNET_CRYPTO_CSPublicRPairP *crp)
     633             : {
     634          22 :   enum TALER_ErrorCode ec = TALER_EC_INVALID;
     635          22 :   const struct TALER_CsPubHashP *h_cs = cdr->h_cs;
     636          22 :   const struct GNUNET_CRYPTO_CsSessionNonce *nonce = cdr->nonce;
     637             : 
     638          22 :   memset (crp,
     639             :           0,
     640             :           sizeof (*crp));
     641          22 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     642             :               "Starting R derivation process\n");
     643          22 :   if (GNUNET_OK !=
     644          22 :       try_connect (dh))
     645             :   {
     646           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     647             :                 "Failed to connect to helper\n");
     648           0 :     return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
     649             :   }
     650             : 
     651          22 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     652             :               "Requesting R\n");
     653             :   {
     654          22 :     struct TALER_CRYPTO_CsRDeriveRequest rdr = {
     655          22 :       .header.size = htons (sizeof (rdr)),
     656          22 :       .header.type = htons (TALER_HELPER_CS_MT_REQ_RDERIVE),
     657          22 :       .for_melt = htonl (for_melt ? 1 : 0),
     658             :       .h_cs = *h_cs,
     659             :       .nonce = *nonce
     660             :     };
     661             : 
     662          22 :     if (GNUNET_OK !=
     663          22 :         TALER_crypto_helper_send_all (dh->sock,
     664             :                                       &rdr,
     665             :                                       sizeof (rdr)))
     666             :     {
     667           0 :       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
     668             :                            "send");
     669           0 :       do_disconnect (dh);
     670           0 :       return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
     671             :     }
     672             :   }
     673             : 
     674          22 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     675             :               "Awaiting reply\n");
     676             :   {
     677             :     char buf[UINT16_MAX];
     678          22 :     size_t off = 0;
     679          22 :     const struct GNUNET_MessageHeader *hdr
     680             :       = (const struct GNUNET_MessageHeader *) buf;
     681          22 :     bool finished = false;
     682             : 
     683             :     while (1)
     684          22 :     {
     685             :       uint16_t msize;
     686             :       ssize_t ret;
     687             : 
     688          66 :       ret = recv (dh->sock,
     689          44 :                   &buf[off],
     690             :                   sizeof (buf) - off,
     691          22 :                   (finished && (0 == off))
     692             :                   ? MSG_DONTWAIT
     693             :                   : 0);
     694          44 :       if (ret < 0)
     695             :       {
     696          22 :         if (EINTR == errno)
     697           0 :           continue;
     698          22 :         if (EAGAIN == errno)
     699             :         {
     700          22 :           GNUNET_assert (finished);
     701          22 :           GNUNET_assert (0 == off);
     702          22 :           return ec;
     703             :         }
     704           0 :         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
     705             :                              "recv");
     706           0 :         do_disconnect (dh);
     707           0 :         return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
     708             :       }
     709          22 :       if (0 == ret)
     710             :       {
     711           0 :         GNUNET_break (0 == off);
     712           0 :         if (! finished)
     713           0 :           return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
     714           0 :         return ec;
     715             :       }
     716          22 :       off += ret;
     717          44 : more:
     718          44 :       if (off < sizeof (struct GNUNET_MessageHeader))
     719          22 :         continue;
     720          22 :       msize = ntohs (hdr->size);
     721          22 :       if (off < msize)
     722           0 :         continue;
     723          22 :       switch (ntohs (hdr->type))
     724             :       {
     725          11 :       case TALER_HELPER_CS_MT_RES_RDERIVE:
     726          11 :         if (msize != sizeof (struct TALER_CRYPTO_RDeriveResponse))
     727             :         {
     728           0 :           GNUNET_break_op (0);
     729           0 :           do_disconnect (dh);
     730           0 :           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     731             :         }
     732          11 :         if (finished)
     733             :         {
     734           0 :           GNUNET_break_op (0);
     735           0 :           do_disconnect (dh);
     736           0 :           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     737             :         }
     738             :         {
     739          11 :           const struct TALER_CRYPTO_RDeriveResponse *rdr =
     740             :             (const struct TALER_CRYPTO_RDeriveResponse *) buf;
     741             : 
     742          11 :           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     743             :                       "Received R\n");
     744          11 :           finished = true;
     745          11 :           ec = TALER_EC_NONE;
     746          11 :           *crp = rdr->r_pub;
     747          11 :           break;
     748             :         }
     749          11 :       case TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE:
     750          11 :         if (msize != sizeof (struct TALER_CRYPTO_RDeriveFailure))
     751             :         {
     752           0 :           GNUNET_break_op (0);
     753           0 :           do_disconnect (dh);
     754           0 :           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     755             :         }
     756             :         {
     757          11 :           const struct TALER_CRYPTO_RDeriveFailure *rdf =
     758             :             (const struct TALER_CRYPTO_RDeriveFailure *) buf;
     759             : 
     760          11 :           ec = (enum TALER_ErrorCode) (int) ntohl (rdf->ec);
     761          11 :           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     762             :                       "R derivation failed!\n");
     763          11 :           finished = true;
     764          11 :           break;
     765             :         }
     766           0 :       case TALER_HELPER_CS_MT_AVAIL:
     767           0 :         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     768             :                     "Received new key!\n");
     769           0 :         if (GNUNET_OK !=
     770           0 :             handle_mt_avail (dh,
     771             :                              hdr))
     772             :         {
     773           0 :           GNUNET_break_op (0);
     774           0 :           do_disconnect (dh);
     775           0 :           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     776             :         }
     777           0 :         break; /* while(1) loop ensures we recvfrom() again */
     778           0 :       case TALER_HELPER_CS_MT_PURGE:
     779           0 :         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     780             :                     "Received revocation!\n");
     781           0 :         if (GNUNET_OK !=
     782           0 :             handle_mt_purge (dh,
     783             :                              hdr))
     784             :         {
     785           0 :           GNUNET_break_op (0);
     786           0 :           do_disconnect (dh);
     787           0 :           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     788             :         }
     789           0 :         break; /* while(1) loop ensures we recvfrom() again */
     790           0 :       case TALER_HELPER_CS_SYNCED:
     791           0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     792             :                     "Synchronized add odd time with CS helper!\n");
     793           0 :         dh->synced = true;
     794           0 :         break;
     795           0 :       default:
     796           0 :         GNUNET_break_op (0);
     797           0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     798             :                     "Received unexpected message of type %u\n",
     799             :                     ntohs (hdr->type));
     800           0 :         do_disconnect (dh);
     801           0 :         return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     802             :       }
     803          22 :       memmove (buf,
     804          22 :                &buf[msize],
     805             :                off - msize);
     806          22 :       off -= msize;
     807          22 :       goto more;
     808             :     } /* while(1) */
     809             :   }
     810             : }
     811             : 
     812             : 
     813             : enum TALER_ErrorCode
     814          57 : TALER_CRYPTO_helper_cs_batch_sign (
     815             :   struct TALER_CRYPTO_CsDenominationHelper *dh,
     816             :   unsigned int reqs_length,
     817             :   const struct TALER_CRYPTO_CsSignRequest reqs[static reqs_length],
     818             :   bool for_melt,
     819             :   struct TALER_BlindedDenominationSignature bss[static reqs_length])
     820          57 : {
     821          57 :   enum TALER_ErrorCode ec = TALER_EC_INVALID;
     822             :   unsigned int rpos;
     823             :   unsigned int rend;
     824             :   unsigned int wpos;
     825             : 
     826          57 :   memset (bss,
     827             :           0,
     828             :           sizeof (*bss) * reqs_length);
     829          57 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     830             :               "Starting signature process\n");
     831          57 :   if (GNUNET_OK !=
     832          57 :       try_connect (dh))
     833             :   {
     834           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     835             :                 "Failed to connect to helper\n");
     836           0 :     return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
     837             :   }
     838             : 
     839          57 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     840             :               "Requesting %u signatures\n",
     841             :               reqs_length);
     842          57 :   rpos = 0;
     843          57 :   rend = 0;
     844          57 :   wpos = 0;
     845         114 :   while (rpos < reqs_length)
     846             :   {
     847          57 :     unsigned int mlen = sizeof (struct TALER_CRYPTO_BatchSignRequest);
     848             : 
     849         307 :     while ( (rend < reqs_length) &&
     850         250 :             (mlen + sizeof (struct TALER_CRYPTO_CsSignRequestMessage)
     851             :              < UINT16_MAX) )
     852             :     {
     853         250 :       mlen += sizeof (struct TALER_CRYPTO_CsSignRequestMessage);
     854         250 :       rend++;
     855             :     }
     856          57 :     {
     857          57 :       char obuf[mlen] GNUNET_ALIGN;
     858          57 :       struct TALER_CRYPTO_BatchSignRequest *bsr
     859             :         = (struct TALER_CRYPTO_BatchSignRequest *) obuf;
     860             :       void *wbuf;
     861             : 
     862          57 :       bsr->header.type = htons (TALER_HELPER_CS_MT_REQ_BATCH_SIGN);
     863          57 :       bsr->header.size = htons (mlen);
     864          57 :       bsr->batch_size = htonl (rend - rpos);
     865          57 :       wbuf = &bsr[1];
     866         307 :       for (unsigned int i = rpos; i<rend; i++)
     867             :       {
     868         250 :         struct TALER_CRYPTO_CsSignRequestMessage *csm = wbuf;
     869         250 :         const struct TALER_CRYPTO_CsSignRequest *csr = &reqs[i];
     870             : 
     871         250 :         csm->header.size = htons (sizeof (*csm));
     872         250 :         csm->header.type = htons (TALER_HELPER_CS_MT_REQ_SIGN);
     873         250 :         csm->for_melt = htonl (for_melt ? 1 : 0);
     874         250 :         csm->h_cs = *csr->h_cs;
     875         250 :         csm->message = *csr->blinded_planchet;
     876         250 :         wbuf += sizeof (*csm);
     877             :       }
     878          57 :       GNUNET_assert (wbuf == &obuf[mlen]);
     879          57 :       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     880             :                   "Sending batch request [%u-%u)\n",
     881             :                   rpos,
     882             :                   rend);
     883          57 :       if (GNUNET_OK !=
     884          57 :           TALER_crypto_helper_send_all (dh->sock,
     885             :                                         obuf,
     886          57 :                                         sizeof (obuf)))
     887             :       {
     888           0 :         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
     889             :                              "send");
     890           0 :         do_disconnect (dh);
     891           0 :         return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
     892             :       }
     893             :     } /* end of obuf scope */
     894          57 :     rpos = rend;
     895             :     {
     896             :       char buf[UINT16_MAX];
     897          57 :       size_t off = 0;
     898          57 :       const struct GNUNET_MessageHeader *hdr
     899             :         = (const struct GNUNET_MessageHeader *) buf;
     900          57 :       bool finished = false;
     901             : 
     902             :       while (1)
     903         140 :       {
     904             :         uint16_t msize;
     905             :         ssize_t ret;
     906             : 
     907         197 :         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     908             :                     "Awaiting reply at %u (up to %u)\n",
     909             :                     wpos,
     910             :                     rend);
     911         254 :         ret = recv (dh->sock,
     912         197 :                     &buf[off],
     913             :                     sizeof (buf) - off,
     914          57 :                     (finished && (0 == off))
     915             :                   ? MSG_DONTWAIT
     916             :                   : 0);
     917         197 :         if (ret < 0)
     918             :         {
     919          57 :           if (EINTR == errno)
     920           0 :             continue;
     921          57 :           if (EAGAIN == errno)
     922             :           {
     923          57 :             GNUNET_assert (finished);
     924          57 :             GNUNET_assert (0 == off);
     925          57 :             break;
     926             :           }
     927           0 :           GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
     928             :                                "recv");
     929           0 :           do_disconnect (dh);
     930           0 :           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
     931             :         }
     932         140 :         if (0 == ret)
     933             :         {
     934           0 :           GNUNET_break (0 == off);
     935           0 :           if (! finished)
     936           0 :             return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
     937           0 :           if (TALER_EC_NONE == ec)
     938           0 :             break;
     939           0 :           return ec;
     940             :         }
     941         140 :         off += ret;
     942         390 : more:
     943         390 :         if (off < sizeof (struct GNUNET_MessageHeader))
     944         140 :           continue;
     945         250 :         msize = ntohs (hdr->size);
     946         250 :         if (off < msize)
     947           0 :           continue;
     948         250 :         switch (ntohs (hdr->type))
     949             :         {
     950         248 :         case TALER_HELPER_CS_MT_RES_SIGNATURE:
     951         248 :           if (msize != sizeof (struct TALER_CRYPTO_SignResponse))
     952             :           {
     953           0 :             GNUNET_break_op (0);
     954           0 :             do_disconnect (dh);
     955           0 :             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     956             :           }
     957         248 :           if (finished)
     958             :           {
     959           0 :             GNUNET_break_op (0);
     960           0 :             do_disconnect (dh);
     961           0 :             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     962             :           }
     963             :           {
     964         248 :             const struct TALER_CRYPTO_SignResponse *sr =
     965             :               (const struct TALER_CRYPTO_SignResponse *) buf;
     966             :             struct GNUNET_CRYPTO_BlindedSignature *blinded_sig;
     967         248 :             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     968             :                         "Received %u signature\n",
     969             :                         wpos);
     970         248 :             blinded_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
     971         248 :             blinded_sig->cipher = GNUNET_CRYPTO_BSA_CS;
     972         248 :             blinded_sig->rc = 1;
     973         248 :             blinded_sig->details.blinded_cs_answer.b = ntohl (sr->b);
     974         248 :             blinded_sig->details.blinded_cs_answer.s_scalar = sr->cs_answer;
     975             : 
     976         248 :             bss[wpos].blinded_sig = blinded_sig;
     977         248 :             wpos++;
     978         248 :             if (wpos == rend)
     979             :             {
     980          55 :               if (TALER_EC_INVALID == ec)
     981          55 :                 ec = TALER_EC_NONE;
     982          55 :               finished = true;
     983             :             }
     984         248 :             break;
     985             :           }
     986             : 
     987           2 :         case TALER_HELPER_CS_MT_RES_SIGN_FAILURE:
     988           2 :           if (msize != sizeof (struct TALER_CRYPTO_SignFailure))
     989             :           {
     990           0 :             GNUNET_break_op (0);
     991           0 :             do_disconnect (dh);
     992           0 :             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     993             :           }
     994             :           {
     995           2 :             const struct TALER_CRYPTO_SignFailure *sf =
     996             :               (const struct TALER_CRYPTO_SignFailure *) buf;
     997             : 
     998           2 :             ec = (enum TALER_ErrorCode) (int) ntohl (sf->ec);
     999           2 :             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1000             :                         "Signing %u failed with status %d!\n",
    1001             :                         wpos,
    1002             :                         ec);
    1003           2 :             wpos++;
    1004           2 :             if (wpos == rend)
    1005             :             {
    1006           2 :               finished = true;
    1007             :             }
    1008           2 :             break;
    1009             :           }
    1010           0 :         case TALER_HELPER_CS_MT_AVAIL:
    1011           0 :           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1012             :                       "Received new key!\n");
    1013           0 :           if (GNUNET_OK !=
    1014           0 :               handle_mt_avail (dh,
    1015             :                                hdr))
    1016             :           {
    1017           0 :             GNUNET_break_op (0);
    1018           0 :             do_disconnect (dh);
    1019           0 :             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    1020             :           }
    1021           0 :           break; /* while(1) loop ensures we recvfrom() again */
    1022           0 :         case TALER_HELPER_CS_MT_PURGE:
    1023           0 :           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1024             :                       "Received revocation!\n");
    1025           0 :           if (GNUNET_OK !=
    1026           0 :               handle_mt_purge (dh,
    1027             :                                hdr))
    1028             :           {
    1029           0 :             GNUNET_break_op (0);
    1030           0 :             do_disconnect (dh);
    1031           0 :             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    1032             :           }
    1033           0 :           break; /* while(1) loop ensures we recvfrom() again */
    1034           0 :         case TALER_HELPER_CS_SYNCED:
    1035           0 :           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1036             :                       "Synchronized add odd time with CS helper!\n");
    1037           0 :           dh->synced = true;
    1038           0 :           break;
    1039           0 :         default:
    1040           0 :           GNUNET_break_op (0);
    1041           0 :           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1042             :                       "Received unexpected message of type %u\n",
    1043             :                       ntohs (hdr->type));
    1044           0 :           do_disconnect (dh);
    1045           0 :           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    1046             :         }
    1047         250 :         memmove (buf,
    1048         250 :                  &buf[msize],
    1049             :                  off - msize);
    1050         250 :         off -= msize;
    1051         250 :         goto more;
    1052             :       } /* while(1) */
    1053             :     } /* scope */
    1054             :   } /* while (rpos < cdrs_length) */
    1055          57 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1056             :               "Existing with %u signatures and status %d\n",
    1057             :               wpos,
    1058             :               ec);
    1059          57 :   return ec;
    1060             : }
    1061             : 
    1062             : 
    1063             : enum TALER_ErrorCode
    1064         135 : TALER_CRYPTO_helper_cs_r_batch_derive (
    1065             :   struct TALER_CRYPTO_CsDenominationHelper *dh,
    1066             :   unsigned int cdrs_length,
    1067             :   const struct TALER_CRYPTO_CsDeriveRequest cdrs[static cdrs_length],
    1068             :   bool for_melt,
    1069             :   struct GNUNET_CRYPTO_CSPublicRPairP crps[static cdrs_length])
    1070         135 : {
    1071         135 :   enum TALER_ErrorCode ec = TALER_EC_INVALID;
    1072             :   unsigned int rpos;
    1073             :   unsigned int rend;
    1074             :   unsigned int wpos;
    1075             : 
    1076         135 :   memset (crps,
    1077             :           0,
    1078             :           sizeof (*crps) * cdrs_length);
    1079         135 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1080             :               "Starting R derivation process\n");
    1081         135 :   if (GNUNET_OK !=
    1082         135 :       try_connect (dh))
    1083             :   {
    1084           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1085             :                 "Failed to connect to helper\n");
    1086           0 :     return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
    1087             :   }
    1088             : 
    1089         135 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1090             :               "Requesting %u R pairs\n",
    1091             :               cdrs_length);
    1092         135 :   rpos = 0;
    1093         135 :   rend = 0;
    1094         135 :   wpos = 0;
    1095         270 :   while (rpos < cdrs_length)
    1096             :   {
    1097         135 :     unsigned int mlen = sizeof (struct TALER_CRYPTO_BatchDeriveRequest);
    1098             : 
    1099        1236 :     while ( (rend < cdrs_length) &&
    1100        1101 :             (mlen + sizeof (struct TALER_CRYPTO_CsRDeriveRequest)
    1101             :              < UINT16_MAX) )
    1102             :     {
    1103        1101 :       mlen += sizeof (struct TALER_CRYPTO_CsRDeriveRequest);
    1104        1101 :       rend++;
    1105             :     }
    1106         135 :     {
    1107         135 :       char obuf[mlen] GNUNET_ALIGN;
    1108         135 :       struct TALER_CRYPTO_BatchDeriveRequest *bdr
    1109             :         = (struct TALER_CRYPTO_BatchDeriveRequest *) obuf;
    1110             :       void *wbuf;
    1111             : 
    1112         135 :       bdr->header.type = htons (TALER_HELPER_CS_MT_REQ_BATCH_RDERIVE);
    1113         135 :       bdr->header.size = htons (mlen);
    1114         135 :       bdr->batch_size = htonl (rend - rpos);
    1115         135 :       wbuf = &bdr[1];
    1116        1236 :       for (unsigned int i = rpos; i<rend; i++)
    1117             :       {
    1118        1101 :         struct TALER_CRYPTO_CsRDeriveRequest *rdr = wbuf;
    1119        1101 :         const struct TALER_CRYPTO_CsDeriveRequest *cdr = &cdrs[i];
    1120             : 
    1121        1101 :         rdr->header.size = htons (sizeof (*rdr));
    1122        1101 :         rdr->header.type = htons (TALER_HELPER_CS_MT_REQ_RDERIVE);
    1123        1101 :         rdr->for_melt = htonl (for_melt ? 1 : 0);
    1124        1101 :         rdr->h_cs = *cdr->h_cs;
    1125        1101 :         rdr->nonce = *cdr->nonce;
    1126        1101 :         wbuf += sizeof (*rdr);
    1127             :       }
    1128         135 :       GNUNET_assert (wbuf == &obuf[mlen]);
    1129         135 :       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1130             :                   "Sending batch request [%u-%u)\n",
    1131             :                   rpos,
    1132             :                   rend);
    1133         135 :       if (GNUNET_OK !=
    1134         135 :           TALER_crypto_helper_send_all (dh->sock,
    1135             :                                         obuf,
    1136         135 :                                         sizeof (obuf)))
    1137             :       {
    1138           0 :         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    1139             :                              "send");
    1140           0 :         do_disconnect (dh);
    1141           0 :         return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
    1142             :       }
    1143             :     } /* end of obuf scope */
    1144         135 :     rpos = rend;
    1145             :     {
    1146             :       char buf[UINT16_MAX];
    1147         135 :       size_t off = 0;
    1148         135 :       const struct GNUNET_MessageHeader *hdr
    1149             :         = (const struct GNUNET_MessageHeader *) buf;
    1150         135 :       bool finished = false;
    1151             : 
    1152             :       while (1)
    1153         470 :       {
    1154             :         uint16_t msize;
    1155             :         ssize_t ret;
    1156             : 
    1157         605 :         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1158             :                     "Awaiting reply at %u (up to %u)\n",
    1159             :                     wpos,
    1160             :                     rend);
    1161         740 :         ret = recv (dh->sock,
    1162         605 :                     &buf[off],
    1163             :                     sizeof (buf) - off,
    1164         135 :                     (finished && (0 == off))
    1165             :                   ? MSG_DONTWAIT
    1166             :                   : 0);
    1167         605 :         if (ret < 0)
    1168             :         {
    1169         135 :           if (EINTR == errno)
    1170           0 :             continue;
    1171         135 :           if (EAGAIN == errno)
    1172             :           {
    1173         135 :             GNUNET_assert (finished);
    1174         135 :             GNUNET_assert (0 == off);
    1175         135 :             break;
    1176             :           }
    1177           0 :           GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    1178             :                                "recv");
    1179           0 :           do_disconnect (dh);
    1180           0 :           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
    1181             :         }
    1182         470 :         if (0 == ret)
    1183             :         {
    1184           0 :           GNUNET_break (0 == off);
    1185           0 :           if (! finished)
    1186           0 :             return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    1187           0 :           if (TALER_EC_NONE == ec)
    1188           0 :             break;
    1189           0 :           return ec;
    1190             :         }
    1191         470 :         off += ret;
    1192        1571 : more:
    1193        1571 :         if (off < sizeof (struct GNUNET_MessageHeader))
    1194         470 :           continue;
    1195        1101 :         msize = ntohs (hdr->size);
    1196        1101 :         if (off < msize)
    1197           0 :           continue;
    1198        1101 :         switch (ntohs (hdr->type))
    1199             :         {
    1200         346 :         case TALER_HELPER_CS_MT_RES_RDERIVE:
    1201         346 :           if (msize != sizeof (struct TALER_CRYPTO_RDeriveResponse))
    1202             :           {
    1203           0 :             GNUNET_break_op (0);
    1204           0 :             do_disconnect (dh);
    1205           0 :             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    1206             :           }
    1207         346 :           if (finished)
    1208             :           {
    1209           0 :             GNUNET_break_op (0);
    1210           0 :             do_disconnect (dh);
    1211           0 :             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    1212             :           }
    1213             :           {
    1214         346 :             const struct TALER_CRYPTO_RDeriveResponse *rdr =
    1215             :               (const struct TALER_CRYPTO_RDeriveResponse *) buf;
    1216             : 
    1217         346 :             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1218             :                         "Received %u R pair\n",
    1219             :                         wpos);
    1220         346 :             crps[wpos] = rdr->r_pub;
    1221         346 :             wpos++;
    1222         346 :             if (wpos == rend)
    1223             :             {
    1224         105 :               if (TALER_EC_INVALID == ec)
    1225         105 :                 ec = TALER_EC_NONE;
    1226         105 :               finished = true;
    1227             :             }
    1228         346 :             break;
    1229             :           }
    1230         755 :         case TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE:
    1231         755 :           if (msize != sizeof (struct TALER_CRYPTO_RDeriveFailure))
    1232             :           {
    1233           0 :             GNUNET_break_op (0);
    1234           0 :             do_disconnect (dh);
    1235           0 :             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    1236             :           }
    1237             :           {
    1238         755 :             const struct TALER_CRYPTO_RDeriveFailure *rdf =
    1239             :               (const struct TALER_CRYPTO_RDeriveFailure *) buf;
    1240             : 
    1241         755 :             ec = (enum TALER_ErrorCode) (int) ntohl (rdf->ec);
    1242         755 :             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1243             :                         "R derivation %u failed with status %d!\n",
    1244             :                         wpos,
    1245             :                         ec);
    1246         755 :             wpos++;
    1247         755 :             if (wpos == rend)
    1248             :             {
    1249          30 :               finished = true;
    1250             :             }
    1251         755 :             break;
    1252             :           }
    1253           0 :         case TALER_HELPER_CS_MT_AVAIL:
    1254           0 :           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1255             :                       "Received new key!\n");
    1256           0 :           if (GNUNET_OK !=
    1257           0 :               handle_mt_avail (dh,
    1258             :                                hdr))
    1259             :           {
    1260           0 :             GNUNET_break_op (0);
    1261           0 :             do_disconnect (dh);
    1262           0 :             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    1263             :           }
    1264           0 :           break; /* while(1) loop ensures we recvfrom() again */
    1265           0 :         case TALER_HELPER_CS_MT_PURGE:
    1266           0 :           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1267             :                       "Received revocation!\n");
    1268           0 :           if (GNUNET_OK !=
    1269           0 :               handle_mt_purge (dh,
    1270             :                                hdr))
    1271             :           {
    1272           0 :             GNUNET_break_op (0);
    1273           0 :             do_disconnect (dh);
    1274           0 :             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    1275             :           }
    1276           0 :           break; /* while(1) loop ensures we recvfrom() again */
    1277           0 :         case TALER_HELPER_CS_SYNCED:
    1278           0 :           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1279             :                       "Synchronized add odd time with CS helper!\n");
    1280           0 :           dh->synced = true;
    1281           0 :           break;
    1282           0 :         default:
    1283           0 :           GNUNET_break_op (0);
    1284           0 :           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1285             :                       "Received unexpected message of type %u\n",
    1286             :                       ntohs (hdr->type));
    1287           0 :           do_disconnect (dh);
    1288           0 :           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    1289             :         }
    1290        1101 :         memmove (buf,
    1291        1101 :                  &buf[msize],
    1292             :                  off - msize);
    1293        1101 :         off -= msize;
    1294        1101 :         goto more;
    1295             :       } /* while(1) */
    1296             :     } /* scope */
    1297             :   } /* while (rpos < cdrs_length) */
    1298         135 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1299             :               "Existing with %u signatures and status %d\n",
    1300             :               wpos,
    1301             :               ec);
    1302         135 :   return ec;
    1303             : }
    1304             : 
    1305             : 
    1306             : void
    1307          38 : TALER_CRYPTO_helper_cs_disconnect (
    1308             :   struct TALER_CRYPTO_CsDenominationHelper *dh)
    1309             : {
    1310          38 :   if (-1 != dh->sock)
    1311          38 :     do_disconnect (dh);
    1312          38 :   GNUNET_free (dh);
    1313          38 : }
    1314             : 
    1315             : 
    1316             : /* end of crypto_helper_cs.c */

Generated by: LCOV version 1.16