LCOV - code coverage report
Current view: top level - util - crypto_helper_cs.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 62.1 % 678 421
Test Date: 2026-01-04 22:17:00 Functions: 100.0 % 12 12

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

Generated by: LCOV version 2.0-1