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

Generated by: LCOV version 1.14