LCOV - code coverage report
Current view: top level - util - crypto_helper_cs.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 231 392 58.9 %
Date: 2022-08-25 06:15:09 Functions: 14 14 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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_cs.c
      18             :  * @brief utility functions for running out-of-process private key operations
      19             :  * @author Christian Grothoff
      20             :  */
      21             : #include "platform.h"
      22             : #include "taler_util.h"
      23             : #include "taler_signatures.h"
      24             : #include "taler-exchange-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           9 : do_disconnect (struct TALER_CRYPTO_CsDenominationHelper *dh)
      67             : {
      68           9 :   GNUNET_break (0 == close (dh->sock));
      69           9 :   dh->sock = -1;
      70           9 :   dh->synced = false;
      71           9 : }
      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         960 : try_connect (struct TALER_CRYPTO_CsDenominationHelper *dh)
      83             : {
      84         960 :   if (-1 != dh->sock)
      85         951 :     return GNUNET_OK;
      86           9 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
      87             :               "Establishing connection!\n");
      88           9 :   dh->sock = socket (AF_UNIX,
      89             :                      SOCK_STREAM,
      90             :                      0);
      91           9 :   if (-1 == dh->sock)
      92             :   {
      93           0 :     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
      94             :                          "socket");
      95           0 :     return GNUNET_SYSERR;
      96             :   }
      97           9 :   if (0 !=
      98           9 :       connect (dh->sock,
      99           9 :                (const struct sockaddr *) &dh->sa,
     100             :                sizeof (dh->sa)))
     101             :   {
     102           0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
     103             :                               "connect",
     104             :                               dh->sa.sun_path);
     105           0 :     do_disconnect (dh);
     106           0 :     return GNUNET_SYSERR;
     107             :   }
     108           9 :   TALER_CRYPTO_helper_cs_poll (dh);
     109           9 :   return GNUNET_OK;
     110             : }
     111             : 
     112             : 
     113             : struct TALER_CRYPTO_CsDenominationHelper *
     114           9 : TALER_CRYPTO_helper_cs_connect (
     115             :   const struct GNUNET_CONFIGURATION_Handle *cfg,
     116             :   TALER_CRYPTO_CsDenominationKeyStatusCallback dkc,
     117             :   void *dkc_cls)
     118             : {
     119             :   struct TALER_CRYPTO_CsDenominationHelper *dh;
     120             :   char *unixpath;
     121             : 
     122           9 :   if (GNUNET_OK !=
     123           9 :       GNUNET_CONFIGURATION_get_value_filename (cfg,
     124             :                                                "taler-exchange-secmod-cs",
     125             :                                                "UNIXPATH",
     126             :                                                &unixpath))
     127             :   {
     128           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     129             :                                "taler-exchange-secmod-cs",
     130             :                                "UNIXPATH");
     131           0 :     return NULL;
     132             :   }
     133             :   /* we use >= here because we want the sun_path to always
     134             :      be 0-terminated */
     135           9 :   if (strlen (unixpath) >= sizeof (dh->sa.sun_path))
     136             :   {
     137           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     138             :                                "taler-exchange-secmod-cs",
     139             :                                "UNIXPATH",
     140             :                                "path too long");
     141           0 :     GNUNET_free (unixpath);
     142           0 :     return NULL;
     143             :   }
     144           9 :   dh = GNUNET_new (struct TALER_CRYPTO_CsDenominationHelper);
     145           9 :   dh->dkc = dkc;
     146           9 :   dh->dkc_cls = dkc_cls;
     147           9 :   dh->sa.sun_family = AF_UNIX;
     148           9 :   strncpy (dh->sa.sun_path,
     149             :            unixpath,
     150             :            sizeof (dh->sa.sun_path) - 1);
     151           9 :   GNUNET_free (unixpath);
     152           9 :   dh->sock = -1;
     153           9 :   if (GNUNET_OK !=
     154           9 :       try_connect (dh))
     155             :   {
     156           0 :     TALER_CRYPTO_helper_cs_disconnect (dh);
     157           0 :     return NULL;
     158             :   }
     159           9 :   return dh;
     160             : }
     161             : 
     162             : 
     163             : /**
     164             :  * Handle a #TALER_HELPER_CS_MT_AVAIL message from the helper.
     165             :  *
     166             :  * @param dh helper context
     167             :  * @param hdr message that we received
     168             :  * @return #GNUNET_OK on success
     169             :  */
     170             : static enum GNUNET_GenericReturnValue
     171          81 : handle_mt_avail (struct TALER_CRYPTO_CsDenominationHelper *dh,
     172             :                  const struct GNUNET_MessageHeader *hdr)
     173             : {
     174          81 :   const struct TALER_CRYPTO_CsKeyAvailableNotification *kan
     175             :     = (const struct TALER_CRYPTO_CsKeyAvailableNotification *) hdr;
     176          81 :   const char *buf = (const char *) &kan[1];
     177             :   const char *section_name;
     178             :   uint16_t snl;
     179             : 
     180          81 :   if (sizeof (*kan) > ntohs (hdr->size))
     181             :   {
     182           0 :     GNUNET_break_op (0);
     183           0 :     return GNUNET_SYSERR;
     184             :   }
     185          81 :   snl = ntohs (kan->section_name_len);
     186          81 :   if (ntohs (hdr->size) != sizeof (*kan) + snl)
     187             :   {
     188           0 :     GNUNET_break_op (0);
     189           0 :     return GNUNET_SYSERR;
     190             :   }
     191          81 :   if (0 == snl)
     192             :   {
     193           0 :     GNUNET_break_op (0);
     194           0 :     return GNUNET_SYSERR;
     195             :   }
     196          81 :   section_name = buf;
     197          81 :   if ('\0' != section_name[snl - 1])
     198             :   {
     199           0 :     GNUNET_break_op (0);
     200           0 :     return GNUNET_SYSERR;
     201             :   }
     202             : 
     203             :   {
     204             :     struct TALER_DenominationPublicKey denom_pub;
     205             :     struct TALER_CsPubHashP h_cs;
     206             : 
     207          81 :     denom_pub.cipher = TALER_DENOMINATION_CS;
     208          81 :     denom_pub.details.cs_public_key = kan->denom_pub;
     209             : 
     210          81 :     TALER_cs_pub_hash (&denom_pub.details.cs_public_key, &h_cs);
     211          81 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     212             :                 "Received CS key %s (%s)\n",
     213             :                 GNUNET_h2s (&h_cs.hash),
     214             :                 section_name);
     215          81 :     if (GNUNET_OK !=
     216          81 :         TALER_exchange_secmod_cs_verify (
     217             :           &h_cs,
     218             :           section_name,
     219             :           GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
     220             :           GNUNET_TIME_relative_ntoh (kan->duration_withdraw),
     221             :           &kan->secm_pub,
     222             :           &kan->secm_sig))
     223             :     {
     224           0 :       GNUNET_break_op (0);
     225           0 :       TALER_denom_pub_free (&denom_pub);
     226           0 :       return GNUNET_SYSERR;
     227             :     }
     228          81 :     dh->dkc (dh->dkc_cls,
     229             :              section_name,
     230             :              GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
     231             :              GNUNET_TIME_relative_ntoh (kan->duration_withdraw),
     232             :              &h_cs,
     233             :              &denom_pub,
     234             :              &kan->secm_pub,
     235             :              &kan->secm_sig);
     236          81 :     TALER_denom_pub_free (&denom_pub);
     237             :   }
     238          81 :   return GNUNET_OK;
     239             : }
     240             : 
     241             : 
     242             : /**
     243             :  * Handle a #TALER_HELPER_CS_MT_PURGE message from the helper.
     244             :  *
     245             :  * @param dh helper context
     246             :  * @param hdr message that we received
     247             :  * @return #GNUNET_OK on success
     248             :  */
     249             : static enum GNUNET_GenericReturnValue
     250           3 : handle_mt_purge (struct TALER_CRYPTO_CsDenominationHelper *dh,
     251             :                  const struct GNUNET_MessageHeader *hdr)
     252             : {
     253           3 :   const struct TALER_CRYPTO_CsKeyPurgeNotification *pn
     254             :     = (const struct TALER_CRYPTO_CsKeyPurgeNotification *) hdr;
     255             : 
     256           3 :   if (sizeof (*pn) != ntohs (hdr->size))
     257             :   {
     258           0 :     GNUNET_break_op (0);
     259           0 :     return GNUNET_SYSERR;
     260             :   }
     261           3 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     262             :               "Received revocation of denomination key %s\n",
     263             :               GNUNET_h2s (&pn->h_cs.hash));
     264           3 :   dh->dkc (dh->dkc_cls,
     265             :            NULL,
     266           3 :            GNUNET_TIME_UNIT_ZERO_TS,
     267           3 :            GNUNET_TIME_UNIT_ZERO,
     268             :            &pn->h_cs,
     269             :            NULL,
     270             :            NULL,
     271             :            NULL);
     272           3 :   return GNUNET_OK;
     273             : }
     274             : 
     275             : 
     276             : void
     277          24 : TALER_CRYPTO_helper_cs_poll (struct TALER_CRYPTO_CsDenominationHelper *dh)
     278             : {
     279             :   char buf[UINT16_MAX];
     280          24 :   size_t off = 0;
     281          24 :   unsigned int retry_limit = 3;
     282          24 :   const struct GNUNET_MessageHeader *hdr
     283             :     = (const struct GNUNET_MessageHeader *) buf;
     284             : 
     285          24 :   if (GNUNET_OK !=
     286          24 :       try_connect (dh))
     287           0 :     return; /* give up */
     288             :   while (1)
     289          12 :   {
     290             :     uint16_t msize;
     291             :     ssize_t ret;
     292             : 
     293          36 :     ret = recv (dh->sock,
     294             :                 buf + off,
     295             :                 sizeof (buf) - off,
     296          36 :                 (dh->synced && (0 == off))
     297             :                 ? MSG_DONTWAIT
     298             :                 : 0);
     299          36 :     if (ret < 0)
     300             :     {
     301          24 :       if (EINTR == errno)
     302           0 :         continue;
     303          24 :       if (EAGAIN == errno)
     304             :       {
     305          24 :         GNUNET_assert (dh->synced);
     306          24 :         GNUNET_assert (0 == off);
     307          24 :         break;
     308             :       }
     309           0 :       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
     310             :                            "recv");
     311           0 :       do_disconnect (dh);
     312           0 :       if (0 == retry_limit)
     313           0 :         return; /* give up */
     314           0 :       if (GNUNET_OK !=
     315           0 :           try_connect (dh))
     316           0 :         return; /* give up */
     317           0 :       retry_limit--;
     318           0 :       continue;
     319             :     }
     320          12 :     if (0 == ret)
     321             :     {
     322           0 :       GNUNET_break (0 == off);
     323           0 :       return;
     324             :     }
     325          12 :     off += ret;
     326         105 : more:
     327         105 :     if (off < sizeof (struct GNUNET_MessageHeader))
     328          12 :       continue;
     329          93 :     msize = ntohs (hdr->size);
     330          93 :     if (off < msize)
     331           0 :       continue;
     332          93 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     333             :                 "Received message of type %u and length %u\n",
     334             :                 (unsigned int) ntohs (hdr->type),
     335             :                 (unsigned int) msize);
     336          93 :     switch (ntohs (hdr->type))
     337             :     {
     338          81 :     case TALER_HELPER_CS_MT_AVAIL:
     339          81 :       if (GNUNET_OK !=
     340          81 :           handle_mt_avail (dh,
     341             :                            hdr))
     342             :       {
     343           0 :         GNUNET_break_op (0);
     344           0 :         do_disconnect (dh);
     345           0 :         return;
     346             :       }
     347          81 :       break;
     348           3 :     case TALER_HELPER_CS_MT_PURGE:
     349           3 :       if (GNUNET_OK !=
     350           3 :           handle_mt_purge (dh,
     351             :                            hdr))
     352             :       {
     353           0 :         GNUNET_break_op (0);
     354           0 :         do_disconnect (dh);
     355           0 :         return;
     356             :       }
     357           3 :       break;
     358           9 :     case TALER_HELPER_CS_SYNCED:
     359           9 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     360             :                   "Now synchronized with CS helper\n");
     361           9 :       dh->synced = true;
     362           9 :       break;
     363           0 :     default:
     364           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     365             :                   "Received unexpected message of type %d (len: %u)\n",
     366             :                   (unsigned int) ntohs (hdr->type),
     367             :                   (unsigned int) msize);
     368           0 :       GNUNET_break_op (0);
     369           0 :       do_disconnect (dh);
     370           0 :       return;
     371             :     }
     372          93 :     memmove (buf,
     373          93 :              &buf[msize],
     374             :              off - msize);
     375          93 :     off -= msize;
     376          93 :     goto more;
     377             :   }
     378             : }
     379             : 
     380             : 
     381             : /**
     382             :  * Request helper @a dh to sign @a msg using the public key corresponding to
     383             :  * @a h_denom_pub.
     384             :  *
     385             :  * This operation will block until the signature has been obtained.  Should
     386             :  * this process receive a signal (that is not ignored) while the operation is
     387             :  * pending, the operation will fail.  Note that the helper may still believe
     388             :  * that it created the signature. Thus, signals may result in a small
     389             :  * differences in the signature counters.  Retrying in this case may work.
     390             :  *
     391             :  * @param dh helper process connection
     392             :  * @param h_cs hash of the CS public key to use to sign
     393             :  * @param blinded_planchet blinded planchet containing c and nonce
     394             :  * @param for_melt true if the HKDF for melt should be used
     395             :  * @param[out] bs set to the blind signature
     396             :  * @return #TALER_EC_NONE on success
     397             :  */
     398             : static enum TALER_ErrorCode
     399         902 : helper_cs_sign (
     400             :   struct TALER_CRYPTO_CsDenominationHelper *dh,
     401             :   const struct TALER_CsPubHashP *h_cs,
     402             :   const struct TALER_BlindedCsPlanchet *blinded_planchet,
     403             :   bool for_melt,
     404             :   struct TALER_BlindedDenominationSignature *bs)
     405             : {
     406         902 :   enum TALER_ErrorCode ec = TALER_EC_INVALID;
     407             : 
     408         902 :   bs->cipher = TALER_DENOMINATION_INVALID;
     409         902 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     410             :               "Starting signature process\n");
     411         902 :   if (GNUNET_OK !=
     412         902 :       try_connect (dh))
     413             :   {
     414           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     415             :                 "Failed to connect to helper\n");
     416           0 :     return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
     417             :   }
     418             : 
     419         902 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     420             :               "Requesting signature\n");
     421             :   {
     422             :     char buf[sizeof (struct TALER_CRYPTO_CsSignRequest)];
     423         902 :     struct TALER_CRYPTO_CsSignRequest *sr
     424             :       = (struct TALER_CRYPTO_CsSignRequest *) buf;
     425             : 
     426         902 :     sr->header.size = htons (sizeof (buf));
     427         902 :     sr->header.type = htons (TALER_HELPER_CS_MT_REQ_SIGN);
     428         902 :     sr->for_melt = htonl (for_melt ? 1 : 0);
     429         902 :     sr->h_cs = *h_cs;
     430         902 :     sr->planchet = *blinded_planchet;
     431         902 :     if (GNUNET_OK !=
     432         902 :         TALER_crypto_helper_send_all (dh->sock,
     433             :                                       buf,
     434             :                                       sizeof (buf)))
     435             :     {
     436           0 :       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
     437             :                            "send");
     438           0 :       do_disconnect (dh);
     439           0 :       return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
     440             :     }
     441             :   }
     442             : 
     443         902 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     444             :               "Awaiting reply\n");
     445             :   {
     446             :     char buf[UINT16_MAX];
     447         902 :     size_t off = 0;
     448         902 :     const struct GNUNET_MessageHeader *hdr
     449             :       = (const struct GNUNET_MessageHeader *) buf;
     450         902 :     bool finished = false;
     451             : 
     452             :     while (1)
     453         902 :     {
     454             :       uint16_t msize;
     455             :       ssize_t ret;
     456             : 
     457        2706 :       ret = recv (dh->sock,
     458        1804 :                   &buf[off],
     459             :                   sizeof (buf) - off,
     460         902 :                   (finished && (0 == off))
     461             :                   ? MSG_DONTWAIT
     462             :                   : 0);
     463        1804 :       if (ret < 0)
     464             :       {
     465         902 :         if (EINTR == errno)
     466           0 :           continue;
     467         902 :         if (EAGAIN == errno)
     468             :         {
     469         902 :           GNUNET_assert (finished);
     470         902 :           GNUNET_assert (0 == off);
     471         902 :           return ec;
     472             :         }
     473           0 :         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
     474             :                              "recv");
     475           0 :         do_disconnect (dh);
     476           0 :         ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
     477           0 :         break;
     478             :       }
     479         902 :       if (0 == ret)
     480             :       {
     481           0 :         GNUNET_break (0 == off);
     482           0 :         if (! finished)
     483           0 :           ec = TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
     484           0 :         return ec;
     485             :       }
     486         902 :       off += ret;
     487        1804 : more:
     488        1804 :       if (off < sizeof (struct GNUNET_MessageHeader))
     489         902 :         continue;
     490         902 :       msize = ntohs (hdr->size);
     491         902 :       if (off < msize)
     492           0 :         continue;
     493         902 :       switch (ntohs (hdr->type))
     494             :       {
     495         901 :       case TALER_HELPER_CS_MT_RES_SIGNATURE:
     496         901 :         if (msize < sizeof (struct TALER_CRYPTO_SignResponse))
     497             :         {
     498           0 :           GNUNET_break_op (0);
     499           0 :           do_disconnect (dh);
     500           0 :           ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     501           0 :           goto end;
     502             :         }
     503         901 :         if (finished)
     504             :         {
     505           0 :           GNUNET_break_op (0);
     506           0 :           do_disconnect (dh);
     507           0 :           ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     508           0 :           goto end;
     509             :         }
     510             :         {
     511         901 :           const struct TALER_CRYPTO_SignResponse *sr =
     512             :             (const struct TALER_CRYPTO_SignResponse *) buf;
     513             : 
     514         901 :           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     515             :                       "Received signature\n");
     516         901 :           ec = TALER_EC_NONE;
     517         901 :           finished = true;
     518         901 :           bs->cipher = TALER_DENOMINATION_CS;
     519         901 :           bs->details.blinded_cs_answer = sr->cs_answer;
     520         901 :           break;
     521             :         }
     522           1 :       case TALER_HELPER_CS_MT_RES_SIGN_FAILURE:
     523           1 :         if (msize != sizeof (struct TALER_CRYPTO_SignFailure))
     524             :         {
     525           0 :           GNUNET_break_op (0);
     526           0 :           do_disconnect (dh);
     527           0 :           ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     528           0 :           goto end;
     529             :         }
     530             :         {
     531           1 :           const struct TALER_CRYPTO_SignFailure *sf =
     532             :             (const struct TALER_CRYPTO_SignFailure *) buf;
     533             : 
     534           1 :           ec = (enum TALER_ErrorCode) ntohl (sf->ec);
     535           1 :           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     536             :                       "Signing failed!\n");
     537           1 :           finished = true;
     538           1 :           break;
     539             :         }
     540           0 :       case TALER_HELPER_CS_MT_AVAIL:
     541           0 :         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     542             :                     "Received new key!\n");
     543           0 :         if (GNUNET_OK !=
     544           0 :             handle_mt_avail (dh,
     545             :                              hdr))
     546             :         {
     547           0 :           GNUNET_break_op (0);
     548           0 :           do_disconnect (dh);
     549           0 :           ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     550           0 :           goto end;
     551             :         }
     552           0 :         break; /* while(1) loop ensures we recvfrom() again */
     553           0 :       case TALER_HELPER_CS_MT_PURGE:
     554           0 :         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     555             :                     "Received revocation!\n");
     556           0 :         if (GNUNET_OK !=
     557           0 :             handle_mt_purge (dh,
     558             :                              hdr))
     559             :         {
     560           0 :           GNUNET_break_op (0);
     561           0 :           do_disconnect (dh);
     562           0 :           ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     563           0 :           goto end;
     564             :         }
     565           0 :         break; /* while(1) loop ensures we recvfrom() again */
     566           0 :       case TALER_HELPER_CS_SYNCED:
     567           0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     568             :                     "Synchronized add odd time with CS helper!\n");
     569           0 :         dh->synced = true;
     570           0 :         break;
     571           0 :       default:
     572           0 :         GNUNET_break_op (0);
     573           0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     574             :                     "Received unexpected message of type %u\n",
     575             :                     ntohs (hdr->type));
     576           0 :         do_disconnect (dh);
     577           0 :         ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     578           0 :         goto end;
     579             :       }
     580         902 :       memmove (buf,
     581         902 :                &buf[msize],
     582             :                off - msize);
     583         902 :       off -= msize;
     584         902 :       goto more;
     585             :     } /* while(1) */
     586           0 : end:
     587           0 :     if (finished)
     588           0 :       TALER_blinded_denom_sig_free (bs);
     589           0 :     return ec;
     590             :   }
     591             : }
     592             : 
     593             : 
     594             : enum TALER_ErrorCode
     595         900 : TALER_CRYPTO_helper_cs_sign_melt (
     596             :   struct TALER_CRYPTO_CsDenominationHelper *dh,
     597             :   const struct TALER_CsPubHashP *h_cs,
     598             :   const struct TALER_BlindedCsPlanchet *blinded_planchet,
     599             :   struct TALER_BlindedDenominationSignature *bs)
     600             : {
     601         900 :   return helper_cs_sign (dh,
     602             :                          h_cs,
     603             :                          blinded_planchet,
     604             :                          true,
     605             :                          bs);
     606             : }
     607             : 
     608             : 
     609             : enum TALER_ErrorCode
     610           2 : TALER_CRYPTO_helper_cs_sign_withdraw (
     611             :   struct TALER_CRYPTO_CsDenominationHelper *dh,
     612             :   const struct TALER_CsPubHashP *h_cs,
     613             :   const struct TALER_BlindedCsPlanchet *blinded_planchet,
     614             :   struct TALER_BlindedDenominationSignature *bs)
     615             : {
     616           2 :   return helper_cs_sign (dh,
     617             :                          h_cs,
     618             :                          blinded_planchet,
     619             :                          false,
     620             :                          bs);
     621             : }
     622             : 
     623             : 
     624             : void
     625           3 : TALER_CRYPTO_helper_cs_revoke (
     626             :   struct TALER_CRYPTO_CsDenominationHelper *dh,
     627             :   const struct TALER_CsPubHashP *h_cs)
     628             : {
     629           3 :   struct TALER_CRYPTO_CsRevokeRequest rr = {
     630           3 :     .header.size = htons (sizeof (rr)),
     631           3 :     .header.type = htons (TALER_HELPER_CS_MT_REQ_REVOKE),
     632             :     .h_cs = *h_cs
     633             :   };
     634             : 
     635           3 :   if (GNUNET_OK !=
     636           3 :       try_connect (dh))
     637           0 :     return; /* give up */
     638           3 :   if (GNUNET_OK !=
     639           3 :       TALER_crypto_helper_send_all (dh->sock,
     640             :                                     &rr,
     641             :                                     sizeof (rr)))
     642             :   {
     643           0 :     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
     644             :                          "send");
     645           0 :     do_disconnect (dh);
     646           0 :     return;
     647             :   }
     648           3 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     649             :               "Requested revocation of denomination key %s\n",
     650             :               GNUNET_h2s (&h_cs->hash));
     651             : }
     652             : 
     653             : 
     654             : /**
     655             :  * Ask the helper to derive R using the @a nonce and denomination key
     656             :  * associated with @a h_cs.
     657             :  *
     658             :  * This operation will block until the R has been obtained.  Should
     659             :  * this process receive a signal (that is not ignored) while the operation is
     660             :  * pending, the operation will fail.  Note that the helper may still believe
     661             :  * that it created the signature. Thus, signals may result in a small
     662             :  * differences in the signature counters.  Retrying in this case may work.
     663             :  *
     664             :  * @param dh helper to process connection
     665             :  * @param h_cs hash of the CS public key to revoke
     666             :  * @param nonce witdhraw nonce
     667             :  * @param for_melt true if the HKDF for melt should be used
     668             :  * @param[out] crp set to the pair of R values
     669             :  * @return set to the error code (or #TALER_EC_NONE on success)
     670             :  */
     671             : static enum TALER_ErrorCode
     672          22 : helper_cs_r_derive (struct TALER_CRYPTO_CsDenominationHelper *dh,
     673             :                     const struct TALER_CsPubHashP *h_cs,
     674             :                     const struct TALER_CsNonce *nonce,
     675             :                     bool for_melt,
     676             :                     struct TALER_DenominationCSPublicRPairP *crp)
     677             : {
     678          22 :   enum TALER_ErrorCode ec = TALER_EC_INVALID;
     679             : 
     680          22 :   memset (crp,
     681             :           0,
     682             :           sizeof (*crp));
     683          22 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     684             :               "Starting R derivation process\n");
     685          22 :   if (GNUNET_OK !=
     686          22 :       try_connect (dh))
     687             :   {
     688           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     689             :                 "Failed to connect to helper\n");
     690           0 :     return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
     691             :   }
     692             : 
     693          22 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     694             :               "Requesting R\n");
     695             :   {
     696          22 :     struct TALER_CRYPTO_CsRDeriveRequest rdr = {
     697          22 :       .header.size = htons (sizeof (rdr)),
     698          22 :       .header.type = htons (TALER_HELPER_CS_MT_REQ_RDERIVE),
     699          22 :       .for_melt = htonl (for_melt ? 1 : 0),
     700             :       .h_cs = *h_cs,
     701             :       .nonce = *nonce
     702             :     };
     703             : 
     704          22 :     if (GNUNET_OK !=
     705          22 :         TALER_crypto_helper_send_all (dh->sock,
     706             :                                       &rdr,
     707             :                                       sizeof (rdr)))
     708             :     {
     709           0 :       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
     710             :                            "send");
     711           0 :       do_disconnect (dh);
     712           0 :       return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
     713             :     }
     714             :   }
     715             : 
     716          22 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     717             :               "Awaiting reply\n");
     718             :   {
     719             :     char buf[UINT16_MAX];
     720          22 :     size_t off = 0;
     721          22 :     const struct GNUNET_MessageHeader *hdr
     722             :       = (const struct GNUNET_MessageHeader *) buf;
     723          22 :     bool finished = false;
     724             : 
     725             :     while (1)
     726          22 :     {
     727             :       uint16_t msize;
     728             :       ssize_t ret;
     729             : 
     730          66 :       ret = recv (dh->sock,
     731          44 :                   &buf[off],
     732             :                   sizeof (buf) - off,
     733          22 :                   (finished && (0 == off))
     734             :                   ? MSG_DONTWAIT
     735             :                   : 0);
     736          44 :       if (ret < 0)
     737             :       {
     738          22 :         if (EINTR == errno)
     739           0 :           continue;
     740          22 :         if (EAGAIN == errno)
     741             :         {
     742          22 :           GNUNET_assert (finished);
     743          22 :           GNUNET_assert (0 == off);
     744          22 :           return ec;
     745             :         }
     746           0 :         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
     747             :                              "recv");
     748           0 :         do_disconnect (dh);
     749           0 :         return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
     750             :       }
     751          22 :       if (0 == ret)
     752             :       {
     753           0 :         GNUNET_break (0 == off);
     754           0 :         if (! finished)
     755           0 :           return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
     756           0 :         return ec;
     757             :       }
     758          22 :       off += ret;
     759          44 : more:
     760          44 :       if (off < sizeof (struct GNUNET_MessageHeader))
     761          22 :         continue;
     762          22 :       msize = ntohs (hdr->size);
     763          22 :       if (off < msize)
     764           0 :         continue;
     765          22 :       switch (ntohs (hdr->type))
     766             :       {
     767          11 :       case TALER_HELPER_CS_MT_RES_RDERIVE:
     768          11 :         if (msize != sizeof (struct TALER_CRYPTO_RDeriveResponse))
     769             :         {
     770           0 :           GNUNET_break_op (0);
     771           0 :           do_disconnect (dh);
     772           0 :           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     773             :         }
     774          11 :         if (finished)
     775             :         {
     776           0 :           GNUNET_break_op (0);
     777           0 :           do_disconnect (dh);
     778           0 :           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     779             :         }
     780             :         {
     781          11 :           const struct TALER_CRYPTO_RDeriveResponse *rdr =
     782             :             (const struct TALER_CRYPTO_RDeriveResponse *) buf;
     783             : 
     784          11 :           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     785             :                       "Received R\n");
     786          11 :           finished = true;
     787          11 :           ec = TALER_EC_NONE;
     788          11 :           *crp = rdr->r_pub;
     789          11 :           break;
     790             :         }
     791          11 :       case TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE:
     792          11 :         if (msize != sizeof (struct TALER_CRYPTO_RDeriveFailure))
     793             :         {
     794           0 :           GNUNET_break_op (0);
     795           0 :           do_disconnect (dh);
     796           0 :           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     797             :         }
     798             :         {
     799          11 :           const struct TALER_CRYPTO_RDeriveFailure *rdf =
     800             :             (const struct TALER_CRYPTO_RDeriveFailure *) buf;
     801             : 
     802          11 :           ec = (enum TALER_ErrorCode) ntohl (rdf->ec);
     803          11 :           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     804             :                       "R derivation failed!\n");
     805          11 :           finished = true;
     806          11 :           break;
     807             :         }
     808           0 :       case TALER_HELPER_CS_MT_AVAIL:
     809           0 :         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     810             :                     "Received new key!\n");
     811           0 :         if (GNUNET_OK !=
     812           0 :             handle_mt_avail (dh,
     813             :                              hdr))
     814             :         {
     815           0 :           GNUNET_break_op (0);
     816           0 :           do_disconnect (dh);
     817           0 :           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     818             :         }
     819           0 :         break; /* while(1) loop ensures we recvfrom() again */
     820           0 :       case TALER_HELPER_CS_MT_PURGE:
     821           0 :         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     822             :                     "Received revocation!\n");
     823           0 :         if (GNUNET_OK !=
     824           0 :             handle_mt_purge (dh,
     825             :                              hdr))
     826             :         {
     827           0 :           GNUNET_break_op (0);
     828           0 :           do_disconnect (dh);
     829           0 :           return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     830             :         }
     831           0 :         break; /* while(1) loop ensures we recvfrom() again */
     832           0 :       case TALER_HELPER_CS_SYNCED:
     833           0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     834             :                     "Synchronized add odd time with CS helper!\n");
     835           0 :         dh->synced = true;
     836           0 :         break;
     837           0 :       default:
     838           0 :         GNUNET_break_op (0);
     839           0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     840             :                     "Received unexpected message of type %u\n",
     841             :                     ntohs (hdr->type));
     842           0 :         do_disconnect (dh);
     843           0 :         return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
     844             :       }
     845          22 :       memmove (buf,
     846          22 :                &buf[msize],
     847             :                off - msize);
     848          22 :       off -= msize;
     849          22 :       goto more;
     850             :     } /* while(1) */
     851             :   }
     852             : }
     853             : 
     854             : 
     855             : enum TALER_ErrorCode
     856          13 : TALER_CRYPTO_helper_cs_r_derive_withdraw (
     857             :   struct TALER_CRYPTO_CsDenominationHelper *dh,
     858             :   const struct TALER_CsPubHashP *h_cs,
     859             :   const struct TALER_CsNonce *nonce,
     860             :   struct TALER_DenominationCSPublicRPairP *crp)
     861             : {
     862          13 :   return helper_cs_r_derive (dh,
     863             :                              h_cs,
     864             :                              nonce,
     865             :                              false,
     866             :                              crp);
     867             : }
     868             : 
     869             : 
     870             : enum TALER_ErrorCode
     871           9 : TALER_CRYPTO_helper_cs_r_derive_melt (
     872             :   struct TALER_CRYPTO_CsDenominationHelper *dh,
     873             :   const struct TALER_CsPubHashP *h_cs,
     874             :   const struct TALER_CsNonce *nonce,
     875             :   struct TALER_DenominationCSPublicRPairP *crp)
     876             : {
     877           9 :   return helper_cs_r_derive (dh,
     878             :                              h_cs,
     879             :                              nonce,
     880             :                              true,
     881             :                              crp);
     882             : }
     883             : 
     884             : 
     885             : void
     886           9 : TALER_CRYPTO_helper_cs_disconnect (
     887             :   struct TALER_CRYPTO_CsDenominationHelper *dh)
     888             : {
     889           9 :   if (-1 != dh->sock)
     890           9 :     do_disconnect (dh);
     891           9 :   GNUNET_free (dh);
     892           9 : }
     893             : 
     894             : 
     895             : /* end of crypto_helper_cs.c */

Generated by: LCOV version 1.14