exchange

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

crypto_helper_esign.c (15381B)


      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_esign.c
     18  * @brief utility functions for running out-of-process private key operations
     19  * @author Christian Grothoff
     20  */
     21 #include "platform.h"
     22 #include "taler/taler_util.h"
     23 #include "taler/taler_signatures.h"
     24 #include "secmod_eddsa.h"
     25 #include <poll.h>
     26 #include "crypto_helper_common.h"
     27 
     28 
     29 struct TALER_CRYPTO_ExchangeSignHelper
     30 {
     31   /**
     32    * Function to call with updates to available key material.
     33    */
     34   TALER_CRYPTO_ExchangeKeyStatusCallback ekc;
     35 
     36   /**
     37    * Closure for @e ekc
     38    */
     39   void *ekc_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 reached the sync'ed state?
     54    */
     55   bool synced;
     56 
     57 };
     58 
     59 
     60 /**
     61  * Disconnect from the helper process.  Updates
     62  * @e sock field in @a esh.
     63  *
     64  * @param[in,out] esh handle to tear down connection of
     65  */
     66 static void
     67 do_disconnect (struct TALER_CRYPTO_ExchangeSignHelper *esh)
     68 {
     69   GNUNET_break (0 == close (esh->sock));
     70   esh->sock = -1;
     71   esh->synced = false;
     72 }
     73 
     74 
     75 /**
     76  * Try to connect to the helper process.  Updates
     77  * @e sock field in @a esh.
     78  *
     79  * @param[in,out] esh handle to establish connection for
     80  * @return #GNUNET_OK on success
     81  */
     82 static enum GNUNET_GenericReturnValue
     83 try_connect (struct TALER_CRYPTO_ExchangeSignHelper *esh)
     84 {
     85   if (-1 != esh->sock)
     86     return GNUNET_OK;
     87   esh->sock = socket (AF_UNIX,
     88                       SOCK_STREAM,
     89                       0);
     90   if (-1 == esh->sock)
     91   {
     92     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
     93                          "socket");
     94     return GNUNET_SYSERR;
     95   }
     96   if (0 !=
     97       connect (esh->sock,
     98                (const struct sockaddr *) &esh->sa,
     99                sizeof (esh->sa)))
    100   {
    101     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
    102                               "connect",
    103                               esh->sa.sun_path);
    104     do_disconnect (esh);
    105     return GNUNET_SYSERR;
    106   }
    107   return GNUNET_OK;
    108 }
    109 
    110 
    111 struct TALER_CRYPTO_ExchangeSignHelper *
    112 TALER_CRYPTO_helper_esign_connect (
    113   const struct GNUNET_CONFIGURATION_Handle *cfg,
    114   const char *section,
    115   TALER_CRYPTO_ExchangeKeyStatusCallback ekc,
    116   void *ekc_cls)
    117 {
    118   struct TALER_CRYPTO_ExchangeSignHelper *esh;
    119   char *unixpath;
    120   char *secname;
    121 
    122   GNUNET_asprintf (&secname,
    123                    "%s-secmod-eddsa",
    124                    section);
    125 
    126   if (GNUNET_OK !=
    127       GNUNET_CONFIGURATION_get_value_filename (cfg,
    128                                                secname,
    129                                                "UNIXPATH",
    130                                                &unixpath))
    131   {
    132     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    133                                secname,
    134                                "UNIXPATH");
    135     GNUNET_free (secname);
    136     return NULL;
    137   }
    138   /* we use >= here because we want the sun_path to always
    139      be 0-terminated */
    140   if (strlen (unixpath) >= sizeof (esh->sa.sun_path))
    141   {
    142     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
    143                                secname,
    144                                "UNIXPATH",
    145                                "path too long");
    146     GNUNET_free (unixpath);
    147     GNUNET_free (secname);
    148     return NULL;
    149   }
    150   GNUNET_free (secname);
    151   esh = GNUNET_new (struct TALER_CRYPTO_ExchangeSignHelper);
    152   esh->ekc = ekc;
    153   esh->ekc_cls = ekc_cls;
    154   esh->sa.sun_family = AF_UNIX;
    155   strncpy (esh->sa.sun_path,
    156            unixpath,
    157            sizeof (esh->sa.sun_path) - 1);
    158   GNUNET_free (unixpath);
    159   esh->sock = -1;
    160   if (GNUNET_OK !=
    161       try_connect (esh))
    162   {
    163     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    164                 "Could not connect to %s. Will keep trying\n",
    165                 "taler-exchange-helper-secmod-eddsa");
    166     return esh;
    167   }
    168   TALER_CRYPTO_helper_esign_poll (esh);
    169   return esh;
    170 }
    171 
    172 
    173 /**
    174  * Handle a #TALER_HELPER_EDDSA_MT_AVAIL message from the helper.
    175  *
    176  * @param esh 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_ExchangeSignHelper *esh,
    182                  const struct GNUNET_MessageHeader *hdr)
    183 {
    184   const struct TALER_CRYPTO_EddsaKeyAvailableNotification *kan
    185     = (const struct TALER_CRYPTO_EddsaKeyAvailableNotification *) hdr;
    186 
    187   if (sizeof (*kan) != ntohs (hdr->size))
    188   {
    189     GNUNET_break_op (0);
    190     return GNUNET_SYSERR;
    191   }
    192   if (GNUNET_OK !=
    193       TALER_exchange_secmod_eddsa_verify (
    194         &kan->exchange_pub,
    195         GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
    196         GNUNET_TIME_relative_ntoh (kan->duration),
    197         &kan->secm_pub,
    198         &kan->secm_sig))
    199   {
    200     GNUNET_break_op (0);
    201     return GNUNET_SYSERR;
    202   }
    203   esh->ekc (esh->ekc_cls,
    204             GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
    205             GNUNET_TIME_relative_ntoh (kan->duration),
    206             &kan->exchange_pub,
    207             &kan->secm_pub,
    208             &kan->secm_sig);
    209   return GNUNET_OK;
    210 }
    211 
    212 
    213 /**
    214  * Handle a #TALER_HELPER_EDDSA_MT_PURGE message from the helper.
    215  *
    216  * @param esh helper context
    217  * @param hdr message that we received
    218  * @return #GNUNET_OK on success
    219  */
    220 static enum GNUNET_GenericReturnValue
    221 handle_mt_purge (struct TALER_CRYPTO_ExchangeSignHelper *esh,
    222                  const struct GNUNET_MessageHeader *hdr)
    223 {
    224   const struct TALER_CRYPTO_EddsaKeyPurgeNotification *pn
    225     = (const struct TALER_CRYPTO_EddsaKeyPurgeNotification *) hdr;
    226 
    227   if (sizeof (*pn) != ntohs (hdr->size))
    228   {
    229     GNUNET_break_op (0);
    230     return GNUNET_SYSERR;
    231   }
    232   esh->ekc (esh->ekc_cls,
    233             GNUNET_TIME_UNIT_ZERO_TS,
    234             GNUNET_TIME_UNIT_ZERO,
    235             &pn->exchange_pub,
    236             NULL,
    237             NULL);
    238   return GNUNET_OK;
    239 }
    240 
    241 
    242 void
    243 TALER_CRYPTO_helper_esign_poll (struct TALER_CRYPTO_ExchangeSignHelper *esh)
    244 {
    245   char buf[UINT16_MAX];
    246   size_t off = 0;
    247   unsigned int retry_limit = 3;
    248   const struct GNUNET_MessageHeader *hdr
    249     = (const struct GNUNET_MessageHeader *) buf;
    250 
    251   if (GNUNET_OK !=
    252       try_connect (esh))
    253     return; /* give up */
    254   while (1)
    255   {
    256     uint16_t msize;
    257     ssize_t ret;
    258 
    259     ret = recv (esh->sock,
    260                 buf + off,
    261                 sizeof (buf) - off,
    262                 (esh->synced && (0 == off))
    263                 ? MSG_DONTWAIT
    264                 : 0);
    265     if (ret < 0)
    266     {
    267       if (EINTR == errno)
    268         continue;
    269       if (EAGAIN == errno)
    270       {
    271         GNUNET_assert (esh->synced);
    272         GNUNET_assert (0 == off);
    273         break;
    274       }
    275       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    276                            "recv");
    277       do_disconnect (esh);
    278       if (0 == retry_limit)
    279         return; /* give up */
    280       if (GNUNET_OK !=
    281           try_connect (esh))
    282         return; /* give up */
    283       retry_limit--;
    284       continue;
    285     }
    286     if (0 == ret)
    287     {
    288       GNUNET_break (0 == off);
    289       return;
    290     }
    291     off += ret;
    292 more:
    293     if (off < sizeof (struct GNUNET_MessageHeader))
    294       continue;
    295     msize = ntohs (hdr->size);
    296     if (msize < sizeof (struct GNUNET_MessageHeader))
    297     {
    298       GNUNET_break_op (0);
    299       do_disconnect (esh);
    300       return;
    301     }
    302     if (off < msize)
    303       continue;
    304     switch (ntohs (hdr->type))
    305     {
    306     case TALER_HELPER_EDDSA_MT_AVAIL:
    307       if (GNUNET_OK !=
    308           handle_mt_avail (esh,
    309                            hdr))
    310       {
    311         GNUNET_break_op (0);
    312         do_disconnect (esh);
    313         return;
    314       }
    315       break;
    316     case TALER_HELPER_EDDSA_MT_PURGE:
    317       if (GNUNET_OK !=
    318           handle_mt_purge (esh,
    319                            hdr))
    320       {
    321         GNUNET_break_op (0);
    322         do_disconnect (esh);
    323         return;
    324       }
    325       break;
    326     case TALER_HELPER_EDDSA_SYNCED:
    327       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    328                   "Now synchronized with EdDSA helper\n");
    329       esh->synced = true;
    330       break;
    331     default:
    332       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    333                   "Received unexpected message of type %d (len: %u)\n",
    334                   (unsigned int) ntohs (hdr->type),
    335                   (unsigned int) msize);
    336       GNUNET_break_op (0);
    337       do_disconnect (esh);
    338       return;
    339     }
    340     memmove (buf,
    341              &buf[msize],
    342              off - msize);
    343     off -= msize;
    344     goto more;
    345   }
    346 }
    347 
    348 
    349 enum TALER_ErrorCode
    350 TALER_CRYPTO_helper_esign_sign_ (
    351   struct TALER_CRYPTO_ExchangeSignHelper *esh,
    352   const struct GNUNET_CRYPTO_SignaturePurpose *purpose,
    353   struct TALER_ExchangePublicKeyP *exchange_pub,
    354   struct TALER_ExchangeSignatureP *exchange_sig)
    355 {
    356   uint32_t purpose_size = ntohl (purpose->size);
    357 
    358   if (GNUNET_OK !=
    359       try_connect (esh))
    360   {
    361     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    362                 "Failed to connect to helper\n");
    363     return TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE;
    364   }
    365   GNUNET_assert (purpose_size <
    366                  UINT16_MAX - sizeof (struct TALER_CRYPTO_EddsaSignRequest));
    367   {
    368     char buf[sizeof (struct TALER_CRYPTO_EddsaSignRequest) + purpose_size
    369              - sizeof (struct GNUNET_CRYPTO_SignaturePurpose)];
    370     struct TALER_CRYPTO_EddsaSignRequest *sr
    371       = (struct TALER_CRYPTO_EddsaSignRequest *) buf;
    372 
    373     sr->header.size = htons (sizeof (buf));
    374     sr->header.type = htons (TALER_HELPER_EDDSA_MT_REQ_SIGN);
    375     sr->reserved = htonl (0);
    376     GNUNET_memcpy (&sr->purpose,
    377                    purpose,
    378                    purpose_size);
    379     if (GNUNET_OK !=
    380         TALER_crypto_helper_send_all (esh->sock,
    381                                       buf,
    382                                       sizeof (buf)))
    383     {
    384       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
    385                                 "send",
    386                                 esh->sa.sun_path);
    387       do_disconnect (esh);
    388       return TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE;
    389     }
    390   }
    391 
    392   {
    393     char buf[UINT16_MAX];
    394     size_t off = 0;
    395     const struct GNUNET_MessageHeader *hdr
    396       = (const struct GNUNET_MessageHeader *) buf;
    397     bool finished = false;
    398     enum TALER_ErrorCode ec = TALER_EC_INVALID;
    399 
    400     while (1)
    401     {
    402       ssize_t ret;
    403       uint16_t msize;
    404 
    405       ret = recv (esh->sock,
    406                   &buf[off],
    407                   sizeof (buf) - off,
    408                   (finished && (0 == off))
    409                   ? MSG_DONTWAIT
    410                   : 0);
    411       if (ret < 0)
    412       {
    413         if (EINTR == errno)
    414           continue;
    415         if (EAGAIN == errno)
    416         {
    417           GNUNET_assert (finished);
    418           GNUNET_assert (0 == off);
    419           break;
    420         }
    421         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    422                              "recv");
    423         do_disconnect (esh);
    424         return TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE;
    425       }
    426       if (0 == ret)
    427       {
    428         GNUNET_break (0 == off);
    429         if (finished)
    430           return TALER_EC_NONE;
    431         return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    432       }
    433       off += ret;
    434 more:
    435       if (off < sizeof (struct GNUNET_MessageHeader))
    436         continue;
    437       msize = ntohs (hdr->size);
    438       if (msize < sizeof (struct GNUNET_MessageHeader))
    439       {
    440         GNUNET_break_op (0);
    441         do_disconnect (esh);
    442         return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    443       }
    444       if (off < msize)
    445         continue;
    446       switch (ntohs (hdr->type))
    447       {
    448       case TALER_HELPER_EDDSA_MT_RES_SIGNATURE:
    449         if (msize != sizeof (struct TALER_CRYPTO_EddsaSignResponse))
    450         {
    451           GNUNET_break_op (0);
    452           do_disconnect (esh);
    453           return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    454         }
    455         if (finished)
    456         {
    457           GNUNET_break_op (0);
    458           do_disconnect (esh);
    459           return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    460         }
    461         {
    462           const struct TALER_CRYPTO_EddsaSignResponse *sr =
    463             (const struct TALER_CRYPTO_EddsaSignResponse *) buf;
    464           *exchange_sig = sr->exchange_sig;
    465           *exchange_pub = sr->exchange_pub;
    466           finished = true;
    467           ec = TALER_EC_NONE;
    468           break;
    469         }
    470       case TALER_HELPER_EDDSA_MT_RES_SIGN_FAILURE:
    471         if (msize != sizeof (struct TALER_CRYPTO_EddsaSignFailure))
    472         {
    473           GNUNET_break_op (0);
    474           do_disconnect (esh);
    475           return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    476         }
    477         {
    478           const struct TALER_CRYPTO_EddsaSignFailure *sf =
    479             (const struct TALER_CRYPTO_EddsaSignFailure *) buf;
    480 
    481           finished = true;
    482           ec = (enum TALER_ErrorCode) (int) ntohl (sf->ec);
    483           break;
    484         }
    485       case TALER_HELPER_EDDSA_MT_AVAIL:
    486         if (GNUNET_OK !=
    487             handle_mt_avail (esh,
    488                              hdr))
    489         {
    490           GNUNET_break_op (0);
    491           do_disconnect (esh);
    492           return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    493         }
    494         break; /* while(1) loop ensures we recv() again */
    495       case TALER_HELPER_EDDSA_MT_PURGE:
    496         if (GNUNET_OK !=
    497             handle_mt_purge (esh,
    498                              hdr))
    499         {
    500           GNUNET_break_op (0);
    501           do_disconnect (esh);
    502           return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    503         }
    504         break; /* while(1) loop ensures we recv() again */
    505       case TALER_HELPER_EDDSA_SYNCED:
    506         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    507                     "Synchronized add odd time with EdDSA helper!\n");
    508         esh->synced = true;
    509         break;
    510       default:
    511         GNUNET_break_op (0);
    512         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    513                     "Received unexpected message of type %u\n",
    514                     ntohs (hdr->type));
    515         do_disconnect (esh);
    516         return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    517       }
    518       memmove (buf,
    519                &buf[msize],
    520                off - msize);
    521       off -= msize;
    522       goto more;
    523     } /* while(1) */
    524     return ec;
    525   }
    526 }
    527 
    528 
    529 void
    530 TALER_CRYPTO_helper_esign_revoke (
    531   struct TALER_CRYPTO_ExchangeSignHelper *esh,
    532   const struct TALER_ExchangePublicKeyP *exchange_pub)
    533 {
    534   if (GNUNET_OK !=
    535       try_connect (esh))
    536     return; /* give up */
    537   {
    538     struct TALER_CRYPTO_EddsaRevokeRequest rr = {
    539       .header.size = htons (sizeof (rr)),
    540       .header.type = htons (TALER_HELPER_EDDSA_MT_REQ_REVOKE),
    541       .exchange_pub = *exchange_pub
    542     };
    543 
    544     if (GNUNET_OK !=
    545         TALER_crypto_helper_send_all (esh->sock,
    546                                       &rr,
    547                                       sizeof (rr)))
    548     {
    549       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    550                            "send");
    551       do_disconnect (esh);
    552       return;
    553     }
    554   }
    555 }
    556 
    557 
    558 void
    559 TALER_CRYPTO_helper_esign_disconnect (
    560   struct TALER_CRYPTO_ExchangeSignHelper *esh)
    561 {
    562   if (-1 != esh->sock)
    563     do_disconnect (esh);
    564   GNUNET_free (esh);
    565 }
    566 
    567 
    568 /* end of crypto_helper_esign.c */