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 (20170B)


      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 "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_batch_sign (
    406   struct TALER_CRYPTO_RsaDenominationHelper *dh,
    407   unsigned int rsrs_length,
    408   const struct TALER_CRYPTO_RsaSignRequest rsrs[static rsrs_length],
    409   struct TALER_BlindedDenominationSignature bss[static rsrs_length])
    410 {
    411   enum TALER_ErrorCode ec = TALER_EC_INVALID;
    412   unsigned int rpos;
    413   unsigned int rend;
    414   unsigned int wpos;
    415 
    416   memset (bss,
    417           0,
    418           sizeof (*bss) * rsrs_length);
    419   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    420               "Starting signature process\n");
    421   if (GNUNET_OK !=
    422       try_connect (dh))
    423   {
    424     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    425                 "Failed to connect to helper\n");
    426     return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
    427   }
    428   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    429               "Requesting %u signatures\n",
    430               rsrs_length);
    431   rpos = 0;
    432   rend = 0;
    433   wpos = 0;
    434   while (rpos < rsrs_length)
    435   {
    436     unsigned int mlen = sizeof (struct TALER_CRYPTO_BatchSignRequest);
    437 
    438     while ( (rend < rsrs_length) &&
    439             (mlen
    440              + sizeof (struct TALER_CRYPTO_SignRequest)
    441              + rsrs[rend].msg_size < UINT16_MAX) )
    442     {
    443       mlen += sizeof (struct TALER_CRYPTO_SignRequest) + rsrs[rend].msg_size;
    444       rend++;
    445     }
    446     {
    447       char obuf[mlen] GNUNET_ALIGN;
    448       struct TALER_CRYPTO_BatchSignRequest *bsr
    449         = (struct TALER_CRYPTO_BatchSignRequest *) obuf;
    450       void *wbuf;
    451 
    452       bsr->header.type = htons (TALER_HELPER_RSA_MT_REQ_BATCH_SIGN);
    453       bsr->header.size = htons (mlen);
    454       bsr->batch_size = htonl (rend - rpos);
    455       wbuf = &bsr[1];
    456       for (unsigned int i = rpos; i<rend; i++)
    457       {
    458         struct TALER_CRYPTO_SignRequest *sr = wbuf;
    459         const struct TALER_CRYPTO_RsaSignRequest *rsr = &rsrs[i];
    460 
    461         sr->header.type = htons (TALER_HELPER_RSA_MT_REQ_SIGN);
    462         sr->header.size = htons (sizeof (*sr) + rsr->msg_size);
    463         sr->reserved = htonl (0);
    464         sr->h_rsa = *rsr->h_rsa;
    465         GNUNET_memcpy (&sr[1],
    466                        rsr->msg,
    467                        rsr->msg_size);
    468         wbuf += sizeof (*sr) + rsr->msg_size;
    469       }
    470       GNUNET_assert (wbuf == &obuf[mlen]);
    471       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    472                   "Sending batch request [%u-%u)\n",
    473                   rpos,
    474                   rend);
    475       if (GNUNET_OK !=
    476           TALER_crypto_helper_send_all (dh->sock,
    477                                         obuf,
    478                                         sizeof (obuf)))
    479       {
    480         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    481                              "send");
    482         do_disconnect (dh);
    483         return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
    484       }
    485     }
    486     rpos = rend;
    487     {
    488       char buf[UINT16_MAX];
    489       size_t off = 0;
    490       const struct GNUNET_MessageHeader *hdr
    491         = (const struct GNUNET_MessageHeader *) buf;
    492       bool finished = false;
    493 
    494       while (1)
    495       {
    496         uint16_t msize;
    497         ssize_t ret;
    498 
    499         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    500                     "Awaiting reply at %u (up to %u)\n",
    501                     wpos,
    502                     rend);
    503         ret = recv (dh->sock,
    504                     &buf[off],
    505                     sizeof (buf) - off,
    506                     (finished && (0 == off))
    507                   ? MSG_DONTWAIT
    508                   : 0);
    509         if (ret < 0)
    510         {
    511           if (EINTR == errno)
    512             continue;
    513           if (EAGAIN == errno)
    514           {
    515             GNUNET_assert (finished);
    516             GNUNET_assert (0 == off);
    517             break;
    518           }
    519           GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    520                                "recv");
    521           do_disconnect (dh);
    522           ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
    523           break;
    524         }
    525         if (0 == ret)
    526         {
    527           GNUNET_break (0 == off);
    528           if (! finished)
    529             ec = TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    530           if (TALER_EC_NONE == ec)
    531             break;
    532           return ec;
    533         }
    534         off += ret;
    535 more:
    536         if (off < sizeof (struct GNUNET_MessageHeader))
    537           continue;
    538         msize = ntohs (hdr->size);
    539         if (off < msize)
    540           continue;
    541         switch (ntohs (hdr->type))
    542         {
    543         case TALER_HELPER_RSA_MT_RES_SIGNATURE:
    544           if (msize < sizeof (struct TALER_CRYPTO_SignResponse))
    545           {
    546             GNUNET_break_op (0);
    547             do_disconnect (dh);
    548             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    549           }
    550           if (finished)
    551           {
    552             GNUNET_break_op (0);
    553             do_disconnect (dh);
    554             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    555           }
    556           {
    557             const struct TALER_CRYPTO_SignResponse *sr =
    558               (const struct TALER_CRYPTO_SignResponse *) buf;
    559             struct GNUNET_CRYPTO_RsaSignature *rsa_signature;
    560             struct GNUNET_CRYPTO_BlindedSignature *blind_sig;
    561 
    562             rsa_signature = GNUNET_CRYPTO_rsa_signature_decode (
    563               &sr[1],
    564               msize - sizeof (*sr));
    565             if (NULL == rsa_signature)
    566             {
    567               GNUNET_break_op (0);
    568               do_disconnect (dh);
    569               return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    570             }
    571             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    572                         "Received %u signature\n",
    573                         wpos);
    574             blind_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
    575             blind_sig->cipher = GNUNET_CRYPTO_BSA_RSA;
    576             blind_sig->rc = 1;
    577             blind_sig->details.blinded_rsa_signature = rsa_signature;
    578             bss[wpos].blinded_sig = blind_sig;
    579             wpos++;
    580             if (wpos == rend)
    581             {
    582               if (TALER_EC_INVALID == ec)
    583                 ec = TALER_EC_NONE;
    584               finished = true;
    585             }
    586             break;
    587           }
    588         case TALER_HELPER_RSA_MT_RES_SIGN_FAILURE:
    589           if (msize != sizeof (struct TALER_CRYPTO_SignFailure))
    590           {
    591             GNUNET_break_op (0);
    592             do_disconnect (dh);
    593             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    594           }
    595           {
    596             const struct TALER_CRYPTO_SignFailure *sf =
    597               (const struct TALER_CRYPTO_SignFailure *) buf;
    598 
    599             ec = (enum TALER_ErrorCode) (int) ntohl (sf->ec);
    600             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    601                         "Signing %u failed with status %d!\n",
    602                         wpos,
    603                         ec);
    604             wpos++;
    605             if (wpos == rend)
    606             {
    607               finished = true;
    608             }
    609             break;
    610           }
    611         case TALER_HELPER_RSA_MT_AVAIL:
    612           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    613                       "Received new key!\n");
    614           if (GNUNET_OK !=
    615               handle_mt_avail (dh,
    616                                hdr))
    617           {
    618             GNUNET_break_op (0);
    619             do_disconnect (dh);
    620             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    621           }
    622           break; /* while(1) loop ensures we recvfrom() again */
    623         case TALER_HELPER_RSA_MT_PURGE:
    624           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    625                       "Received revocation!\n");
    626           if (GNUNET_OK !=
    627               handle_mt_purge (dh,
    628                                hdr))
    629           {
    630             GNUNET_break_op (0);
    631             do_disconnect (dh);
    632             return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    633           }
    634           break; /* while(1) loop ensures we recvfrom() again */
    635         case TALER_HELPER_RSA_SYNCED:
    636           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    637                       "Synchronized add odd time with RSA helper!\n");
    638           dh->synced = true;
    639           break;
    640         default:
    641           GNUNET_break_op (0);
    642           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    643                       "Received unexpected message of type %u\n",
    644                       ntohs (hdr->type));
    645           do_disconnect (dh);
    646           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
    647         }
    648         memmove (buf,
    649                  &buf[msize],
    650                  off - msize);
    651         off -= msize;
    652         goto more;
    653       } /* while(1) */
    654     } /* scope */
    655   }   /* while (rpos < rsrs_length) */
    656   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    657               "Existing with %u signatures and status %d\n",
    658               wpos,
    659               ec);
    660   return ec;
    661 }
    662 
    663 
    664 void
    665 TALER_CRYPTO_helper_rsa_revoke (
    666   struct TALER_CRYPTO_RsaDenominationHelper *dh,
    667   const struct TALER_RsaPubHashP *h_rsa)
    668 {
    669   struct TALER_CRYPTO_RevokeRequest rr = {
    670     .header.size = htons (sizeof (rr)),
    671     .header.type = htons (TALER_HELPER_RSA_MT_REQ_REVOKE),
    672     .h_rsa = *h_rsa
    673   };
    674 
    675   if (GNUNET_OK !=
    676       try_connect (dh))
    677     return; /* give up */
    678   if (GNUNET_OK !=
    679       TALER_crypto_helper_send_all (dh->sock,
    680                                     &rr,
    681                                     sizeof (rr)))
    682   {
    683     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    684                          "send");
    685     do_disconnect (dh);
    686     return;
    687   }
    688   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    689               "Requested revocation of denomination key %s\n",
    690               GNUNET_h2s (&h_rsa->hash));
    691 }
    692 
    693 
    694 void
    695 TALER_CRYPTO_helper_rsa_disconnect (
    696   struct TALER_CRYPTO_RsaDenominationHelper *dh)
    697 {
    698   if (-1 != dh->sock)
    699     do_disconnect (dh);
    700   GNUNET_free (dh);
    701 }
    702 
    703 
    704 /* end of crypto_helper_denom.c */