exchange

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

crypto_helper_rsa.c (26604B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2020, 2021 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_rsa.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 "crypto_helper_common.h"
     25 #include "secmod_rsa.h"
     26 #include <poll.h>
     27 
     28 
     29 struct TALER_CRYPTO_RsaDenominationHelper
     30 {
     31   /**
     32    * Function to call with updates to available key material.
     33    */
     34   TALER_CRYPTO_RsaDenominationKeyStatusCallback 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_RsaDenominationHelper *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_RsaDenominationHelper *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_rsa_poll (dh);
    109   return GNUNET_OK;
    110 }
    111 
    112 
    113 struct TALER_CRYPTO_RsaDenominationHelper *
    114 TALER_CRYPTO_helper_rsa_connect (
    115   const struct GNUNET_CONFIGURATION_Handle *cfg,
    116   const char *section,
    117   TALER_CRYPTO_RsaDenominationKeyStatusCallback dkc,
    118   void *dkc_cls)
    119 {
    120   struct TALER_CRYPTO_RsaDenominationHelper *dh;
    121   char *unixpath;
    122   char *secname;
    123 
    124   GNUNET_asprintf (&secname,
    125                    "%s-secmod-rsa",
    126                    section);
    127 
    128   if (GNUNET_OK !=
    129       GNUNET_CONFIGURATION_get_value_filename (cfg,
    130                                                secname,
    131                                                "UNIXPATH",
    132                                                &unixpath))
    133   {
    134     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    135                                secname,
    136                                "UNIXPATH");
    137     GNUNET_free (secname);
    138     return NULL;
    139   }
    140   /* we use >= here because we want the sun_path to always
    141      be 0-terminated */
    142   if (strlen (unixpath) >= sizeof (dh->sa.sun_path))
    143   {
    144     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    145                                secname,
    146                                "UNIXPATH",
    147                                "path too long");
    148     GNUNET_free (unixpath);
    149     GNUNET_free (secname);
    150     return NULL;
    151   }
    152   GNUNET_free (secname);
    153   dh = GNUNET_new (struct TALER_CRYPTO_RsaDenominationHelper);
    154   dh->dkc = dkc;
    155   dh->dkc_cls = dkc_cls;
    156   dh->sa.sun_family = AF_UNIX;
    157   strncpy (dh->sa.sun_path,
    158            unixpath,
    159            sizeof (dh->sa.sun_path) - 1);
    160   GNUNET_free (unixpath);
    161   dh->sock = -1;
    162   if (GNUNET_OK !=
    163       try_connect (dh))
    164   {
    165     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    166                 "Could not connect to %s. Will keep trying\n",
    167                 "taler-exchange-helper-secmod-rsa");
    168   }
    169   return dh;
    170 }
    171 
    172 
    173 /**
    174  * Handle a #TALER_HELPER_RSA_MT_AVAIL message from the helper.
    175  *
    176  * @param dh helper context
    177  * @param hdr message that we received
    178  * @return #GNUNET_OK on success
    179  */
    180 static enum GNUNET_GenericReturnValue
    181 handle_mt_avail (struct TALER_CRYPTO_RsaDenominationHelper *dh,
    182                  const struct GNUNET_MessageHeader *hdr)
    183 {
    184   const struct TALER_CRYPTO_RsaKeyAvailableNotification *kan
    185     = (const struct TALER_CRYPTO_RsaKeyAvailableNotification *) hdr;
    186   const char *buf = (const char *) &kan[1];
    187   const char *section_name;
    188   uint16_t ps;
    189   uint16_t snl;
    190 
    191   if (sizeof (*kan) > ntohs (hdr->size))
    192   {
    193     GNUNET_break_op (0);
    194     return GNUNET_SYSERR;
    195   }
    196   ps = ntohs (kan->pub_size);
    197   snl = ntohs (kan->section_name_len);
    198   if (ntohs (hdr->size) != sizeof (*kan) + ps + snl)
    199   {
    200     GNUNET_break_op (0);
    201     return GNUNET_SYSERR;
    202   }
    203   if (0 == snl)
    204   {
    205     GNUNET_break_op (0);
    206     return GNUNET_SYSERR;
    207   }
    208   section_name = &buf[ps];
    209   if ('\0' != section_name[snl - 1])
    210   {
    211     GNUNET_break_op (0);
    212     return GNUNET_SYSERR;
    213   }
    214 
    215   {
    216     struct GNUNET_CRYPTO_BlindSignPublicKey *bs_pub;
    217     struct TALER_RsaPubHashP h_rsa;
    218 
    219     bs_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
    220     bs_pub->cipher = GNUNET_CRYPTO_BSA_RSA;
    221     bs_pub->details.rsa_public_key
    222       = GNUNET_CRYPTO_rsa_public_key_decode (buf,
    223                                              ntohs (kan->pub_size));
    224     if (NULL == bs_pub->details.rsa_public_key)
    225     {
    226       GNUNET_break_op (0);
    227       GNUNET_free (bs_pub);
    228       return GNUNET_SYSERR;
    229     }
    230     bs_pub->rc = 1;
    231     GNUNET_CRYPTO_rsa_public_key_hash (bs_pub->details.rsa_public_key,
    232                                        &bs_pub->pub_key_hash);
    233     h_rsa.hash = bs_pub->pub_key_hash;
    234     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    235                 "Received RSA key %s (%s)\n",
    236                 GNUNET_h2s (&bs_pub->pub_key_hash),
    237                 section_name);
    238     if (GNUNET_OK !=
    239         TALER_exchange_secmod_rsa_verify (
    240           &h_rsa,
    241           section_name,
    242           GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
    243           GNUNET_TIME_relative_ntoh (kan->duration_withdraw),
    244           &kan->secm_pub,
    245           &kan->secm_sig))
    246     {
    247       GNUNET_break_op (0);
    248       GNUNET_CRYPTO_blind_sign_pub_decref (bs_pub);
    249       return GNUNET_SYSERR;
    250     }
    251     dh->dkc (dh->dkc_cls,
    252              section_name,
    253              GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
    254              GNUNET_TIME_relative_ntoh (kan->duration_withdraw),
    255              &h_rsa,
    256              bs_pub,
    257              &kan->secm_pub,
    258              &kan->secm_sig);
    259     GNUNET_CRYPTO_blind_sign_pub_decref (bs_pub);
    260   }
    261   return GNUNET_OK;
    262 }
    263 
    264 
    265 /**
    266  * Handle a #TALER_HELPER_RSA_MT_PURGE message from the helper.
    267  *
    268  * @param dh helper context
    269  * @param hdr message that we received
    270  * @return #GNUNET_OK on success
    271  */
    272 static enum GNUNET_GenericReturnValue
    273 handle_mt_purge (struct TALER_CRYPTO_RsaDenominationHelper *dh,
    274                  const struct GNUNET_MessageHeader *hdr)
    275 {
    276   const struct TALER_CRYPTO_RsaKeyPurgeNotification *pn
    277     = (const struct TALER_CRYPTO_RsaKeyPurgeNotification *) hdr;
    278 
    279   if (sizeof (*pn) != ntohs (hdr->size))
    280   {
    281     GNUNET_break_op (0);
    282     return GNUNET_SYSERR;
    283   }
    284   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    285               "Received revocation of denomination key %s\n",
    286               GNUNET_h2s (&pn->h_rsa.hash));
    287   dh->dkc (dh->dkc_cls,
    288            NULL,
    289            GNUNET_TIME_UNIT_ZERO_TS,
    290            GNUNET_TIME_UNIT_ZERO,
    291            &pn->h_rsa,
    292            NULL,
    293            NULL,
    294            NULL);
    295   return GNUNET_OK;
    296 }
    297 
    298 
    299 void
    300 TALER_CRYPTO_helper_rsa_poll (struct TALER_CRYPTO_RsaDenominationHelper *dh)
    301 {
    302   char buf[UINT16_MAX];
    303   size_t off = 0;
    304   unsigned int retry_limit = 3;
    305   const struct GNUNET_MessageHeader *hdr
    306     = (const struct GNUNET_MessageHeader *) buf;
    307 
    308   if (GNUNET_OK !=
    309       try_connect (dh))
    310     return; /* give up */
    311   while (1)
    312   {
    313     uint16_t msize;
    314     ssize_t ret;
    315 
    316     ret = recv (dh->sock,
    317                 buf + off,
    318                 sizeof (buf) - off,
    319                 (dh->synced && (0 == off))
    320                 ? MSG_DONTWAIT
    321                 : 0);
    322     if (ret < 0)
    323     {
    324       if (EINTR == errno)
    325         continue;
    326       if (EAGAIN == errno)
    327       {
    328         GNUNET_assert (dh->synced);
    329         GNUNET_assert (0 == off);
    330         break;
    331       }
    332       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    333                            "recv");
    334       do_disconnect (dh);
    335       if (0 == retry_limit)
    336         return; /* give up */
    337       if (GNUNET_OK !=
    338           try_connect (dh))
    339         return; /* give up */
    340       retry_limit--;
    341       continue;
    342     }
    343     if (0 == ret)
    344     {
    345       GNUNET_break (0 == off);
    346       return;
    347     }
    348     off += ret;
    349 more:
    350     if (off < sizeof (struct GNUNET_MessageHeader))
    351       continue;
    352     msize = ntohs (hdr->size);
    353     if (off < msize)
    354       continue;
    355     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    356                 "Received message of type %u and length %u\n",
    357                 (unsigned int) ntohs (hdr->type),
    358                 (unsigned int) msize);
    359     switch (ntohs (hdr->type))
    360     {
    361     case TALER_HELPER_RSA_MT_AVAIL:
    362       if (GNUNET_OK !=
    363           handle_mt_avail (dh,
    364                            hdr))
    365       {
    366         GNUNET_break_op (0);
    367         do_disconnect (dh);
    368         return;
    369       }
    370       break;
    371     case TALER_HELPER_RSA_MT_PURGE:
    372       if (GNUNET_OK !=
    373           handle_mt_purge (dh,
    374                            hdr))
    375       {
    376         GNUNET_break_op (0);
    377         do_disconnect (dh);
    378         return;
    379       }
    380       break;
    381     case TALER_HELPER_RSA_SYNCED:
    382       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    383                   "Now synchronized with RSA helper\n");
    384       dh->synced = true;
    385       break;
    386     default:
    387       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    388                   "Received unexpected message of type %d (len: %u)\n",
    389                   (unsigned int) ntohs (hdr->type),
    390                   (unsigned int) msize);
    391       GNUNET_break_op (0);
    392       do_disconnect (dh);
    393       return;
    394     }
    395     memmove (buf,
    396              &buf[msize],
    397              off - msize);
    398     off -= msize;
    399     goto more;
    400   }
    401 }
    402 
    403 
    404 enum TALER_ErrorCode
    405 TALER_CRYPTO_helper_rsa_sign (
    406   struct TALER_CRYPTO_RsaDenominationHelper *dh,
    407   const struct TALER_CRYPTO_RsaSignRequest *rsr,
    408   struct TALER_BlindedDenominationSignature *bs)
    409 {
    410   enum TALER_ErrorCode ec = TALER_EC_INVALID;
    411 
    412   memset (bs,
    413           0,
    414           sizeof (*bs));
    415   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    416               "Starting signature process\n");
    417   if (GNUNET_OK !=
    418       try_connect (dh))
    419   {
    420     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    421                 "Failed to connect to helper\n");
    422     return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
    423   }
    424 
    425   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    426               "Requesting signature\n");
    427   {
    428     char buf[sizeof (struct TALER_CRYPTO_SignRequest) + rsr->msg_size];
    429     struct TALER_CRYPTO_SignRequest *sr
    430       = (struct TALER_CRYPTO_SignRequest *) buf;
    431 
    432     sr->header.size = htons (sizeof (buf));
    433     sr->header.type = htons (TALER_HELPER_RSA_MT_REQ_SIGN);
    434     sr->reserved = htonl (0);
    435     sr->h_rsa = *rsr->h_rsa;
    436     GNUNET_memcpy (&sr[1],
    437                    rsr->msg,
    438                    rsr->msg_size);
    439     if (GNUNET_OK !=
    440         TALER_crypto_helper_send_all (dh->sock,
    441                                       buf,
    442                                       sizeof (buf)))
    443     {
    444       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    445                            "send");
    446       do_disconnect (dh);
    447       return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
    448     }
    449   }
    450 
    451   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    452               "Awaiting reply\n");
    453   {
    454     char buf[UINT16_MAX];
    455     size_t off = 0;
    456     const struct GNUNET_MessageHeader *hdr
    457       = (const struct GNUNET_MessageHeader *) buf;
    458     bool finished = false;
    459 
    460     while (1)
    461     {
    462       uint16_t msize;
    463       ssize_t ret;
    464 
    465       ret = recv (dh->sock,
    466                   &buf[off],
    467                   sizeof (buf) - off,
    468                   (finished && (0 == off))
    469                   ? MSG_DONTWAIT
    470                   : 0);
    471       if (ret < 0)
    472       {
    473         if (EINTR == errno)
    474           continue;
    475         if (EAGAIN == errno)
    476         {
    477           GNUNET_assert (finished);
    478           GNUNET_assert (0 == off);
    479           return ec;
    480         }
    481         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    482                              "recv");
    483         do_disconnect (dh);
    484         ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
    485         break;
    486       }
    487       if (0 == ret)
    488       {
    489         GNUNET_break (0 == off);
    490         if (! finished)
    491           ec = TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    492         return ec;
    493       }
    494       off += ret;
    495 more:
    496       if (off < sizeof (struct GNUNET_MessageHeader))
    497         continue;
    498       msize = ntohs (hdr->size);
    499       if (off < msize)
    500         continue;
    501       switch (ntohs (hdr->type))
    502       {
    503       case TALER_HELPER_RSA_MT_RES_SIGNATURE:
    504         if (msize < sizeof (struct TALER_CRYPTO_SignResponse))
    505         {
    506           GNUNET_break_op (0);
    507           do_disconnect (dh);
    508           ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    509           goto end;
    510         }
    511         if (finished)
    512         {
    513           GNUNET_break_op (0);
    514           do_disconnect (dh);
    515           ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    516           goto end;
    517         }
    518         {
    519           const struct TALER_CRYPTO_SignResponse *sr =
    520             (const struct TALER_CRYPTO_SignResponse *) buf;
    521           struct GNUNET_CRYPTO_RsaSignature *rsa_signature;
    522           struct GNUNET_CRYPTO_BlindedSignature *blind_sig;
    523 
    524           rsa_signature = GNUNET_CRYPTO_rsa_signature_decode (
    525             &sr[1],
    526             msize - sizeof (*sr));
    527           if (NULL == rsa_signature)
    528           {
    529             GNUNET_break_op (0);
    530             do_disconnect (dh);
    531             ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    532             goto end;
    533           }
    534           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    535                       "Received signature\n");
    536           ec = TALER_EC_NONE;
    537           finished = true;
    538           blind_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
    539           blind_sig->cipher = GNUNET_CRYPTO_BSA_RSA;
    540           blind_sig->rc = 1;
    541           blind_sig->details.blinded_rsa_signature = rsa_signature;
    542           bs->blinded_sig = blind_sig;
    543           break;
    544         }
    545       case TALER_HELPER_RSA_MT_RES_SIGN_FAILURE:
    546         if (msize != sizeof (struct TALER_CRYPTO_SignFailure))
    547         {
    548           GNUNET_break_op (0);
    549           do_disconnect (dh);
    550           ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    551           goto end;
    552         }
    553         {
    554           const struct TALER_CRYPTO_SignFailure *sf =
    555             (const struct TALER_CRYPTO_SignFailure *) buf;
    556 
    557           ec = (enum TALER_ErrorCode) (int) ntohl (sf->ec);
    558           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    559                       "Signing failed!\n");
    560           finished = true;
    561           break;
    562         }
    563       case TALER_HELPER_RSA_MT_AVAIL:
    564         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    565                     "Received new key!\n");
    566         if (GNUNET_OK !=
    567             handle_mt_avail (dh,
    568                              hdr))
    569         {
    570           GNUNET_break_op (0);
    571           do_disconnect (dh);
    572           ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    573           goto end;
    574         }
    575         break; /* while(1) loop ensures we recvfrom() again */
    576       case TALER_HELPER_RSA_MT_PURGE:
    577         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    578                     "Received revocation!\n");
    579         if (GNUNET_OK !=
    580             handle_mt_purge (dh,
    581                              hdr))
    582         {
    583           GNUNET_break_op (0);
    584           do_disconnect (dh);
    585           ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    586           goto end;
    587         }
    588         break; /* while(1) loop ensures we recvfrom() again */
    589       case TALER_HELPER_RSA_SYNCED:
    590         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    591                     "Synchronized add odd time with RSA helper!\n");
    592         dh->synced = true;
    593         break;
    594       default:
    595         GNUNET_break_op (0);
    596         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    597                     "Received unexpected message of type %u\n",
    598                     ntohs (hdr->type));
    599         do_disconnect (dh);
    600         ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    601         goto end;
    602       }
    603       memmove (buf,
    604                &buf[msize],
    605                off - msize);
    606       off -= msize;
    607       goto more;
    608     } /* while(1) */
    609 end:
    610     if (finished)
    611       TALER_blinded_denom_sig_free (bs);
    612     return ec;
    613   }
    614 }
    615 
    616 
    617 enum TALER_ErrorCode
    618 TALER_CRYPTO_helper_rsa_batch_sign (
    619   struct TALER_CRYPTO_RsaDenominationHelper *dh,
    620   unsigned int rsrs_length,
    621   const struct TALER_CRYPTO_RsaSignRequest rsrs[static rsrs_length],
    622   struct TALER_BlindedDenominationSignature bss[static rsrs_length])
    623 {
    624   enum TALER_ErrorCode ec = TALER_EC_INVALID;
    625   unsigned int rpos;
    626   unsigned int rend;
    627   unsigned int wpos;
    628 
    629   memset (bss,
    630           0,
    631           sizeof (*bss) * rsrs_length);
    632   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    633               "Starting signature process\n");
    634   if (GNUNET_OK !=
    635       try_connect (dh))
    636   {
    637     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    638                 "Failed to connect to helper\n");
    639     return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
    640   }
    641   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    642               "Requesting %u signatures\n",
    643               rsrs_length);
    644   rpos = 0;
    645   rend = 0;
    646   wpos = 0;
    647   while (rpos < rsrs_length)
    648   {
    649     unsigned int mlen = sizeof (struct TALER_CRYPTO_BatchSignRequest);
    650 
    651     while ( (rend < rsrs_length) &&
    652             (mlen
    653              + sizeof (struct TALER_CRYPTO_SignRequest)
    654              + rsrs[rend].msg_size < UINT16_MAX) )
    655     {
    656       mlen += sizeof (struct TALER_CRYPTO_SignRequest) + rsrs[rend].msg_size;
    657       rend++;
    658     }
    659     {
    660       char obuf[mlen] GNUNET_ALIGN;
    661       struct TALER_CRYPTO_BatchSignRequest *bsr
    662         = (struct TALER_CRYPTO_BatchSignRequest *) obuf;
    663       void *wbuf;
    664 
    665       bsr->header.type = htons (TALER_HELPER_RSA_MT_REQ_BATCH_SIGN);
    666       bsr->header.size = htons (mlen);
    667       bsr->batch_size = htonl (rend - rpos);
    668       wbuf = &bsr[1];
    669       for (unsigned int i = rpos; i<rend; i++)
    670       {
    671         struct TALER_CRYPTO_SignRequest *sr = wbuf;
    672         const struct TALER_CRYPTO_RsaSignRequest *rsr = &rsrs[i];
    673 
    674         sr->header.type = htons (TALER_HELPER_RSA_MT_REQ_SIGN);
    675         sr->header.size = htons (sizeof (*sr) + rsr->msg_size);
    676         sr->reserved = htonl (0);
    677         sr->h_rsa = *rsr->h_rsa;
    678         GNUNET_memcpy (&sr[1],
    679                        rsr->msg,
    680                        rsr->msg_size);
    681         wbuf += sizeof (*sr) + rsr->msg_size;
    682       }
    683       GNUNET_assert (wbuf == &obuf[mlen]);
    684       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    685                   "Sending batch request [%u-%u)\n",
    686                   rpos,
    687                   rend);
    688       if (GNUNET_OK !=
    689           TALER_crypto_helper_send_all (dh->sock,
    690                                         obuf,
    691                                         sizeof (obuf)))
    692       {
    693         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    694                              "send");
    695         do_disconnect (dh);
    696         return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
    697       }
    698     }
    699     rpos = rend;
    700     {
    701       char buf[UINT16_MAX];
    702       size_t off = 0;
    703       const struct GNUNET_MessageHeader *hdr
    704         = (const struct GNUNET_MessageHeader *) buf;
    705       bool finished = false;
    706 
    707       while (1)
    708       {
    709         uint16_t msize;
    710         ssize_t ret;
    711 
    712         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    713                     "Awaiting reply at %u (up to %u)\n",
    714                     wpos,
    715                     rend);
    716         ret = recv (dh->sock,
    717                     &buf[off],
    718                     sizeof (buf) - off,
    719                     (finished && (0 == off))
    720                   ? MSG_DONTWAIT
    721                   : 0);
    722         if (ret < 0)
    723         {
    724           if (EINTR == errno)
    725             continue;
    726           if (EAGAIN == errno)
    727           {
    728             GNUNET_assert (finished);
    729             GNUNET_assert (0 == off);
    730             break;
    731           }
    732           GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    733                                "recv");
    734           do_disconnect (dh);
    735           ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
    736           break;
    737         }
    738         if (0 == ret)
    739         {
    740           GNUNET_break (0 == off);
    741           if (! finished)
    742             ec = TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    743           if (TALER_EC_NONE == ec)
    744             break;
    745           return ec;
    746         }
    747         off += ret;
    748 more:
    749         if (off < sizeof (struct GNUNET_MessageHeader))
    750           continue;
    751         msize = ntohs (hdr->size);
    752         if (off < msize)
    753           continue;
    754         switch (ntohs (hdr->type))
    755         {
    756         case TALER_HELPER_RSA_MT_RES_SIGNATURE:
    757           if (msize < sizeof (struct TALER_CRYPTO_SignResponse))
    758           {
    759             GNUNET_break_op (0);
    760             do_disconnect (dh);
    761             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    762           }
    763           if (finished)
    764           {
    765             GNUNET_break_op (0);
    766             do_disconnect (dh);
    767             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    768           }
    769           {
    770             const struct TALER_CRYPTO_SignResponse *sr =
    771               (const struct TALER_CRYPTO_SignResponse *) buf;
    772             struct GNUNET_CRYPTO_RsaSignature *rsa_signature;
    773             struct GNUNET_CRYPTO_BlindedSignature *blind_sig;
    774 
    775             rsa_signature = GNUNET_CRYPTO_rsa_signature_decode (
    776               &sr[1],
    777               msize - sizeof (*sr));
    778             if (NULL == rsa_signature)
    779             {
    780               GNUNET_break_op (0);
    781               do_disconnect (dh);
    782               return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    783             }
    784             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    785                         "Received %u signature\n",
    786                         wpos);
    787             blind_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
    788             blind_sig->cipher = GNUNET_CRYPTO_BSA_RSA;
    789             blind_sig->rc = 1;
    790             blind_sig->details.blinded_rsa_signature = rsa_signature;
    791             bss[wpos].blinded_sig = blind_sig;
    792             wpos++;
    793             if (wpos == rend)
    794             {
    795               if (TALER_EC_INVALID == ec)
    796                 ec = TALER_EC_NONE;
    797               finished = true;
    798             }
    799             break;
    800           }
    801         case TALER_HELPER_RSA_MT_RES_SIGN_FAILURE:
    802           if (msize != sizeof (struct TALER_CRYPTO_SignFailure))
    803           {
    804             GNUNET_break_op (0);
    805             do_disconnect (dh);
    806             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    807           }
    808           {
    809             const struct TALER_CRYPTO_SignFailure *sf =
    810               (const struct TALER_CRYPTO_SignFailure *) buf;
    811 
    812             ec = (enum TALER_ErrorCode) (int) ntohl (sf->ec);
    813             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    814                         "Signing %u failed with status %d!\n",
    815                         wpos,
    816                         ec);
    817             wpos++;
    818             if (wpos == rend)
    819             {
    820               finished = true;
    821             }
    822             break;
    823           }
    824         case TALER_HELPER_RSA_MT_AVAIL:
    825           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    826                       "Received new key!\n");
    827           if (GNUNET_OK !=
    828               handle_mt_avail (dh,
    829                                hdr))
    830           {
    831             GNUNET_break_op (0);
    832             do_disconnect (dh);
    833             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    834           }
    835           break; /* while(1) loop ensures we recvfrom() again */
    836         case TALER_HELPER_RSA_MT_PURGE:
    837           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    838                       "Received revocation!\n");
    839           if (GNUNET_OK !=
    840               handle_mt_purge (dh,
    841                                hdr))
    842           {
    843             GNUNET_break_op (0);
    844             do_disconnect (dh);
    845             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    846           }
    847           break; /* while(1) loop ensures we recvfrom() again */
    848         case TALER_HELPER_RSA_SYNCED:
    849           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    850                       "Synchronized add odd time with RSA helper!\n");
    851           dh->synced = true;
    852           break;
    853         default:
    854           GNUNET_break_op (0);
    855           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    856                       "Received unexpected message of type %u\n",
    857                       ntohs (hdr->type));
    858           do_disconnect (dh);
    859           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    860         }
    861         memmove (buf,
    862                  &buf[msize],
    863                  off - msize);
    864         off -= msize;
    865         goto more;
    866       } /* while(1) */
    867     } /* scope */
    868   }   /* while (rpos < rsrs_length) */
    869   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    870               "Existing with %u signatures and status %d\n",
    871               wpos,
    872               ec);
    873   return ec;
    874 }
    875 
    876 
    877 void
    878 TALER_CRYPTO_helper_rsa_revoke (
    879   struct TALER_CRYPTO_RsaDenominationHelper *dh,
    880   const struct TALER_RsaPubHashP *h_rsa)
    881 {
    882   struct TALER_CRYPTO_RevokeRequest rr = {
    883     .header.size = htons (sizeof (rr)),
    884     .header.type = htons (TALER_HELPER_RSA_MT_REQ_REVOKE),
    885     .h_rsa = *h_rsa
    886   };
    887 
    888   if (GNUNET_OK !=
    889       try_connect (dh))
    890     return; /* give up */
    891   if (GNUNET_OK !=
    892       TALER_crypto_helper_send_all (dh->sock,
    893                                     &rr,
    894                                     sizeof (rr)))
    895   {
    896     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    897                          "send");
    898     do_disconnect (dh);
    899     return;
    900   }
    901   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    902               "Requested revocation of denomination key %s\n",
    903               GNUNET_h2s (&h_rsa->hash));
    904 }
    905 
    906 
    907 void
    908 TALER_CRYPTO_helper_rsa_disconnect (
    909   struct TALER_CRYPTO_RsaDenominationHelper *dh)
    910 {
    911   if (-1 != dh->sock)
    912     do_disconnect (dh);
    913   GNUNET_free (dh);
    914 }
    915 
    916 
    917 /* end of crypto_helper_denom.c */