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


      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 "taler/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 (off < msize)
    297       continue;
    298     switch (ntohs (hdr->type))
    299     {
    300     case TALER_HELPER_EDDSA_MT_AVAIL:
    301       if (GNUNET_OK !=
    302           handle_mt_avail (esh,
    303                            hdr))
    304       {
    305         GNUNET_break_op (0);
    306         do_disconnect (esh);
    307         return;
    308       }
    309       break;
    310     case TALER_HELPER_EDDSA_MT_PURGE:
    311       if (GNUNET_OK !=
    312           handle_mt_purge (esh,
    313                            hdr))
    314       {
    315         GNUNET_break_op (0);
    316         do_disconnect (esh);
    317         return;
    318       }
    319       break;
    320     case TALER_HELPER_EDDSA_SYNCED:
    321       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    322                   "Now synchronized with EdDSA helper\n");
    323       esh->synced = true;
    324       break;
    325     default:
    326       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    327                   "Received unexpected message of type %d (len: %u)\n",
    328                   (unsigned int) ntohs (hdr->type),
    329                   (unsigned int) msize);
    330       GNUNET_break_op (0);
    331       do_disconnect (esh);
    332       return;
    333     }
    334     memmove (buf,
    335              &buf[msize],
    336              off - msize);
    337     off -= msize;
    338     goto more;
    339   }
    340 }
    341 
    342 
    343 enum TALER_ErrorCode
    344 TALER_CRYPTO_helper_esign_sign_ (
    345   struct TALER_CRYPTO_ExchangeSignHelper *esh,
    346   const struct GNUNET_CRYPTO_SignaturePurpose *purpose,
    347   struct TALER_ExchangePublicKeyP *exchange_pub,
    348   struct TALER_ExchangeSignatureP *exchange_sig)
    349 {
    350   uint32_t purpose_size = ntohl (purpose->size);
    351 
    352   if (GNUNET_OK !=
    353       try_connect (esh))
    354   {
    355     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    356                 "Failed to connect to helper\n");
    357     return TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE;
    358   }
    359   GNUNET_assert (purpose_size <
    360                  UINT16_MAX - sizeof (struct TALER_CRYPTO_EddsaSignRequest));
    361   {
    362     char buf[sizeof (struct TALER_CRYPTO_EddsaSignRequest) + purpose_size
    363              - sizeof (struct GNUNET_CRYPTO_SignaturePurpose)];
    364     struct TALER_CRYPTO_EddsaSignRequest *sr
    365       = (struct TALER_CRYPTO_EddsaSignRequest *) buf;
    366 
    367     sr->header.size = htons (sizeof (buf));
    368     sr->header.type = htons (TALER_HELPER_EDDSA_MT_REQ_SIGN);
    369     sr->reserved = htonl (0);
    370     GNUNET_memcpy (&sr->purpose,
    371                    purpose,
    372                    purpose_size);
    373     if (GNUNET_OK !=
    374         TALER_crypto_helper_send_all (esh->sock,
    375                                       buf,
    376                                       sizeof (buf)))
    377     {
    378       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
    379                                 "send",
    380                                 esh->sa.sun_path);
    381       do_disconnect (esh);
    382       return TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE;
    383     }
    384   }
    385 
    386   {
    387     char buf[UINT16_MAX];
    388     size_t off = 0;
    389     const struct GNUNET_MessageHeader *hdr
    390       = (const struct GNUNET_MessageHeader *) buf;
    391     bool finished = false;
    392     enum TALER_ErrorCode ec = TALER_EC_INVALID;
    393 
    394     while (1)
    395     {
    396       ssize_t ret;
    397       uint16_t msize;
    398 
    399       ret = recv (esh->sock,
    400                   &buf[off],
    401                   sizeof (buf) - off,
    402                   (finished && (0 == off))
    403                   ? MSG_DONTWAIT
    404                   : 0);
    405       if (ret < 0)
    406       {
    407         if (EINTR == errno)
    408           continue;
    409         if (EAGAIN == errno)
    410         {
    411           GNUNET_assert (finished);
    412           GNUNET_assert (0 == off);
    413           break;
    414         }
    415         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    416                              "recv");
    417         do_disconnect (esh);
    418         return TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE;
    419       }
    420       if (0 == ret)
    421       {
    422         GNUNET_break (0 == off);
    423         if (finished)
    424           return TALER_EC_NONE;
    425         return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    426       }
    427       off += ret;
    428 more:
    429       if (off < sizeof (struct GNUNET_MessageHeader))
    430         continue;
    431       msize = ntohs (hdr->size);
    432       if (off < msize)
    433         continue;
    434       switch (ntohs (hdr->type))
    435       {
    436       case TALER_HELPER_EDDSA_MT_RES_SIGNATURE:
    437         if (msize != sizeof (struct TALER_CRYPTO_EddsaSignResponse))
    438         {
    439           GNUNET_break_op (0);
    440           do_disconnect (esh);
    441           return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    442         }
    443         if (finished)
    444         {
    445           GNUNET_break_op (0);
    446           do_disconnect (esh);
    447           return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    448         }
    449         {
    450           const struct TALER_CRYPTO_EddsaSignResponse *sr =
    451             (const struct TALER_CRYPTO_EddsaSignResponse *) buf;
    452           *exchange_sig = sr->exchange_sig;
    453           *exchange_pub = sr->exchange_pub;
    454           finished = true;
    455           ec = TALER_EC_NONE;
    456           break;
    457         }
    458       case TALER_HELPER_EDDSA_MT_RES_SIGN_FAILURE:
    459         if (msize != sizeof (struct TALER_CRYPTO_EddsaSignFailure))
    460         {
    461           GNUNET_break_op (0);
    462           do_disconnect (esh);
    463           return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    464         }
    465         {
    466           const struct TALER_CRYPTO_EddsaSignFailure *sf =
    467             (const struct TALER_CRYPTO_EddsaSignFailure *) buf;
    468 
    469           finished = true;
    470           ec = (enum TALER_ErrorCode) (int) ntohl (sf->ec);
    471           break;
    472         }
    473       case TALER_HELPER_EDDSA_MT_AVAIL:
    474         if (GNUNET_OK !=
    475             handle_mt_avail (esh,
    476                              hdr))
    477         {
    478           GNUNET_break_op (0);
    479           do_disconnect (esh);
    480           return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    481         }
    482         break; /* while(1) loop ensures we recv() again */
    483       case TALER_HELPER_EDDSA_MT_PURGE:
    484         if (GNUNET_OK !=
    485             handle_mt_purge (esh,
    486                              hdr))
    487         {
    488           GNUNET_break_op (0);
    489           do_disconnect (esh);
    490           return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    491         }
    492         break; /* while(1) loop ensures we recv() again */
    493       case TALER_HELPER_EDDSA_SYNCED:
    494         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    495                     "Synchronized add odd time with EdDSA helper!\n");
    496         esh->synced = true;
    497         break;
    498       default:
    499         GNUNET_break_op (0);
    500         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    501                     "Received unexpected message of type %u\n",
    502                     ntohs (hdr->type));
    503         do_disconnect (esh);
    504         return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
    505       }
    506       memmove (buf,
    507                &buf[msize],
    508                off - msize);
    509       off -= msize;
    510       goto more;
    511     } /* while(1) */
    512     return ec;
    513   }
    514 }
    515 
    516 
    517 void
    518 TALER_CRYPTO_helper_esign_revoke (
    519   struct TALER_CRYPTO_ExchangeSignHelper *esh,
    520   const struct TALER_ExchangePublicKeyP *exchange_pub)
    521 {
    522   if (GNUNET_OK !=
    523       try_connect (esh))
    524     return; /* give up */
    525   {
    526     struct TALER_CRYPTO_EddsaRevokeRequest rr = {
    527       .header.size = htons (sizeof (rr)),
    528       .header.type = htons (TALER_HELPER_EDDSA_MT_REQ_REVOKE),
    529       .exchange_pub = *exchange_pub
    530     };
    531 
    532     if (GNUNET_OK !=
    533         TALER_crypto_helper_send_all (esh->sock,
    534                                       &rr,
    535                                       sizeof (rr)))
    536     {
    537       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
    538                            "send");
    539       do_disconnect (esh);
    540       return;
    541     }
    542   }
    543 }
    544 
    545 
    546 void
    547 TALER_CRYPTO_helper_esign_disconnect (
    548   struct TALER_CRYPTO_ExchangeSignHelper *esh)
    549 {
    550   if (-1 != esh->sock)
    551     do_disconnect (esh);
    552   GNUNET_free (esh);
    553 }
    554 
    555 
    556 /* end of crypto_helper_esign.c */