LCOV - code coverage report
Current view: top level - util - crypto_helper_esign.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 148 249 59.4 %
Date: 2025-06-05 21:03:14 Functions: 9 9 100.0 %

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

Generated by: LCOV version 1.16