diff options
| -rw-r--r-- | src/util/crypto_helper_denom.c | 525 | ||||
| -rw-r--r-- | src/util/crypto_helper_esign.c | 525 | 
2 files changed, 402 insertions, 648 deletions
| diff --git a/src/util/crypto_helper_denom.c b/src/util/crypto_helper_denom.c index cce5af63..4c6ab84e 100644 --- a/src/util/crypto_helper_denom.c +++ b/src/util/crypto_helper_denom.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2020 Taler Systems SA +  Copyright (C) 2020, 2021 Taler Systems SA    TALER is free software; you can redistribute it and/or modify it under the    terms of the GNU General Public License as published by the Free Software @@ -20,10 +20,10 @@   */  #include "platform.h"  #include "taler_util.h" -#include "taler_extensions.h"  #include "taler_signatures.h"  #include "taler-exchange-secmod-rsa.h"  #include <poll.h> +#include "crypto_helper_common.h"  struct TALER_CRYPTO_DenominationHelper @@ -45,16 +45,6 @@ struct TALER_CRYPTO_DenominationHelper    struct sockaddr_un sa;    /** -   * Socket address of this process. -   */ -  struct sockaddr_un my_sa; - -  /** -   * Template for @e my_sa. -   */ -  char *template; - -  /**     * The UNIX domain socket, -1 if we are currently not connected.     */    int sock; @@ -63,11 +53,6 @@ struct TALER_CRYPTO_DenominationHelper     * Have we ever been sync'ed?     */    bool synced; - -  /** -   * Age Mask that applies to this denomination. -   */ -  struct TALER_AgeMask age_mask;  }; @@ -81,10 +66,6 @@ static void  do_disconnect (struct TALER_CRYPTO_DenominationHelper *dh)  {    GNUNET_break (0 == close (dh->sock)); -  if (0 != unlink (dh->my_sa.sun_path)) -    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, -                              "unlink", -                              dh->my_sa.sun_path);    dh->sock = -1;    dh->synced = false;  } @@ -95,106 +76,34 @@ do_disconnect (struct TALER_CRYPTO_DenominationHelper *dh)   * @e sock field in @a dh.   *   * @param[in,out] dh handle to establish connection for + * @return #GNUNET_OK on success   */ -static void +static enum GNUNET_GenericReturnValue  try_connect (struct TALER_CRYPTO_DenominationHelper *dh)  { -  char *tmpdir; -    if (-1 != dh->sock) -    return; +    return GNUNET_OK;    dh->sock = socket (AF_UNIX, -                     SOCK_DGRAM, +                     SOCK_STREAM,                       0);    if (-1 == dh->sock)    {      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,                           "socket"); -    return; -  } -  tmpdir = GNUNET_DISK_mktemp (dh->template); -  if (NULL == tmpdir) -  { -    do_disconnect (dh); -    return; -  } -  /* we use >= here because we want the sun_path to always -     be 0-terminated */ -  if (strlen (tmpdir) >= sizeof (dh->sa.sun_path)) -  { -    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, -                               "PATHS", -                               "TALER_RUNTIME_DIR", -                               "path too long"); -    GNUNET_free (tmpdir); -    do_disconnect (dh); -    return; +    return GNUNET_SYSERR;    } -  dh->my_sa.sun_family = AF_UNIX; -  strncpy (dh->my_sa.sun_path, -           tmpdir, -           sizeof (dh->sa.sun_path) - 1); -  if (0 != unlink (tmpdir)) -    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, -                              "unlink", -                              tmpdir); -  if (0 != bind (dh->sock, -                 (const struct sockaddr *) &dh->my_sa, -                 sizeof (dh->my_sa))) +  if (0 != +      connect (dh->sock, +               (const struct sockaddr *) &dh->sa, +               sizeof (dh->sa)))    {      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, -                              "bind", -                              tmpdir); +                              "connect", +                              dh->sa.sun_path);      do_disconnect (dh); -    GNUNET_free (tmpdir); -    return; -  } -  /* Fix permissions on client UNIX domain socket, -     just in case umask() is not set to enable group write */ -  { -    char path[sizeof (dh->my_sa.sun_path) + 1]; - -    strncpy (path, -             dh->my_sa.sun_path, -             sizeof (path) - 1); -    path[sizeof (dh->my_sa.sun_path)] = '\0'; - -    if (0 != chmod (path, -                    S_IRUSR | S_IWUSR | S_IWGRP)) -    { -      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, -                                "chmod", -                                path); -    } -  } -  GNUNET_free (tmpdir); -  { -    struct GNUNET_MessageHeader hdr = { -      .size = htons (sizeof (hdr)), -      .type = htons (TALER_HELPER_RSA_MT_REQ_INIT) -    }; -    ssize_t ret; - -    ret = sendto (dh->sock, -                  &hdr, -                  sizeof (hdr), -                  0, -                  (const struct sockaddr *) &dh->sa, -                  sizeof (dh->sa)); -    if (ret < 0) -    { -      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, -                                "sendto", -                                dh->sa.sun_path); -      do_disconnect (dh); -      return; -    } -    /* We are using SOCK_DGRAM, partial writes should not be possible */ -    GNUNET_break (((size_t) ret) == sizeof (hdr)); -    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, -                "Successfully sent REQ_INIT\n"); +    return GNUNET_SYSERR;    } - +  return GNUNET_OK;  } @@ -238,17 +147,9 @@ TALER_CRYPTO_helper_denom_connect (             sizeof (dh->sa.sun_path) - 1);    GNUNET_free (unixpath);    dh->sock = -1; -  /* Extract the age groups from the config, if the extension has been set, -   * and serialize them into the age mask -   */    if (GNUNET_OK != -      TALER_get_age_mask (cfg, &dh->age_mask)) +      try_connect (dh))    { -    /* FIXME: maybe more specific error? */ -    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, -                               "extensions",   /* FIXME: right section etc? */ -                               "age-restriction", -                               "invalid age groups");      TALER_CRYPTO_helper_denom_disconnect (dh);      return NULL;    } @@ -298,7 +199,6 @@ handle_mt_avail (struct TALER_CRYPTO_DenominationHelper *dh,      struct TALER_DenominationHash h_denom_pub;      denom_pub.cipher = TALER_DENOMINATION_RSA; -    denom_pub.age_mask = dh->age_mask;      denom_pub.details.rsa_public_key        = GNUNET_CRYPTO_rsa_public_key_decode (buf,                                               ntohs (kan->pub_size)); @@ -307,8 +207,8 @@ handle_mt_avail (struct TALER_CRYPTO_DenominationHelper *dh,        GNUNET_break_op (0);        return GNUNET_SYSERR;      } -    TALER_denom_pub_hash (&denom_pub, -                          &h_denom_pub); +    GNUNET_CRYPTO_rsa_public_key_hash (denom_pub.details.rsa_public_key, +                                       &h_denom_pub.hash);      GNUNET_log (GNUNET_ERROR_TYPE_INFO,                  "Received RSA key %s (%s)\n",                  GNUNET_h2s (&h_denom_pub.hash), @@ -323,7 +223,7 @@ handle_mt_avail (struct TALER_CRYPTO_DenominationHelper *dh,            &kan->secm_sig))      {        GNUNET_break_op (0); -      GNUNET_CRYPTO_rsa_public_key_free (denom_pub.details.rsa_public_key); +      TALER_denom_pub_free (&denom_pub);        return GNUNET_SYSERR;      }      dh->dkc (dh->dkc_cls, @@ -334,7 +234,7 @@ handle_mt_avail (struct TALER_CRYPTO_DenominationHelper *dh,               &denom_pub,               &kan->secm_pub,               &kan->secm_sig); -    GNUNET_CRYPTO_rsa_public_key_free (denom_pub.details.rsa_public_key); +    TALER_denom_pub_free (&denom_pub);    }    return GNUNET_OK;  } @@ -374,115 +274,62 @@ handle_mt_purge (struct TALER_CRYPTO_DenominationHelper *dh,  } -/** - * Wait until the socket is ready to read. - * - * @param dh helper to wait for - * @return false on timeout (after 1s) - */ -static bool -await_read_ready (struct TALER_CRYPTO_DenominationHelper *dh) -{ -  /* wait for reply with 1s timeout */ -  struct pollfd pfd = { -    .fd = dh->sock, -    .events = POLLIN -  }; -  sigset_t sigmask; -  struct timespec ts = { -    .tv_sec = 1 -  }; -  int ret; - -  GNUNET_assert (0 == sigemptyset (&sigmask)); -  GNUNET_assert (0 == sigaddset (&sigmask, SIGTERM)); -  GNUNET_assert (0 == sigaddset (&sigmask, SIGHUP)); -  ret = ppoll (&pfd, -               1, -               &ts, -               &sigmask); -  if ( (-1 == ret) && -       (EINTR != errno) ) -    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, -                         "ppoll"); -  return (0 < ret); -} - -  void  TALER_CRYPTO_helper_denom_poll (struct TALER_CRYPTO_DenominationHelper *dh)  {    char buf[UINT16_MAX]; -  ssize_t ret; +  size_t off = 0;    unsigned int retry_limit = 3;    const struct GNUNET_MessageHeader *hdr      = (const struct GNUNET_MessageHeader *) buf; -  int flag = MSG_DONTWAIT; -  try_connect (dh); -  if (-1 == dh->sock) -  { -    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                "Cannot poll denom helper: socket down\n"); +  if (GNUNET_OK != +      try_connect (dh))      return; /* give up */ -  }    while (1)    { +    uint16_t msize; +    ssize_t ret; +      ret = recv (dh->sock,                  buf,                  sizeof (buf), -                flag); +                (dh->synced && (0 == off)) +                ? MSG_DONTWAIT +                : 0);      if (ret < 0)      { +      if (EINTR == errno) +        continue;        if (EAGAIN == errno)        { -        /* EAGAIN should only happen if we did not -           already go through this loop */ -        GNUNET_assert (0 != flag); -        if (dh->synced) -          break; -        if (! await_read_ready (dh)) -        { -          /* timeout AND not synced => full reconnect */ -          GNUNET_log (GNUNET_ERROR_TYPE_INFO, -                      "Restarting connection to RSA helper, did not come up properly\n"); -          do_disconnect (dh); -          if (0 == retry_limit) -          { -            GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                        "Cannot poll denom helper: retry limit reached\n"); -            return; /* give up */ -          } -          try_connect (dh); -          if (-1 == dh->sock) -          { -            GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                        "Cannot poll denom helper: failed to connect\n"); -            return; /* give up */ -          } -          retry_limit--; -          flag = MSG_DONTWAIT; -        } -        else -        { -          flag = 0; /* syscall must be non-blocking this time */ -        } -        continue; /* try again */ +        GNUNET_assert (dh->synced); +        GNUNET_assert (0 == off); +        break;        }        GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,                             "recv");        do_disconnect (dh); -      return; +      if (0 == retry_limit) +        return; /* give up */ +      if (GNUNET_OK != +          try_connect (dh)) +        return; /* give up */ +      retry_limit--; +      continue;      } -    retry_limit = 10; -    flag = MSG_DONTWAIT; -    if ( (ret < sizeof (struct GNUNET_MessageHeader)) || -         (ret != ntohs (hdr->size)) ) +    if (0 == ret)      { -      GNUNET_break_op (0); -      do_disconnect (dh); +      GNUNET_break (0 == off);        return;      } +    off += ret; +more: +    if (off < sizeof (struct GNUNET_MessageHeader)) +      continue; +    msize = ntohs (hdr->size); +    if (off < msize) +      continue;      switch (ntohs (hdr->type))      {      case TALER_HELPER_RSA_MT_AVAIL: @@ -511,10 +358,19 @@ TALER_CRYPTO_helper_denom_poll (struct TALER_CRYPTO_DenominationHelper *dh)        dh->synced = true;        break;      default: +      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                  "Received unexpected message of type %d (len: %u)\n", +                  (unsigned int) ntohs (hdr->type), +                  (unsigned int) msize);        GNUNET_break_op (0);        do_disconnect (dh);        return;      } +    memmove (buf, +             &buf[msize], +             off - msize); +    off -= msize; +    goto more;    }  } @@ -528,22 +384,23 @@ TALER_CRYPTO_helper_denom_sign (    enum TALER_ErrorCode *ec)  {    struct TALER_BlindedDenominationSignature ds = { -    .details.blinded_rsa_signature = NULL +    .cipher = TALER_DENOMINATION_INVALID    }; + +  if (GNUNET_OK != +      try_connect (dh)) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                "Failed to connect to helper\n"); +    *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; +    return ds; +  } +    {      char buf[sizeof (struct TALER_CRYPTO_SignRequest) + msg_size];      struct TALER_CRYPTO_SignRequest *sr        = (struct TALER_CRYPTO_SignRequest *) buf; -    ssize_t ret; -    try_connect (dh); -    if (-1 == dh->sock) -    { -      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                  "Failed to connect to helper\n"); -      *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; -      return ds; -    }      sr->header.size = htons (sizeof (buf));      sr->header.type = htons (TALER_HELPER_RSA_MT_REQ_SIGN);      sr->reserved = htonl (0); @@ -551,131 +408,160 @@ TALER_CRYPTO_helper_denom_sign (      memcpy (&sr[1],              msg,              msg_size); -    ret = sendto (dh->sock, -                  buf, -                  sizeof (buf), -                  0, -                  (const struct sockaddr *) &dh->sa, -                  sizeof (dh->sa)); -    if (ret < 0) +    if (GNUNET_OK != +        TALER_crypto_helper_send_all (dh->sock, +                                      buf, +                                      sizeof (buf)))      {        GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, -                           "sendto"); +                           "send");        do_disconnect (dh);        *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;        return ds;      } -    /* We are using SOCK_DGRAM, partial writes should not be possible */ -    GNUNET_break (((size_t) ret) == sizeof (buf));    } -  while (1)    {      char buf[UINT16_MAX]; -    ssize_t ret; +    size_t off = 0;      const struct GNUNET_MessageHeader *hdr        = (const struct GNUNET_MessageHeader *) buf; +    bool finished = false; -    if (! await_read_ready (dh)) -    { -      do_disconnect (dh); -      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                  "Timeout waiting for helper\n"); -      *ec = TALER_EC_GENERIC_TIMEOUT; -      return ds; -    } -    ret = recv (dh->sock, -                buf, -                sizeof (buf), -                0); -    if (ret < 0) -    { -      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, -                           "recv"); -      do_disconnect (dh); -      *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; -      return ds; -    } -    if ( (ret < sizeof (struct GNUNET_MessageHeader)) || -         (ret != ntohs (hdr->size)) ) -    { -      GNUNET_break_op (0); -      do_disconnect (dh); -      *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; -      return ds; -    } -    switch (ntohs (hdr->type)) +    *ec = TALER_EC_INVALID; +    while (1)      { -    case TALER_HELPER_RSA_MT_RES_SIGNATURE: -      if (ret < sizeof (struct TALER_CRYPTO_SignResponse)) +      uint16_t msize; +      ssize_t ret; + +      ret = recv (dh->sock, +                  buf, +                  sizeof (buf), +                  (finished && (0 == off)) +                  ? MSG_DONTWAIT +                  : 0); +      if (ret < 0)        { -        GNUNET_break_op (0); +        if (EINTR == errno) +          continue; +        if (EAGAIN == errno) +        { +          GNUNET_assert (finished); +          GNUNET_assert (0 == off); +          return ds; +        } +        GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, +                             "recv");          do_disconnect (dh); -        *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; +        *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; +        break; +      } +      if (0 == ret) +      { +        GNUNET_break (0 == off); +        if (! finished) +          *ec = TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;          return ds;        } +      off += ret; +more: +      if (off < sizeof (struct GNUNET_MessageHeader)) +        continue; +      msize = ntohs (hdr->size); +      if (off < msize) +        continue; +      switch (ntohs (hdr->type))        { -        const struct TALER_CRYPTO_SignResponse *sr = -          (const struct TALER_CRYPTO_SignResponse *) buf; -        struct GNUNET_CRYPTO_RsaSignature *rsa_signature; - -        rsa_signature = GNUNET_CRYPTO_rsa_signature_decode (&sr[1], -                                                            ret - sizeof (*sr)); -        if (NULL == rsa_signature) +      case TALER_HELPER_RSA_MT_RES_SIGNATURE: +        if ( (msize < sizeof (struct TALER_CRYPTO_SignResponse)) || +             (finished) )          {            GNUNET_break_op (0);            do_disconnect (dh);            *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; -          return ds; +          goto end;          } -        *ec = TALER_EC_NONE; -        ds.cipher = TALER_DENOMINATION_RSA; -        ds.details.blinded_rsa_signature = rsa_signature; -        return ds; -      } -    case TALER_HELPER_RSA_MT_RES_SIGN_FAILURE: -      if (ret != sizeof (struct TALER_CRYPTO_SignFailure)) -      { -        GNUNET_break_op (0); -        do_disconnect (dh); -        *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; -        return ds; -      } -      { -        const struct TALER_CRYPTO_SignFailure *sf = -          (const struct TALER_CRYPTO_SignFailure *) buf; +        { +          const struct TALER_CRYPTO_SignResponse *sr = +            (const struct TALER_CRYPTO_SignResponse *) buf; +          struct GNUNET_CRYPTO_RsaSignature *rsa_signature; + +          rsa_signature = GNUNET_CRYPTO_rsa_signature_decode ( +            &sr[1], +            msize - sizeof (*sr)); +          if (NULL == rsa_signature) +          { +            GNUNET_break_op (0); +            do_disconnect (dh); +            *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; +            goto end; +          } +          *ec = TALER_EC_NONE; +          finished = true; +          ds.details.blinded_rsa_signature = rsa_signature; +          break; +        } +      case TALER_HELPER_RSA_MT_RES_SIGN_FAILURE: +        if (msize != sizeof (struct TALER_CRYPTO_SignFailure)) +        { +          GNUNET_break_op (0); +          do_disconnect (dh); +          *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; +          goto end; +        } +        { +          const struct TALER_CRYPTO_SignFailure *sf = +            (const struct TALER_CRYPTO_SignFailure *) buf; -        *ec = (enum TALER_ErrorCode) ntohl (sf->ec); -        return ds; -      } -    case TALER_HELPER_RSA_MT_AVAIL: -      if (GNUNET_OK != -          handle_mt_avail (dh, -                           hdr)) -      { -        GNUNET_break_op (0); -        do_disconnect (dh); -        *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; -        return ds; -      } -      break; /* while(1) loop ensures we recvfrom() again */ -    case TALER_HELPER_RSA_MT_PURGE: -      if (GNUNET_OK != -          handle_mt_purge (dh, -                           hdr)) -      { +          *ec = (enum TALER_ErrorCode) ntohl (sf->ec); +          return ds; +        } +      case TALER_HELPER_RSA_MT_AVAIL: +        if (GNUNET_OK != +            handle_mt_avail (dh, +                             hdr)) +        { +          GNUNET_break_op (0); +          do_disconnect (dh); +          *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; +          goto end; +        } +        break; /* while(1) loop ensures we recvfrom() again */ +      case TALER_HELPER_RSA_MT_PURGE: +        if (GNUNET_OK != +            handle_mt_purge (dh, +                             hdr)) +        { +          GNUNET_break_op (0); +          do_disconnect (dh); +          *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; +          goto end; +        } +        break; /* while(1) loop ensures we recvfrom() again */ +      case TALER_HELPER_RSA_SYNCED: +        GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                    "Synchronized add odd time with RSA helper!\n"); +        dh->synced = true; +        break; +      default:          GNUNET_break_op (0); +        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                    "Received unexpected message of type %u\n", +                    ntohs (hdr->type));          do_disconnect (dh);          *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; -        return ds; +        goto end;        } -      break; /* while(1) loop ensures we recvfrom() again */ -    default: -      GNUNET_break_op (0); -      do_disconnect (dh); -      *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; -      return ds; -    } +      memmove (buf, +               &buf[msize], +               off - msize); +      off -= msize; +      goto more; +    } /* while(1) */ +end: +    if (finished) +      TALER_blinded_denom_sig_free (&ds); +    return ds;    }  } @@ -690,26 +576,20 @@ TALER_CRYPTO_helper_denom_revoke (      .header.type = htons (TALER_HELPER_RSA_MT_REQ_REVOKE),      .h_denom_pub = *h_denom_pub    }; -  ssize_t ret; -  try_connect (dh); -  if (-1 == dh->sock) +  if (GNUNET_OK != +      try_connect (dh))      return; /* give up */ -  ret = sendto (dh->sock, -                &rr, -                sizeof (rr), -                0, -                (const struct sockaddr *) &dh->sa, -                sizeof (dh->sa)); -  if (ret < 0) +  if (GNUNET_OK != +      TALER_crypto_helper_send_all (dh->sock, +                                    &rr, +                                    sizeof (rr)))    {      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, -                         "sendto"); +                         "send");      do_disconnect (dh);      return;    } -  /* We are using SOCK_DGRAM, partial writes should not be possible */ -  GNUNET_break (((size_t) ret) == sizeof (rr));    GNUNET_log (GNUNET_ERROR_TYPE_INFO,                "Requested revocation of denomination key %s\n",                GNUNET_h2s (&h_denom_pub->hash)); @@ -722,7 +602,6 @@ TALER_CRYPTO_helper_denom_disconnect (  {    if (-1 != dh->sock)      do_disconnect (dh); -  GNUNET_free (dh->template);    GNUNET_free (dh);  } diff --git a/src/util/crypto_helper_esign.c b/src/util/crypto_helper_esign.c index 6257a1d2..794a916a 100644 --- a/src/util/crypto_helper_esign.c +++ b/src/util/crypto_helper_esign.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2020 Taler Systems SA +  Copyright (C) 2020, 2021 Taler Systems SA    TALER is free software; you can redistribute it and/or modify it under the    terms of the GNU General Public License as published by the Free Software @@ -23,6 +23,7 @@  #include "taler_signatures.h"  #include "taler-exchange-secmod-eddsa.h"  #include <poll.h> +#include "crypto_helper_common.h"  struct TALER_CRYPTO_ExchangeSignHelper @@ -44,16 +45,6 @@ struct TALER_CRYPTO_ExchangeSignHelper    struct sockaddr_un sa;    /** -   * Socket address of this process. -   */ -  struct sockaddr_un my_sa; - -  /** -   * Template for @e my_sa. -   */ -  char *template; - -  /**     * The UNIX domain socket, -1 if we are currently not connected.     */    int sock; @@ -76,10 +67,6 @@ static void  do_disconnect (struct TALER_CRYPTO_ExchangeSignHelper *esh)  {    GNUNET_break (0 == close (esh->sock)); -  if (0 != unlink (esh->my_sa.sun_path)) -    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, -                              "unlink", -                              esh->my_sa.sun_path);    esh->sock = -1;    esh->synced = false;  } @@ -90,107 +77,34 @@ do_disconnect (struct TALER_CRYPTO_ExchangeSignHelper *esh)   * @e sock field in @a esh.   *   * @param[in,out] esh handle to establish connection for + * @return #GNUNET_OK on success   */ -static void +static enum GNUNET_GenericReturnValue  try_connect (struct TALER_CRYPTO_ExchangeSignHelper *esh)  { -  char *tmpdir; -    if (-1 != esh->sock) -    return; +    return GNUNET_OK;    esh->sock = socket (AF_UNIX, -                      SOCK_DGRAM, +                      SOCK_STREAM,                        0);    if (-1 == esh->sock)    {      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,                           "socket"); -    return; -  } -  tmpdir = GNUNET_DISK_mktemp (esh->template); -  if (NULL == tmpdir) -  { -    do_disconnect (esh); -    return; -  } -  /* we use >= here because we want the sun_path to always -     be 0-terminated */ -  if (strlen (tmpdir) >= sizeof (esh->sa.sun_path)) -  { -    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, -                               "PATHS", -                               "TALER_RUNTIME_DIR", -                               "path too long"); -    GNUNET_free (tmpdir); -    do_disconnect (esh); -    return; +    return GNUNET_SYSERR;    } -  esh->my_sa.sun_family = AF_UNIX; -  strncpy (esh->my_sa.sun_path, -           tmpdir, -           sizeof (esh->sa.sun_path) - 1); -  if (0 != unlink (tmpdir)) -    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, -                              "unlink", -                              tmpdir); -  if (0 != bind (esh->sock, -                 (const struct sockaddr *) &esh->my_sa, -                 sizeof (esh->my_sa))) +  if (0 != +      connect (esh->sock, +               (const struct sockaddr *) &esh->sa, +               sizeof (esh->sa)))    {      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, -                              "bind", -                              tmpdir); +                              "connect", +                              esh->sa.sun_path);      do_disconnect (esh); -    GNUNET_free (tmpdir); -    return; -  } -  /* Fix permissions on client UNIX domain socket, -     just in case umask() is not set to enable group write */ -  { -    char path[sizeof (esh->my_sa.sun_path) + 1]; - -    strncpy (path, -             esh->my_sa.sun_path, -             sizeof (path) - 1); -    path[sizeof (esh->my_sa.sun_path)] = '\0'; - -    if (0 != chmod (path, -                    S_IRUSR | S_IWUSR | S_IWGRP)) -    { -      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, -                                "chmod", -                                path); -    } -  } - -  GNUNET_free (tmpdir); -  { -    struct GNUNET_MessageHeader hdr = { -      .size = htons (sizeof (hdr)), -      .type = htons (TALER_HELPER_EDDSA_MT_REQ_INIT) -    }; -    ssize_t ret; - -    ret = sendto (esh->sock, -                  &hdr, -                  sizeof (hdr), -                  0, -                  (const struct sockaddr *) &esh->sa, -                  sizeof (esh->sa)); -    if (ret < 0) -    { -      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, -                                "sendto", -                                esh->sa.sun_path); -      do_disconnect (esh); -      return; -    } -    /* We are using SOCK_DGRAM, partial writes should not be possible */ -    GNUNET_break (((size_t) ret) == sizeof (hdr)); -    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, -                "Successfully sent REQ_INIT\n"); +    return GNUNET_SYSERR;    } - +  return GNUNET_OK;  } @@ -234,50 +148,13 @@ TALER_CRYPTO_helper_esign_connect (             sizeof (esh->sa.sun_path) - 1);    GNUNET_free (unixpath);    esh->sock = -1; +  if (GNUNET_OK != +      try_connect (esh))    { -    char *tmpdir; -    char *template; - -    if (GNUNET_OK != -        GNUNET_CONFIGURATION_get_value_filename (cfg, -                                                 "taler-exchange-secmod-eddsa", -                                                 "CLIENT_DIR", -                                                 &tmpdir)) -    { -      GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, -                                 "taler-exchange-secmod-eddsa", -                                 "CLIENT_DIR"); -      GNUNET_free (esh); -      return NULL; -    } -    GNUNET_asprintf (&template, -                     "%s/cli", -                     tmpdir); -    /* We expect the service to create the client directory */ -    if (GNUNET_OK != -        GNUNET_DISK_directory_test (tmpdir, -                                    GNUNET_YES)) -    { -      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                  "Unable to read secmod client directory (%s)\n", -                  tmpdir); -      GNUNET_free (esh); -      GNUNET_free (template); -      GNUNET_free (tmpdir); -      return NULL; -    } -    GNUNET_free (tmpdir); -    esh->template = template; -    if (strlen (template) >= sizeof (esh->sa.sun_path)) -    { -      GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, -                                 "PATHS", -                                 "TALER_RUNTIME_DIR", -                                 "path too long"); -      TALER_CRYPTO_helper_esign_disconnect (esh); -      return NULL; -    } +    TALER_CRYPTO_helper_esign_disconnect (esh); +    return NULL;    } +    TALER_CRYPTO_helper_esign_poll (esh);    return esh;  } @@ -290,7 +167,7 @@ TALER_CRYPTO_helper_esign_connect (   * @param hdr message that we received   * @return #GNUNET_OK on success   */ -static int +static enum GNUNET_GenericReturnValue  handle_mt_avail (struct TALER_CRYPTO_ExchangeSignHelper *esh,                   const struct GNUNET_MessageHeader *hdr)  { @@ -330,7 +207,7 @@ handle_mt_avail (struct TALER_CRYPTO_ExchangeSignHelper *esh,   * @param hdr message that we received   * @return #GNUNET_OK on success   */ -static int +static enum GNUNET_GenericReturnValue  handle_mt_purge (struct TALER_CRYPTO_ExchangeSignHelper *esh,                   const struct GNUNET_MessageHeader *hdr)  { @@ -352,101 +229,62 @@ handle_mt_purge (struct TALER_CRYPTO_ExchangeSignHelper *esh,  } -/** - * Wait until the socket is ready to read. - * - * @param esh helper to wait for - * @return false on timeout (after 1s) - */ -static bool -await_read_ready (struct TALER_CRYPTO_ExchangeSignHelper *esh) -{ -  /* wait for reply with 1s timeout */ -  struct pollfd pfd = { -    .fd = esh->sock, -    .events = POLLIN -  }; -  sigset_t sigmask; -  struct timespec ts = { -    .tv_sec = 1 -  }; -  int ret; - -  GNUNET_assert (0 == sigemptyset (&sigmask)); -  GNUNET_assert (0 == sigaddset (&sigmask, SIGTERM)); -  GNUNET_assert (0 == sigaddset (&sigmask, SIGHUP)); -  ret = ppoll (&pfd, -               1, -               &ts, -               &sigmask); -  if ( (-1 == ret) && -       (EINTR != errno) ) -    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, -                         "ppoll"); -  return (0 < ret); -} - -  void  TALER_CRYPTO_helper_esign_poll (struct TALER_CRYPTO_ExchangeSignHelper *esh)  {    char buf[UINT16_MAX]; -  ssize_t ret; +  size_t off = 0;    unsigned int retry_limit = 3;    const struct GNUNET_MessageHeader *hdr      = (const struct GNUNET_MessageHeader *) buf; -  int flag = MSG_DONTWAIT; -  try_connect (esh); -  if (-1 == esh->sock) +  if (GNUNET_OK != +      try_connect (esh))      return; /* give up */    while (1)    { +    uint16_t msize; +    ssize_t ret; +      ret = recv (esh->sock, -                buf, -                sizeof (buf), -                flag); +                buf + off, +                sizeof (buf) - off, +                (esh->synced && (0 == off)) +                ? MSG_DONTWAIT +                : 0);      if (ret < 0)      { +      if (EINTR == errno) +        continue;        if (EAGAIN == errno)        { -        GNUNET_assert (0 != flag); -        if (esh->synced) -          break; -        if (! await_read_ready (esh)) -        { -          /* timeout AND not synced => full reconnect */ -          GNUNET_log (GNUNET_ERROR_TYPE_INFO, -                      "Restarting connection to EdDSA helper, did not come up properly\n"); -          do_disconnect (esh); -          if (0 == retry_limit) -            return; /* give up */ -          try_connect (esh); -          if (-1 == esh->sock) -            return; /* give up */ -          retry_limit--; -          flag = MSG_DONTWAIT; -        } -        else -        { -          flag = 0; /* syscall must be non-blocking this time */ -        } -        continue; /* try again */ +        GNUNET_assert (esh->synced); +        GNUNET_assert (0 == off); +        break;        }        GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,                             "recv");        do_disconnect (esh); -      return; +      if (0 == retry_limit) +        return; /* give up */ +      if (GNUNET_OK != +          try_connect (esh)) +        return; /* give up */ +      retry_limit--; +      continue;      } - -    flag = MSG_DONTWAIT; -    if ( (ret < sizeof (struct GNUNET_MessageHeader)) || -         (ret != ntohs (hdr->size)) ) +    if (0 == ret)      { -      GNUNET_break_op (0); -      do_disconnect (esh); +      GNUNET_break (0 == off);        return;      } +    off += ret; +more: +    if (off < sizeof (struct GNUNET_MessageHeader)) +      continue; +    msize = ntohs (hdr->size); +    if (off < msize) +      continue;      switch (ntohs (hdr->type))      {      case TALER_HELPER_EDDSA_MT_AVAIL: @@ -475,10 +313,19 @@ TALER_CRYPTO_helper_esign_poll (struct TALER_CRYPTO_ExchangeSignHelper *esh)        esh->synced = true;        break;      default: +      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                  "Received unexpected message of type %d (len: %u)\n", +                  (unsigned int) ntohs (hdr->type), +                  (unsigned int) msize);        GNUNET_break_op (0);        do_disconnect (esh);        return;      } +    memmove (buf, +             &buf[msize], +             off - msize); +    off -= msize; +    goto more;    }  } @@ -490,131 +337,164 @@ TALER_CRYPTO_helper_esign_sign_ (    struct TALER_ExchangePublicKeyP *exchange_pub,    struct TALER_ExchangeSignatureP *exchange_sig)  { +  if (GNUNET_OK != +      try_connect (esh)) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                "Failed to connect to helper\n"); +    return TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE; +  }    {      uint32_t purpose_size = ntohl (purpose->size);      char buf[sizeof (struct TALER_CRYPTO_EddsaSignRequest) + purpose_size               - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose)];      struct TALER_CRYPTO_EddsaSignRequest *sr        = (struct TALER_CRYPTO_EddsaSignRequest *) buf; -    ssize_t ret; -    try_connect (esh); -    if (-1 == esh->sock) -    { -      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                  "Failed to connect to helper\n"); -      return TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE; -    }      sr->header.size = htons (sizeof (buf));      sr->header.type = htons (TALER_HELPER_EDDSA_MT_REQ_SIGN);      sr->reserved = htonl (0);      memcpy (&sr->purpose,              purpose,              purpose_size); -    ret = sendto (esh->sock, -                  buf, -                  sizeof (buf), -                  0, -                  (const struct sockaddr *) &esh->sa, -                  sizeof (esh->sa)); -    if (ret < 0) +    if (GNUNET_OK != +        TALER_crypto_helper_send_all (esh->sock, +                                      buf, +                                      sizeof (buf)))      {        GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, -                                "sendto", +                                "send",                                  esh->sa.sun_path);        do_disconnect (esh);        return TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE;      } -    /* We are using SOCK_DGRAM, partial writes should not be possible */ -    GNUNET_break (((size_t) ret) == sizeof (buf));    } -  while (1)    {      char buf[UINT16_MAX]; -    ssize_t ret; +    size_t off = 0;      const struct GNUNET_MessageHeader *hdr        = (const struct GNUNET_MessageHeader *) buf; +    bool finished = false; +    enum TALER_ErrorCode ec = TALER_EC_INVALID; -    if (! await_read_ready (esh)) -    { -      do_disconnect (esh); -      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                  "Timeout waiting for helper\n"); -      return TALER_EC_GENERIC_TIMEOUT; -    } -    ret = recv (esh->sock, -                buf, -                sizeof (buf), -                0); -    if (ret < 0) -    { -      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, -                           "recv"); -      do_disconnect (esh); -      return TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE; -    } -    if ( (ret < sizeof (struct GNUNET_MessageHeader)) || -         (ret != ntohs (hdr->size)) ) -    { -      GNUNET_break_op (0); -      do_disconnect (esh); -      return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; -    } -    switch (ntohs (hdr->type)) +    while (1)      { -    case TALER_HELPER_EDDSA_MT_RES_SIGNATURE: -      if (ret != sizeof (struct TALER_CRYPTO_EddsaSignResponse)) +      ssize_t ret; +      uint16_t msize; + +      ret = recv (esh->sock, +                  buf, +                  sizeof (buf), +                  (finished && (0 == off)) +                  ? MSG_DONTWAIT +                  : 0); +      if (ret < 0)        { -        GNUNET_break_op (0); +        if (EINTR == errno) +          continue; +        if (EAGAIN == errno) +        { +          GNUNET_assert (finished); +          GNUNET_assert (0 == off); +          break; +        } +        GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, +                             "recv");          do_disconnect (esh); -        return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; -      } -      { -        const struct TALER_CRYPTO_EddsaSignResponse *sr = -          (const struct TALER_CRYPTO_EddsaSignResponse *) buf; -        *exchange_sig = sr->exchange_sig; -        *exchange_pub = sr->exchange_pub; -        return TALER_EC_NONE; +        return TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE;        } -    case TALER_HELPER_EDDSA_MT_RES_SIGN_FAILURE: -      if (ret != sizeof (struct TALER_CRYPTO_EddsaSignFailure)) +      if (0 == ret)        { -        GNUNET_break_op (0); -        do_disconnect (esh); +        GNUNET_break (0 == off);          return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;        } +      off += ret; +more: +      if (off < sizeof (struct GNUNET_MessageHeader)) +        continue; +      msize = ntohs (hdr->size); +      if (off < msize) +        continue; +      switch (ntohs (hdr->type))        { -        const struct TALER_CRYPTO_EddsaSignFailure *sf = -          (const struct TALER_CRYPTO_EddsaSignFailure *) buf; +      case TALER_HELPER_EDDSA_MT_RES_SIGNATURE: +        if (msize != sizeof (struct TALER_CRYPTO_EddsaSignResponse)) +        { +          GNUNET_break_op (0); +          do_disconnect (esh); +          return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; +        } +        if (finished) +        { +          GNUNET_break_op (0); +          do_disconnect (esh); +          return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; +        } +        { +          const struct TALER_CRYPTO_EddsaSignResponse *sr = +            (const struct TALER_CRYPTO_EddsaSignResponse *) buf; +          *exchange_sig = sr->exchange_sig; +          *exchange_pub = sr->exchange_pub; +          finished = true; +          ec = TALER_EC_NONE; +          break; +        } +      case TALER_HELPER_EDDSA_MT_RES_SIGN_FAILURE: +        if (msize != sizeof (struct TALER_CRYPTO_EddsaSignFailure)) +        { +          GNUNET_break_op (0); +          do_disconnect (esh); +          return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; +        } +        { +          const struct TALER_CRYPTO_EddsaSignFailure *sf = +            (const struct TALER_CRYPTO_EddsaSignFailure *) buf; -        return (enum TALER_ErrorCode) ntohl (sf->ec); -      } -    case TALER_HELPER_EDDSA_MT_AVAIL: -      if (GNUNET_OK != -          handle_mt_avail (esh, -                           hdr)) -      { -        GNUNET_break_op (0); -        do_disconnect (esh); -        return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; -      } -      break; /* while(1) loop ensures we recvfrom() again */ -    case TALER_HELPER_EDDSA_MT_PURGE: -      if (GNUNET_OK != -          handle_mt_purge (esh, -                           hdr)) -      { +          finished = true; +          ec = (enum TALER_ErrorCode) ntohl (sf->ec); +          break; +        } +      case TALER_HELPER_EDDSA_MT_AVAIL: +        if (GNUNET_OK != +            handle_mt_avail (esh, +                             hdr)) +        { +          GNUNET_break_op (0); +          do_disconnect (esh); +          return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; +        } +        break; /* while(1) loop ensures we recv() again */ +      case TALER_HELPER_EDDSA_MT_PURGE: +        if (GNUNET_OK != +            handle_mt_purge (esh, +                             hdr)) +        { +          GNUNET_break_op (0); +          do_disconnect (esh); +          return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; +        } +        break; /* while(1) loop ensures we recv() again */ +      case TALER_HELPER_EDDSA_SYNCED: +        GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                    "Synchronized add odd time with EdDSA helper!\n"); +        esh->synced = true; +        break; +      default:          GNUNET_break_op (0); +        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                    "Received unexpected message of type %u\n", +                    ntohs (hdr->type));          do_disconnect (esh);          return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;        } -      break; /* while(1) loop ensures we recvfrom() again */ -    default: -      GNUNET_break_op (0); -      do_disconnect (esh); -      return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; -    } +      memmove (buf, +               &buf[msize], +               off - msize); +      off -= msize; +      goto more; +    } /* while(1) */ +    return ec;    }  } @@ -624,31 +504,27 @@ TALER_CRYPTO_helper_esign_revoke (    struct TALER_CRYPTO_ExchangeSignHelper *esh,    const struct TALER_ExchangePublicKeyP *exchange_pub)  { -  struct TALER_CRYPTO_EddsaRevokeRequest rr = { -    .header.size = htons (sizeof (rr)), -    .header.type = htons (TALER_HELPER_EDDSA_MT_REQ_REVOKE), -    .exchange_pub = *exchange_pub -  }; -  ssize_t ret; - -  try_connect (esh); -  if (-1 == esh->sock) +  if (GNUNET_OK != +      try_connect (esh))      return; /* give up */ -  ret = sendto (esh->sock, -                &rr, -                sizeof (rr), -                0, -                (const struct sockaddr *) &esh->sa, -                sizeof (esh->sa)); -  if (ret < 0)    { -    GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, -                         "sendto"); -    do_disconnect (esh); -    return; +    struct TALER_CRYPTO_EddsaRevokeRequest rr = { +      .header.size = htons (sizeof (rr)), +      .header.type = htons (TALER_HELPER_EDDSA_MT_REQ_REVOKE), +      .exchange_pub = *exchange_pub +    }; + +    if (GNUNET_OK != +        TALER_crypto_helper_send_all (esh->sock, +                                      &rr, +                                      sizeof (rr))) +    { +      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, +                           "send"); +      do_disconnect (esh); +      return; +    }    } -  /* We are using SOCK_DGRAM, partial writes should not be possible */ -  GNUNET_break (((size_t) ret) == sizeof (rr));  } @@ -658,7 +534,6 @@ TALER_CRYPTO_helper_esign_disconnect (  {    if (-1 != esh->sock)      do_disconnect (esh); -  GNUNET_free (esh->template);    GNUNET_free (esh);  } | 
