exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

crypto_helper_cs.c (27708B)


      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/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 do_disconnect (struct TALER_CRYPTO_CsDenominationHelper *dh)
     67 {
     68   GNUNET_break (0 == close (dh->sock));
     69   dh->sock = -1;
     70   dh->synced = false;
     71 }
     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 try_connect (struct TALER_CRYPTO_CsDenominationHelper *dh)
     83 {
     84   if (-1 != dh->sock)
     85     return GNUNET_OK;
     86   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     87               "Establishing connection!\n");
     88   dh->sock = socket (AF_UNIX,
     89                      SOCK_STREAM,
     90                      0);
     91   if (-1 == dh->sock)
     92   {
     93     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
     94                          "socket");
     95     return GNUNET_SYSERR;
     96   }
     97   if (0 !=
     98       connect (dh->sock,
     99                (const struct sockaddr *) &dh->sa,
    100                sizeof (dh->sa)))
    101   {
    102     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
    103                               "connect",
    104                               dh->sa.sun_path);
    105     do_disconnect (dh);
    106     return GNUNET_SYSERR;
    107   }
    108   TALER_CRYPTO_helper_cs_poll (dh);
    109   return GNUNET_OK;
    110 }
    111 
    112 
    113 struct TALER_CRYPTO_CsDenominationHelper *
    114 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   GNUNET_asprintf (&secname,
    125                    "%s-secmod-cs",
    126                    section);
    127   if (GNUNET_OK !=
    128       GNUNET_CONFIGURATION_get_value_filename (cfg,
    129                                                secname,
    130                                                "UNIXPATH",
    131                                                &unixpath))
    132   {
    133     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    134                                secname,
    135                                "UNIXPATH");
    136     GNUNET_free (secname);
    137     return NULL;
    138   }
    139   /* we use >= here because we want the sun_path to always
    140      be 0-terminated */
    141   if (strlen (unixpath) >= sizeof (dh->sa.sun_path))
    142   {
    143     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    144                                secname,
    145                                "UNIXPATH",
    146                                "path too long");
    147     GNUNET_free (unixpath);
    148     GNUNET_free (secname);
    149     return NULL;
    150   }
    151   GNUNET_free (secname);
    152   dh = GNUNET_new (struct TALER_CRYPTO_CsDenominationHelper);
    153   dh->dkc = dkc;
    154   dh->dkc_cls = dkc_cls;
    155   dh->sa.sun_family = AF_UNIX;
    156   strncpy (dh->sa.sun_path,
    157            unixpath,
    158            sizeof (dh->sa.sun_path) - 1);
    159   GNUNET_free (unixpath);
    160   dh->sock = -1;
    161   if (GNUNET_OK !=
    162       try_connect (dh))
    163   {
    164     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    165                 "Could not connect to %s. Will keep trying\n",
    166                 "taler-exchange-helper-secmod-cs");
    167   }
    168   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 handle_mt_avail (struct TALER_CRYPTO_CsDenominationHelper *dh,
    181                  const struct GNUNET_MessageHeader *hdr)
    182 {
    183   const struct TALER_CRYPTO_CsKeyAvailableNotification *kan
    184     = (const struct TALER_CRYPTO_CsKeyAvailableNotification *) hdr;
    185   const char *buf = (const char *) &kan[1];
    186   const char *section_name;
    187   uint16_t snl;
    188 
    189   if (sizeof (*kan) > ntohs (hdr->size))
    190   {
    191     GNUNET_break_op (0);
    192     return GNUNET_SYSERR;
    193   }
    194   snl = ntohs (kan->section_name_len);
    195   if (ntohs (hdr->size) != sizeof (*kan) + snl)
    196   {
    197     GNUNET_break_op (0);
    198     return GNUNET_SYSERR;
    199   }
    200   if (0 == snl)
    201   {
    202     GNUNET_break_op (0);
    203     return GNUNET_SYSERR;
    204   }
    205   section_name = buf;
    206   if ('\0' != section_name[snl - 1])
    207   {
    208     GNUNET_break_op (0);
    209     return GNUNET_SYSERR;
    210   }
    211 
    212   {
    213     struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
    214     struct TALER_CsPubHashP h_cs;
    215 
    216     bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
    217     bsign_pub->cipher = GNUNET_CRYPTO_BSA_CS;
    218     bsign_pub->rc = 1;
    219     bsign_pub->details.cs_public_key = kan->denom_pub;
    220 
    221     GNUNET_CRYPTO_hash (&bsign_pub->details.cs_public_key,
    222                         sizeof (bsign_pub->details.cs_public_key),
    223                         &bsign_pub->pub_key_hash);
    224     h_cs.hash = bsign_pub->pub_key_hash;
    225     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    226                 "Received CS key %s (%s)\n",
    227                 GNUNET_h2s (&h_cs.hash),
    228                 section_name);
    229     if (GNUNET_OK !=
    230         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       GNUNET_break_op (0);
    239       GNUNET_CRYPTO_blind_sign_pub_decref (bsign_pub);
    240       return GNUNET_SYSERR;
    241     }
    242     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     GNUNET_CRYPTO_blind_sign_pub_decref (bsign_pub);
    251   }
    252   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 handle_mt_purge (struct TALER_CRYPTO_CsDenominationHelper *dh,
    265                  const struct GNUNET_MessageHeader *hdr)
    266 {
    267   const struct TALER_CRYPTO_CsKeyPurgeNotification *pn
    268     = (const struct TALER_CRYPTO_CsKeyPurgeNotification *) hdr;
    269 
    270   if (sizeof (*pn) != ntohs (hdr->size))
    271   {
    272     GNUNET_break_op (0);
    273     return GNUNET_SYSERR;
    274   }
    275   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    276               "Received revocation of denomination key %s\n",
    277               GNUNET_h2s (&pn->h_cs.hash));
    278   dh->dkc (dh->dkc_cls,
    279            NULL,
    280            GNUNET_TIME_UNIT_ZERO_TS,
    281            GNUNET_TIME_UNIT_ZERO,
    282            &pn->h_cs,
    283            NULL,
    284            NULL,
    285            NULL);
    286   return GNUNET_OK;
    287 }
    288 
    289 
    290 void
    291 TALER_CRYPTO_helper_cs_poll (struct TALER_CRYPTO_CsDenominationHelper *dh)
    292 {
    293   char buf[UINT16_MAX];
    294   size_t off = 0;
    295   unsigned int retry_limit = 3;
    296   const struct GNUNET_MessageHeader *hdr
    297     = (const struct GNUNET_MessageHeader *) buf;
    298 
    299   if (GNUNET_OK !=
    300       try_connect (dh))
    301     return; /* give up */
    302   while (1)
    303   {
    304     uint16_t msize;
    305     ssize_t ret;
    306 
    307     ret = recv (dh->sock,
    308                 buf + off,
    309                 sizeof (buf) - off,
    310                 (dh->synced && (0 == off))
    311                 ? MSG_DONTWAIT
    312                 : 0);
    313     if (ret < 0)
    314     {
    315       if (EINTR == errno)
    316         continue;
    317       if (EAGAIN == errno)
    318       {
    319         GNUNET_assert (dh->synced);
    320         GNUNET_assert (0 == off);
    321         break;
    322       }
    323       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    324                            "recv");
    325       do_disconnect (dh);
    326       if (0 == retry_limit)
    327         return; /* give up */
    328       if (GNUNET_OK !=
    329           try_connect (dh))
    330         return; /* give up */
    331       retry_limit--;
    332       continue;
    333     }
    334     if (0 == ret)
    335     {
    336       GNUNET_break (0 == off);
    337       return;
    338     }
    339     off += ret;
    340 more:
    341     if (off < sizeof (struct GNUNET_MessageHeader))
    342       continue;
    343     msize = ntohs (hdr->size);
    344     if (msize < sizeof (struct GNUNET_MessageHeader))
    345     {
    346       GNUNET_break_op (0);
    347       do_disconnect (dh);
    348       return;
    349     }
    350     if (off < msize)
    351       continue;
    352     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    353                 "Received message of type %u and length %u\n",
    354                 (unsigned int) ntohs (hdr->type),
    355                 (unsigned int) msize);
    356     switch (ntohs (hdr->type))
    357     {
    358     case TALER_HELPER_CS_MT_AVAIL:
    359       if (GNUNET_OK !=
    360           handle_mt_avail (dh,
    361                            hdr))
    362       {
    363         GNUNET_break_op (0);
    364         do_disconnect (dh);
    365         return;
    366       }
    367       break;
    368     case TALER_HELPER_CS_MT_PURGE:
    369       if (GNUNET_OK !=
    370           handle_mt_purge (dh,
    371                            hdr))
    372       {
    373         GNUNET_break_op (0);
    374         do_disconnect (dh);
    375         return;
    376       }
    377       break;
    378     case TALER_HELPER_CS_SYNCED:
    379       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    380                   "Now synchronized with CS helper\n");
    381       dh->synced = true;
    382       break;
    383     default:
    384       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    385                   "Received unexpected message of type %d (len: %u)\n",
    386                   (unsigned int) ntohs (hdr->type),
    387                   (unsigned int) msize);
    388       GNUNET_break_op (0);
    389       do_disconnect (dh);
    390       return;
    391     }
    392     memmove (buf,
    393              &buf[msize],
    394              off - msize);
    395     off -= msize;
    396     goto more;
    397   }
    398 }
    399 
    400 
    401 void
    402 TALER_CRYPTO_helper_cs_revoke (
    403   struct TALER_CRYPTO_CsDenominationHelper *dh,
    404   const struct TALER_CsPubHashP *h_cs)
    405 {
    406   struct TALER_CRYPTO_CsRevokeRequest rr = {
    407     .header.size = htons (sizeof (rr)),
    408     .header.type = htons (TALER_HELPER_CS_MT_REQ_REVOKE),
    409     .h_cs = *h_cs
    410   };
    411 
    412   if (GNUNET_OK !=
    413       try_connect (dh))
    414     return; /* give up */
    415   if (GNUNET_OK !=
    416       TALER_crypto_helper_send_all (dh->sock,
    417                                     &rr,
    418                                     sizeof (rr)))
    419   {
    420     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    421                          "send");
    422     do_disconnect (dh);
    423     return;
    424   }
    425   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    426               "Requested revocation of denomination key %s\n",
    427               GNUNET_h2s (&h_cs->hash));
    428 }
    429 
    430 
    431 enum TALER_ErrorCode
    432 TALER_CRYPTO_helper_cs_batch_sign (
    433   struct TALER_CRYPTO_CsDenominationHelper *dh,
    434   unsigned int reqs_length,
    435   const struct TALER_CRYPTO_CsSignRequest reqs[static reqs_length],
    436   bool for_melt,
    437   struct TALER_BlindedDenominationSignature bss[static reqs_length])
    438 {
    439   enum TALER_ErrorCode ec = TALER_EC_INVALID;
    440   unsigned int rpos;
    441   unsigned int rend;
    442   unsigned int wpos;
    443 
    444   memset (bss,
    445           0,
    446           sizeof (*bss) * reqs_length);
    447   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    448               "Starting signature process\n");
    449   if (GNUNET_OK !=
    450       try_connect (dh))
    451   {
    452     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    453                 "Failed to connect to helper\n");
    454     return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
    455   }
    456 
    457   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    458               "Requesting %u signatures\n",
    459               reqs_length);
    460   rpos = 0;
    461   rend = 0;
    462   wpos = 0;
    463   while (rpos < reqs_length)
    464   {
    465     unsigned int mlen = sizeof (struct TALER_CRYPTO_BatchSignRequest);
    466 
    467     while ( (rend < reqs_length) &&
    468             (mlen + sizeof (struct TALER_CRYPTO_CsSignRequestMessage)
    469              < UINT16_MAX) )
    470     {
    471       mlen += sizeof (struct TALER_CRYPTO_CsSignRequestMessage);
    472       rend++;
    473     }
    474     {
    475       char obuf[mlen] GNUNET_ALIGN;
    476       struct TALER_CRYPTO_BatchSignRequest *bsr
    477         = (struct TALER_CRYPTO_BatchSignRequest *) obuf;
    478       void *wbuf;
    479 
    480       bsr->header.type = htons (TALER_HELPER_CS_MT_REQ_BATCH_SIGN);
    481       bsr->header.size = htons (mlen);
    482       bsr->batch_size = htonl (rend - rpos);
    483       wbuf = &bsr[1];
    484       for (unsigned int i = rpos; i<rend; i++)
    485       {
    486         struct TALER_CRYPTO_CsSignRequestMessage *csm = wbuf;
    487         const struct TALER_CRYPTO_CsSignRequest *csr = &reqs[i];
    488 
    489         csm->header.size = htons (sizeof (*csm));
    490         csm->header.type = htons (TALER_HELPER_CS_MT_REQ_SIGN);
    491         csm->for_melt = htonl (for_melt ? 1 : 0);
    492         csm->h_cs = *csr->h_cs;
    493         csm->message = *csr->blinded_planchet;
    494         wbuf += sizeof (*csm);
    495       }
    496       GNUNET_assert (wbuf == &obuf[mlen]);
    497       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    498                   "Sending batch request [%u-%u)\n",
    499                   rpos,
    500                   rend);
    501       if (GNUNET_OK !=
    502           TALER_crypto_helper_send_all (dh->sock,
    503                                         obuf,
    504                                         sizeof (obuf)))
    505       {
    506         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    507                              "send");
    508         do_disconnect (dh);
    509         return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
    510       }
    511     } /* end of obuf scope */
    512     rpos = rend;
    513     {
    514       char buf[UINT16_MAX];
    515       size_t off = 0;
    516       const struct GNUNET_MessageHeader *hdr
    517         = (const struct GNUNET_MessageHeader *) buf;
    518       bool finished = false;
    519 
    520       while (1)
    521       {
    522         uint16_t msize;
    523         ssize_t ret;
    524 
    525         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    526                     "Awaiting reply at %u (up to %u)\n",
    527                     wpos,
    528                     rend);
    529         ret = recv (dh->sock,
    530                     &buf[off],
    531                     sizeof (buf) - off,
    532                     (finished && (0 == off))
    533                   ? MSG_DONTWAIT
    534                   : 0);
    535         if (ret < 0)
    536         {
    537           if (EINTR == errno)
    538             continue;
    539           if (EAGAIN == errno)
    540           {
    541             GNUNET_assert (finished);
    542             GNUNET_assert (0 == off);
    543             break;
    544           }
    545           GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    546                                "recv");
    547           do_disconnect (dh);
    548           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
    549         }
    550         if (0 == ret)
    551         {
    552           GNUNET_break (0 == off);
    553           if (! finished)
    554             return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    555           if (TALER_EC_NONE == ec)
    556             break;
    557           return ec;
    558         }
    559         off += ret;
    560 more:
    561         if (off < sizeof (struct GNUNET_MessageHeader))
    562           continue;
    563         msize = ntohs (hdr->size);
    564         if (msize < sizeof (struct GNUNET_MessageHeader))
    565         {
    566           GNUNET_break_op (0);
    567           do_disconnect (dh);
    568           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    569         }
    570         if (off < msize)
    571           continue;
    572         switch (ntohs (hdr->type))
    573         {
    574         case TALER_HELPER_CS_MT_RES_SIGNATURE:
    575           if (msize != sizeof (struct TALER_CRYPTO_SignResponse))
    576           {
    577             GNUNET_break_op (0);
    578             do_disconnect (dh);
    579             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    580           }
    581           if (finished)
    582           {
    583             GNUNET_break_op (0);
    584             do_disconnect (dh);
    585             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    586           }
    587           {
    588             const struct TALER_CRYPTO_SignResponse *sr =
    589               (const struct TALER_CRYPTO_SignResponse *) buf;
    590             struct GNUNET_CRYPTO_BlindedSignature *blinded_sig;
    591             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    592                         "Received %u signature\n",
    593                         wpos);
    594             blinded_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
    595             blinded_sig->cipher = GNUNET_CRYPTO_BSA_CS;
    596             blinded_sig->rc = 1;
    597             blinded_sig->details.blinded_cs_answer.b = ntohl (sr->b);
    598             blinded_sig->details.blinded_cs_answer.s_scalar = sr->cs_answer;
    599 
    600             bss[wpos].blinded_sig = blinded_sig;
    601             wpos++;
    602             if (wpos == rend)
    603             {
    604               if (TALER_EC_INVALID == ec)
    605                 ec = TALER_EC_NONE;
    606               finished = true;
    607             }
    608             break;
    609           }
    610 
    611         case TALER_HELPER_CS_MT_RES_SIGN_FAILURE:
    612           if (msize != sizeof (struct TALER_CRYPTO_SignFailure))
    613           {
    614             GNUNET_break_op (0);
    615             do_disconnect (dh);
    616             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    617           }
    618           {
    619             const struct TALER_CRYPTO_SignFailure *sf =
    620               (const struct TALER_CRYPTO_SignFailure *) buf;
    621 
    622             ec = (enum TALER_ErrorCode) (int) ntohl (sf->ec);
    623             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    624                         "Signing %u failed with status %d!\n",
    625                         wpos,
    626                         ec);
    627             wpos++;
    628             if (wpos == rend)
    629             {
    630               finished = true;
    631             }
    632             break;
    633           }
    634         case TALER_HELPER_CS_MT_AVAIL:
    635           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    636                       "Received new key!\n");
    637           if (GNUNET_OK !=
    638               handle_mt_avail (dh,
    639                                hdr))
    640           {
    641             GNUNET_break_op (0);
    642             do_disconnect (dh);
    643             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    644           }
    645           break; /* while(1) loop ensures we recvfrom() again */
    646         case TALER_HELPER_CS_MT_PURGE:
    647           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    648                       "Received revocation!\n");
    649           if (GNUNET_OK !=
    650               handle_mt_purge (dh,
    651                                hdr))
    652           {
    653             GNUNET_break_op (0);
    654             do_disconnect (dh);
    655             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    656           }
    657           break; /* while(1) loop ensures we recvfrom() again */
    658         case TALER_HELPER_CS_SYNCED:
    659           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    660                       "Synchronized add odd time with CS helper!\n");
    661           dh->synced = true;
    662           break;
    663         default:
    664           GNUNET_break_op (0);
    665           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    666                       "Received unexpected message of type %u\n",
    667                       ntohs (hdr->type));
    668           do_disconnect (dh);
    669           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    670         }
    671         memmove (buf,
    672                  &buf[msize],
    673                  off - msize);
    674         off -= msize;
    675         goto more;
    676       } /* while(1) */
    677     } /* scope */
    678   } /* while (rpos < cdrs_length) */
    679   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    680               "Existing with %u signatures and status %d\n",
    681               wpos,
    682               ec);
    683   return ec;
    684 }
    685 
    686 
    687 enum TALER_ErrorCode
    688 TALER_CRYPTO_helper_cs_r_batch_derive (
    689   struct TALER_CRYPTO_CsDenominationHelper *dh,
    690   unsigned int cdrs_length,
    691   const struct TALER_CRYPTO_CsDeriveRequest cdrs[static cdrs_length],
    692   bool for_melt,
    693   struct GNUNET_CRYPTO_CSPublicRPairP crps[static cdrs_length])
    694 {
    695   enum TALER_ErrorCode ec = TALER_EC_INVALID;
    696   unsigned int rpos;
    697   unsigned int rend;
    698   unsigned int wpos;
    699 
    700   memset (crps,
    701           0,
    702           sizeof (*crps) * cdrs_length);
    703   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    704               "Starting R derivation process\n");
    705   if (GNUNET_OK !=
    706       try_connect (dh))
    707   {
    708     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    709                 "Failed to connect to helper\n");
    710     return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
    711   }
    712 
    713   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    714               "Requesting %u R pairs\n",
    715               cdrs_length);
    716   rpos = 0;
    717   rend = 0;
    718   wpos = 0;
    719   while (rpos < cdrs_length)
    720   {
    721     unsigned int mlen = sizeof (struct TALER_CRYPTO_BatchDeriveRequest);
    722 
    723     while ( (rend < cdrs_length) &&
    724             (mlen + sizeof (struct TALER_CRYPTO_CsRDeriveRequest)
    725              < UINT16_MAX) )
    726     {
    727       mlen += sizeof (struct TALER_CRYPTO_CsRDeriveRequest);
    728       rend++;
    729     }
    730     {
    731       char obuf[mlen] GNUNET_ALIGN;
    732       struct TALER_CRYPTO_BatchDeriveRequest *bdr
    733         = (struct TALER_CRYPTO_BatchDeriveRequest *) obuf;
    734       void *wbuf;
    735 
    736       bdr->header.type = htons (TALER_HELPER_CS_MT_REQ_BATCH_RDERIVE);
    737       bdr->header.size = htons (mlen);
    738       bdr->batch_size = htonl (rend - rpos);
    739       wbuf = &bdr[1];
    740       for (unsigned int i = rpos; i<rend; i++)
    741       {
    742         struct TALER_CRYPTO_CsRDeriveRequest *rdr = wbuf;
    743         const struct TALER_CRYPTO_CsDeriveRequest *cdr = &cdrs[i];
    744 
    745         rdr->header.size = htons (sizeof (*rdr));
    746         rdr->header.type = htons (TALER_HELPER_CS_MT_REQ_RDERIVE);
    747         rdr->for_melt = htonl (for_melt ? 1 : 0);
    748         rdr->h_cs = *cdr->h_cs;
    749         rdr->nonce = *cdr->nonce;
    750         wbuf += sizeof (*rdr);
    751       }
    752       GNUNET_assert (wbuf == &obuf[mlen]);
    753       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    754                   "Sending batch request [%u-%u)\n",
    755                   rpos,
    756                   rend);
    757       if (GNUNET_OK !=
    758           TALER_crypto_helper_send_all (dh->sock,
    759                                         obuf,
    760                                         sizeof (obuf)))
    761       {
    762         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    763                              "send");
    764         do_disconnect (dh);
    765         return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
    766       }
    767     } /* end of obuf scope */
    768     rpos = rend;
    769     {
    770       char buf[UINT16_MAX];
    771       size_t off = 0;
    772       const struct GNUNET_MessageHeader *hdr
    773         = (const struct GNUNET_MessageHeader *) buf;
    774       bool finished = false;
    775 
    776       while (1)
    777       {
    778         uint16_t msize;
    779         ssize_t ret;
    780 
    781         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    782                     "Awaiting reply at %u (up to %u)\n",
    783                     wpos,
    784                     rend);
    785         ret = recv (dh->sock,
    786                     &buf[off],
    787                     sizeof (buf) - off,
    788                     (finished && (0 == off))
    789                   ? MSG_DONTWAIT
    790                   : 0);
    791         if (ret < 0)
    792         {
    793           if (EINTR == errno)
    794             continue;
    795           if (EAGAIN == errno)
    796           {
    797             GNUNET_assert (finished);
    798             GNUNET_assert (0 == off);
    799             break;
    800           }
    801           GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    802                                "recv");
    803           do_disconnect (dh);
    804           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
    805         }
    806         if (0 == ret)
    807         {
    808           GNUNET_break (0 == off);
    809           if (! finished)
    810             return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    811           if (TALER_EC_NONE == ec)
    812             break;
    813           return ec;
    814         }
    815         off += ret;
    816 more:
    817         if (off < sizeof (struct GNUNET_MessageHeader))
    818           continue;
    819         msize = ntohs (hdr->size);
    820         if (msize < sizeof (struct GNUNET_MessageHeader))
    821         {
    822           GNUNET_break_op (0);
    823           do_disconnect (dh);
    824           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    825         }
    826         if (off < msize)
    827           continue;
    828         switch (ntohs (hdr->type))
    829         {
    830         case TALER_HELPER_CS_MT_RES_RDERIVE:
    831           if (msize != sizeof (struct TALER_CRYPTO_RDeriveResponse))
    832           {
    833             GNUNET_break_op (0);
    834             do_disconnect (dh);
    835             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    836           }
    837           if (finished)
    838           {
    839             GNUNET_break_op (0);
    840             do_disconnect (dh);
    841             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    842           }
    843           {
    844             const struct TALER_CRYPTO_RDeriveResponse *rdr =
    845               (const struct TALER_CRYPTO_RDeriveResponse *) buf;
    846 
    847             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    848                         "Received %u R pair\n",
    849                         wpos);
    850             crps[wpos] = rdr->r_pub;
    851             wpos++;
    852             if (wpos == rend)
    853             {
    854               if (TALER_EC_INVALID == ec)
    855                 ec = TALER_EC_NONE;
    856               finished = true;
    857             }
    858             break;
    859           }
    860         case TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE:
    861           if (msize != sizeof (struct TALER_CRYPTO_RDeriveFailure))
    862           {
    863             GNUNET_break_op (0);
    864             do_disconnect (dh);
    865             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    866           }
    867           {
    868             const struct TALER_CRYPTO_RDeriveFailure *rdf =
    869               (const struct TALER_CRYPTO_RDeriveFailure *) buf;
    870 
    871             ec = (enum TALER_ErrorCode) (int) ntohl (rdf->ec);
    872             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    873                         "R derivation %u failed with status %d!\n",
    874                         wpos,
    875                         ec);
    876             wpos++;
    877             if (wpos == rend)
    878             {
    879               finished = true;
    880             }
    881             break;
    882           }
    883         case TALER_HELPER_CS_MT_AVAIL:
    884           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    885                       "Received new key!\n");
    886           if (GNUNET_OK !=
    887               handle_mt_avail (dh,
    888                                hdr))
    889           {
    890             GNUNET_break_op (0);
    891             do_disconnect (dh);
    892             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    893           }
    894           break; /* while(1) loop ensures we recvfrom() again */
    895         case TALER_HELPER_CS_MT_PURGE:
    896           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    897                       "Received revocation!\n");
    898           if (GNUNET_OK !=
    899               handle_mt_purge (dh,
    900                                hdr))
    901           {
    902             GNUNET_break_op (0);
    903             do_disconnect (dh);
    904             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    905           }
    906           break; /* while(1) loop ensures we recvfrom() again */
    907         case TALER_HELPER_CS_SYNCED:
    908           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    909                       "Synchronized add odd time with CS helper!\n");
    910           dh->synced = true;
    911           break;
    912         default:
    913           GNUNET_break_op (0);
    914           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    915                       "Received unexpected message of type %u\n",
    916                       ntohs (hdr->type));
    917           do_disconnect (dh);
    918           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    919         }
    920         memmove (buf,
    921                  &buf[msize],
    922                  off - msize);
    923         off -= msize;
    924         goto more;
    925       } /* while(1) */
    926     } /* scope */
    927   } /* while (rpos < cdrs_length) */
    928   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    929               "Existing with %u signatures and status %d\n",
    930               wpos,
    931               ec);
    932   return ec;
    933 }
    934 
    935 
    936 void
    937 TALER_CRYPTO_helper_cs_disconnect (
    938   struct TALER_CRYPTO_CsDenominationHelper *dh)
    939 {
    940   if (-1 != dh->sock)
    941     do_disconnect (dh);
    942   GNUNET_free (dh);
    943 }
    944 
    945 
    946 /* end of crypto_helper_cs.c */