diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/exchange-tools/.gitignore | 1 | ||||
| -rw-r--r-- | src/exchange-tools/Makefile.am | 15 | ||||
| -rw-r--r-- | src/exchange-tools/taler-auditor-offline.c | 1267 | ||||
| -rw-r--r-- | src/exchange-tools/taler-exchange-offline.c | 3 | ||||
| -rw-r--r-- | src/exchange/taler-exchange-httpd_auditors.c | 65 | ||||
| -rw-r--r-- | src/include/taler_crypto_lib.h | 73 | ||||
| -rw-r--r-- | src/include/taler_exchange_service.h | 2 | ||||
| -rw-r--r-- | src/include/taler_signatures.h | 2 | ||||
| -rw-r--r-- | src/lib/exchange_api_handle.c | 42 | ||||
| -rw-r--r-- | src/testing/testing_api_cmd_auditor_add_denom_sig.c | 45 | ||||
| -rw-r--r-- | src/util/Makefile.am | 1 | ||||
| -rw-r--r-- | src/util/auditor_signatures.c | 122 | 
12 files changed, 1541 insertions, 97 deletions
| diff --git a/src/exchange-tools/.gitignore b/src/exchange-tools/.gitignore index af97f4b0..4d26c9c2 100644 --- a/src/exchange-tools/.gitignore +++ b/src/exchange-tools/.gitignore @@ -2,3 +2,4 @@ test_taler_exchange_httpd_home/.local/share/taler/exchange/live-keys/  test_taler_exchange_httpd_home/.local/share/taler/exchange/wirefees/  test_taler_exchange_httpd_home/.config/taler/account-1.json  taler-exchange-offline +taler-auditor-offline diff --git a/src/exchange-tools/Makefile.am b/src/exchange-tools/Makefile.am index 947e6b2b..e6096303 100644 --- a/src/exchange-tools/Makefile.am +++ b/src/exchange-tools/Makefile.am @@ -13,6 +13,7 @@ if USE_COVERAGE  endif  bin_PROGRAMS = \ +  taler-auditor-offline \    taler-exchange-keyup \    taler-exchange-keycheck \    taler-exchange-offline \ @@ -47,6 +48,20 @@ taler_exchange_offline_LDADD = \    $(XLIB) +taler_auditor_offline_SOURCES = \ +  taler-auditor-offline.c +taler_auditor_offline_LDADD = \ +  $(LIBGCRYPT_LIBS) \ +  $(top_builddir)/src/lib/libtalerexchange.la \ +  $(top_builddir)/src/json/libtalerjson.la \ +  $(top_builddir)/src/util/libtalerutil.la \ +  -lgnunetjson \ +  -lgnunetcurl \ +  -ljansson \ +  -lgnunetutil \ +  $(XLIB) + +  taler_exchange_wire_SOURCES = \    taler-exchange-wire.c  taler_exchange_wire_LDADD = \ diff --git a/src/exchange-tools/taler-auditor-offline.c b/src/exchange-tools/taler-auditor-offline.c new file mode 100644 index 00000000..18d7360c --- /dev/null +++ b/src/exchange-tools/taler-auditor-offline.c @@ -0,0 +1,1267 @@ +/* +  This file is part of TALER +  Copyright (C) 2020 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 +  Foundation; either version 3, or (at your option) any later version. + +  TALER is distributed in the hope that it will be useful, but WITHOUT ANY +  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +  A PARTICULAR PURPOSE.  See the GNU General Public License for more details. + +  You should have received a copy of the GNU General Public License along with +  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler-auditor-offline.c + * @brief Support for operations involving the auditor's (offline) key. + * @author Christian Grothoff + */ +#include <platform.h> +#include <gnunet/gnunet_json_lib.h> +#include "taler_json_lib.h" +#include "taler_exchange_service.h" + + +/** + * Our private key, initialized in #load_offline_key(). + */ +static struct TALER_AuditorPrivateKeyP auditor_priv; + +/** + * Our private key, initialized in #load_offline_key(). + */ +static struct TALER_AuditorPublicKeyP auditor_pub; + +/** + * Base URL of this auditor's REST endpoint. + */ +static char *auditor_url; + +/** + * Exchange's master public key. + */ +static struct TALER_MasterPublicKeyP master_pub; + +/** + * Our context for making HTTP requests. + */ +static struct GNUNET_CURL_Context *ctx; + +/** + * Reschedule context for #ctx. + */ +static struct GNUNET_CURL_RescheduleContext *rc; + +/** + * Handle to the exchange's configuration + */ +static const struct GNUNET_CONFIGURATION_Handle *kcfg; + +/** + * Return value from main(). + */ +static int global_ret; + +/** + * Input to consume. + */ +static json_t *in; + +/** + * Array of actions to perform. + */ +static json_t *out; + + +/** + * A subcommand supported by this program. + */ +struct SubCommand +{ +  /** +   * Name of the command. +   */ +  const char *name; + +  /** +   * Help text for the command. +   */ +  const char *help; + +  /** +   * Function implementing the command. +   * +   * @param args subsequent command line arguments (char **) +   */ +  void (*cb)(char *const *args); +}; + + +/** + * Data structure for wire add requests. + */ +struct DenominationAddRequest +{ + +  /** +   * Kept in a DLL. +   */ +  struct DenominationAddRequest *next; + +  /** +   * Kept in a DLL. +   */ +  struct DenominationAddRequest *prev; + +  /** +   * Operation handle. +   */ +  struct TALER_EXCHANGE_AuditorAddDenominationHandle *h; + +  /** +   * Array index of the associated command. +   */ +  size_t idx; +}; + + +/** + * Next work item to perform. + */ +static struct GNUNET_SCHEDULER_Task *nxt; + +/** + * Active denomination add requests. + */ +static struct DenominationAddRequest *dar_head; + +/** + * Active denomination add requests. + */ +static struct DenominationAddRequest *dar_tail; + +/** + * Handle to the exchange, used to request /keys. + */ +static struct TALER_EXCHANGE_Handle *exchange; + + +/** + * Shutdown task. Invoked when the application is being terminated. + * + * @param cls NULL + */ +static void +do_shutdown (void *cls) +{ +  (void) cls; + +  { +    struct DenominationAddRequest *dar; + +    while (NULL != (dar = dar_head)) +    { +      fprintf (stderr, +               "Aborting incomplete wire add #%u\n", +               (unsigned int) dar->idx); +      TALER_EXCHANGE_add_auditor_denomination_cancel (dar->h); +      GNUNET_CONTAINER_DLL_remove (dar_head, +                                   dar_tail, +                                   dar); +      GNUNET_free (dar); +    } +  } +  if (NULL != out) +  { +    json_dumpf (out, +                stdout, +                JSON_INDENT (2)); +    json_decref (out); +    out = NULL; +  } +  if (NULL != in) +  { +    fprintf (stderr, +             "Darning: input not consumed!\n"); +    json_decref (in); +    in = NULL; +  } +  if (NULL != exchange) +  { +    TALER_EXCHANGE_disconnect (exchange); +    exchange = NULL; +  } +  if (NULL != nxt) +  { +    GNUNET_SCHEDULER_cancel (nxt); +    nxt = NULL; +  } +  if (NULL != ctx) +  { +    GNUNET_CURL_fini (ctx); +    ctx = NULL; +  } +  if (NULL != rc) +  { +    GNUNET_CURL_gnunet_rc_destroy (rc); +    rc = NULL; +  } +} + + +/** + * Test if we should shut down because all tasks are done. + */ +static void +test_shutdown (void) +{ +  if ( (NULL == dar_head) && +       (NULL == exchange) && +       (NULL == nxt) ) +    GNUNET_SCHEDULER_shutdown (); +} + + +/** + * Function to continue processing the next command. + * + * @param cls must be a `char *const*` with the array of + *        command-line arguments to process next + */ +static void +work (void *cls); + + +/** + * Function to schedule job to process the next command. + * + * @param args the array of command-line arguments to process next + */ +static void +next (char *const *args) +{ +  GNUNET_assert (NULL == nxt); +  if (NULL == args[0]) +  { +    test_shutdown (); +    return; +  } +  nxt = GNUNET_SCHEDULER_add_now (&work, +                                  (void *) args); +} + + +/** + * Add an operation to the #out JSON array for processing later. + * + * @param op_name name of the operation + * @param op_value values for the operation (consumed) + */ +static void +output_operation (const char *op_name, +                  json_t *op_value) +{ +  json_t *action; + +  if (NULL == out) +    out = json_array (); +  action = json_pack ("{ s:s, s:o }", +                      "operation", +                      op_name, +                      "arguments", +                      op_value); +  GNUNET_break (0 == +                json_array_append_new (out, +                                       action)); +} + + +/** + * Information about a subroutine for an upload. + */ +struct UploadHandler +{ +  /** +   * Key to trigger this subroutine. +   */ +  const char *key; + +  /** +   * Function implementing an upload. +   * +   * @param exchange_url URL of the exchange +   * @param idx index of the operation we are performing +   * @param value arguments to drive the upload. +   */ +  void (*cb)(const char *exchange_url, +             size_t idx, +             const json_t *value); + +}; + + +/** + * Load the offline key (if not yet done). Triggers shutdown on failure. + * + * @return #GNUNET_OK on success + */ +static int +load_offline_key (void) +{ +  static bool done; +  int ret; +  char *fn; + +  if (done) +    return GNUNET_OK; +  if (GNUNET_OK != +      GNUNET_CONFIGURATION_get_value_filename (kcfg, +                                               "auditor", +                                               "AUDITOR_PRIV_FILE", +                                               &fn)) +  { +    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, +                               "auditor", +                               "AUDITOR_PRIV_FILE"); +    test_shutdown (); +    return GNUNET_SYSERR; +  } +  if (GNUNET_YES != +      GNUNET_DISK_file_test (fn)) +    GNUNET_log (GNUNET_ERROR_TYPE_INFO, +                "Auditor private key `%s' does not exist yet, creating it!\n", +                fn); +  ret = GNUNET_CRYPTO_eddsa_key_from_file (fn, +                                           GNUNET_YES, +                                           &auditor_priv.eddsa_priv); +  if (GNUNET_SYSERR == ret) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                "Failed to initialize auditor key from file `%s': %s\n", +                fn, +                "could not create file"); +    GNUNET_free (fn); +    test_shutdown (); +    return GNUNET_SYSERR; +  } +  GNUNET_free (fn); +  GNUNET_CRYPTO_eddsa_key_get_public (&auditor_priv.eddsa_priv, +                                      &auditor_pub.eddsa_pub); +  done = true; +  return GNUNET_OK; +} + + +/** + * Function called with information about the post denomination (signature) + * add operation result. + * + * @param cls closure with a `struct DenominationAddRequest` + * @param hr HTTP response data + */ +static void +denomination_add_cb ( +  void *cls, +  const struct TALER_EXCHANGE_HttpResponse *hr) +{ +  struct DenominationAddRequest *dar = cls; + +  if (MHD_HTTP_NO_CONTENT != hr->http_status) +  { +    fprintf (stderr, +             "Upload failed for command %u with status %u: %s (%s)\n", +             (unsigned int) dar->idx, +             hr->http_status, +             TALER_ErrorCode_get_hint (hr->ec), +             hr->hint); +  } +  GNUNET_CONTAINER_DLL_remove (dar_head, +                               dar_tail, +                               dar); +  GNUNET_free (dar); +  test_shutdown (); +} + + +/** + * Upload denomination add data. + * + * @param exchange_url base URL of the exchange + * @param idx index of the operation we are performing (for logging) + * @param value argumets for denomination revocation + */ +static void +upload_denomination_add (const char *exchange_url, +                         size_t idx, +                         const json_t *value) +{ +  struct TALER_AuditorSignatureP auditor_sig; +  struct GNUNET_HashCode h_denom_pub; +  struct DenominationAddRequest *dar; +  const char *err_name; +  unsigned int err_line; +  struct GNUNET_JSON_Specification spec[] = { +    GNUNET_JSON_spec_fixed_auto ("h_denom_pub", +                                 &h_denom_pub), +    GNUNET_JSON_spec_fixed_auto ("auditor_sig", +                                 &auditor_sig), +    GNUNET_JSON_spec_end () +  }; + +  if (GNUNET_OK != +      GNUNET_JSON_parse (value, +                         spec, +                         &err_name, +                         &err_line)) +  { +    fprintf (stderr, +             "Invalid input for adding wire account: %s#%u at %u (skipping)\n", +             err_name, +             err_line, +             (unsigned int) idx); +    global_ret = 7; +    test_shutdown (); +    return; +  } +  dar = GNUNET_new (struct DenominationAddRequest); +  dar->idx = idx; +  dar->h = +    TALER_EXCHANGE_add_auditor_denomination (ctx, +                                             exchange_url, +                                             &h_denom_pub, +                                             &auditor_pub, +                                             &auditor_sig, +                                             &denomination_add_cb, +                                             dar); +  GNUNET_CONTAINER_DLL_insert (dar_head, +                               dar_tail, +                               dar); +} + + +/** + * Perform uploads based on the JSON in #io. + * + * @param exchange_url base URL of the exchange to use + */ +static void +trigger_upload (const char *exchange_url) +{ +  struct UploadHandler uhs[] = { +    { +      .key = "sign-denomination", +      .cb = &upload_denomination_add +    }, +    /* array termination */ +    { +      .key = NULL +    } +  }; +  size_t index; +  json_t *obj; + +  json_array_foreach (out, index, obj) { +    bool found = false; +    const char *key; +    const json_t *value; + +    key = json_string_value (json_object_get (obj, "operation")); +    value = json_object_get (obj, "arguments"); +    if (NULL == key) +    { +      fprintf (stderr, +               "Malformed JSON input\n"); +      global_ret = 3; +      test_shutdown (); +      return; +    } +    /* block of code that uses key and value */ +    for (unsigned int i = 0; NULL != uhs[i].key; i++) +    { +      if (0 == strcasecmp (key, +                           uhs[i].key)) +      { +        found = true; +        uhs[i].cb (exchange_url, +                   index, +                   value); +        break; +      } +    } +    if (! found) +    { +      fprintf (stderr, +               "Upload does not know how to handle `%s'\n", +               key); +      global_ret = 3; +      test_shutdown (); +      return; +    } +  } +} + + +/** + * Upload operation result (signatures) to exchange. + * + * @param args the array of command-line arguments to process next + */ +static void +do_upload (char *const *args) +{ +  char *exchange_url; + +  if (NULL != in) +  { +    fprintf (stderr, +             "Downloaded data was not consumed, refusing upload\n"); +    test_shutdown (); +    global_ret = 4; +    return; +  } +  if (NULL == out) +  { +    json_error_t err; + +    out = json_loadf (stdin, +                      JSON_REJECT_DUPLICATES, +                      &err); +    if (NULL == out) +    { +      fprintf (stderr, +               "Failed to read JSON input: %s at %d:%s (offset: %d)\n", +               err.text, +               err.line, +               err.source, +               err.position); +      test_shutdown (); +      global_ret = 2; +      return; +    } +  } +  if (! json_is_array (out)) +  { +    fprintf (stderr, +             "Error: expected JSON array for `upload` command\n"); +    test_shutdown (); +    global_ret = 2; +    return; +  } +  if (GNUNET_OK != +      GNUNET_CONFIGURATION_get_value_string (kcfg, +                                             "exchange", +                                             "BASE_URL", +                                             &exchange_url)) +  { +    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, +                               "exchange", +                               "BASE_URL"); +    global_ret = 1; +    test_shutdown (); +    return; +  } +  trigger_upload (exchange_url); +  json_decref (out); +  out = NULL; +  GNUNET_free (exchange_url); +} + + +/** + * Function called with information about who is auditing + * a particular exchange and what keys the exchange is using. + * + * @param cls closure with the `char **` remaining args + * @param hr HTTP response data + * @param keys information about the various keys used + *        by the exchange, NULL if /keys failed + * @param compat protocol compatibility information + */ +static void +keys_cb ( +  void *cls, +  const struct TALER_EXCHANGE_HttpResponse *hr, +  const struct TALER_EXCHANGE_Keys *keys, +  enum TALER_EXCHANGE_VersionCompatibility compat) +{ +  char *const *args = cls; + +  switch (hr->http_status) +  { +  case MHD_HTTP_OK: +    break; +  default: +    fprintf (stderr, +             "Failed to download keys: %s (HTTP status: %u/%u)\n", +             hr->hint, +             hr->http_status, +             (unsigned int) hr->ec); +    TALER_EXCHANGE_disconnect (exchange); +    exchange = NULL; +    test_shutdown (); +    global_ret = 4; +    return; +  } +  if (NULL == args[0]) +  { +    json_dumpf (hr->reply, +                stdout, +                JSON_INDENT (2)); +  } +  else +  { +    in = json_incref ((json_t*) hr->reply); +  } +  TALER_EXCHANGE_disconnect (exchange); +  exchange = NULL; +  next (args); +} + + +/** + * Download future keys. + * + * @param args the array of command-line arguments to process next + */ +static void +do_download (char *const *args) +{ +  char *exchange_url; + +  if (GNUNET_OK != +      GNUNET_CONFIGURATION_get_value_string (kcfg, +                                             "exchange", +                                             "BASE_URL", +                                             &exchange_url)) +  { +    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, +                               "exchange", +                               "BASE_URL"); +    test_shutdown (); +    global_ret = 1; +    return; +  } +  exchange = TALER_EXCHANGE_connect (ctx, +                                     exchange_url, +                                     &keys_cb, +                                     (void *) args, +                                     TALER_EXCHANGE_OPTION_END); +  GNUNET_free (exchange_url); +} + + +/** + * Output @a denomkeys for human consumption. + * + * @param denomkeys keys to output + * @return #GNUNET_OK on success + */ +static int +show_denomkeys (const json_t *denomkeys) +{ +  size_t index; +  json_t *value; + +  json_array_foreach (denomkeys, index, value) { +    const char *err_name; +    unsigned int err_line; +    struct TALER_DenominationPublicKey denom_pub; +    struct GNUNET_TIME_Absolute stamp_start; +    struct GNUNET_TIME_Absolute stamp_expire_withdraw; +    struct GNUNET_TIME_Absolute stamp_expire_deposit; +    struct GNUNET_TIME_Absolute stamp_expire_legal; +    struct TALER_Amount coin_value; +    struct TALER_Amount fee_withdraw; +    struct TALER_Amount fee_deposit; +    struct TALER_Amount fee_refresh; +    struct TALER_Amount fee_refund; +    struct TALER_MasterSignatureP master_sig; +    struct GNUNET_JSON_Specification spec[] = { +      GNUNET_JSON_spec_rsa_public_key ("denom_pub", +                                       &denom_pub.rsa_public_key), +      TALER_JSON_spec_amount ("value", +                              &coin_value), +      TALER_JSON_spec_amount ("fee_withdraw", +                              &fee_withdraw), +      TALER_JSON_spec_amount ("fee_deposit", +                              &fee_deposit), +      TALER_JSON_spec_amount ("fee_refresh", +                              &fee_refresh), +      TALER_JSON_spec_amount ("fee_refund", +                              &fee_refund), +      GNUNET_JSON_spec_absolute_time ("stamp_start", +                                      &stamp_start), +      GNUNET_JSON_spec_absolute_time ("stamp_expire_withdraw", +                                      &stamp_expire_withdraw), +      GNUNET_JSON_spec_absolute_time ("stamp_expire_deposit", +                                      &stamp_expire_deposit), +      GNUNET_JSON_spec_absolute_time ("stamp_expire_legal", +                                      &stamp_expire_legal), +      GNUNET_JSON_spec_fixed_auto ("master_sig", +                                   &master_sig), +      GNUNET_JSON_spec_end () +    }; +    struct GNUNET_TIME_Relative duration; +    struct GNUNET_HashCode h_denom_pub; + +    if (GNUNET_OK != +        GNUNET_JSON_parse (value, +                           spec, +                           &err_name, +                           &err_line)) +    { +      fprintf (stderr, +               "Invalid input for denomination key to 'show': %s#%u at %u (skipping)\n", +               err_name, +               err_line, +               (unsigned int) index); +      GNUNET_JSON_parse_free (spec); +      global_ret = 7; +      test_shutdown (); +      return GNUNET_SYSERR; +    } +    duration = GNUNET_TIME_absolute_get_difference (stamp_start, +                                                    stamp_expire_withdraw); +    GNUNET_CRYPTO_rsa_public_key_hash (denom_pub.rsa_public_key, +                                       &h_denom_pub); +    if (GNUNET_OK != +        TALER_exchange_offline_denom_validity_verify ( +          &h_denom_pub, +          stamp_start, +          stamp_expire_withdraw, +          stamp_expire_deposit, +          stamp_expire_legal, +          &coin_value, +          &fee_withdraw, +          &fee_deposit, +          &fee_refresh, +          &fee_refund, +          &master_pub, +          &master_sig)) +    { +      fprintf (stderr, +               "Invalid master signature for key %s (aborting)\n", +               TALER_B2S (&h_denom_pub)); +      global_ret = 9; +      test_shutdown (); +      return GNUNET_SYSERR; +    } + +    { +      char *withdraw_fee_s; +      char *deposit_fee_s; +      char *refresh_fee_s; +      char *refund_fee_s; +      char *deposit_s; +      char *legal_s; + +      withdraw_fee_s = TALER_amount_to_string (&fee_withdraw); +      deposit_fee_s = TALER_amount_to_string (&fee_deposit); +      refresh_fee_s = TALER_amount_to_string (&fee_refresh); +      refund_fee_s = TALER_amount_to_string (&fee_refund); +      deposit_s = GNUNET_strdup ( +        GNUNET_STRINGS_absolute_time_to_string (stamp_expire_deposit)); +      legal_s = GNUNET_strdup ( +        GNUNET_STRINGS_absolute_time_to_string (stamp_expire_legal)); + +      printf ( +        "DENOMINATION-KEY %s of value %s starting at %s " +        "(used for: %s, deposit until: %s legal end: %s) with fees %s/%s/%s/%s\n", +        TALER_B2S (&h_denom_pub), +        TALER_amount2s (&coin_value), +        GNUNET_STRINGS_absolute_time_to_string (stamp_start), +        GNUNET_STRINGS_relative_time_to_string (duration, +                                                GNUNET_NO), +        deposit_s, +        legal_s, +        withdraw_fee_s, +        deposit_fee_s, +        refresh_fee_s, +        refund_fee_s); +      GNUNET_free (withdraw_fee_s); +      GNUNET_free (deposit_fee_s); +      GNUNET_free (refresh_fee_s); +      GNUNET_free (refund_fee_s); +      GNUNET_free (deposit_s); +      GNUNET_free (legal_s); +    } + +    GNUNET_JSON_parse_free (spec); +  } +  return GNUNET_OK; +} + + +/** + * Show exchange denomination keys. + * + * @param args the array of command-line arguments to process next + */ +static void +do_show (char *const *args) +{ +  if (NULL == in) +  { +    json_error_t err; + +    out = json_loadf (stdin, +                      JSON_REJECT_DUPLICATES, +                      &err); +    if (NULL == in) +    { +      fprintf (stderr, +               "Failed to read JSON input: %s at %d:%s (offset: %d)\n", +               err.text, +               err.line, +               err.source, +               err.position); +      global_ret = 2; +      test_shutdown (); +      return; +    } +  } + +  { +    const char *err_name; +    unsigned int err_line; +    json_t *denomkeys; +    struct TALER_MasterPublicKeyP mpub; +    struct GNUNET_JSON_Specification spec[] = { +      GNUNET_JSON_spec_json ("denoms", +                             &denomkeys), +      GNUNET_JSON_spec_fixed_auto ("master_public_key", +                                   &mpub), +      GNUNET_JSON_spec_end () +    }; + +    if (GNUNET_OK != +        GNUNET_JSON_parse (in, +                           spec, +                           &err_name, +                           &err_line)) +    { +      fprintf (stderr, +               "Invalid input to 'show': %s#%u (skipping)\n", +               err_name, +               err_line); +      global_ret = 7; +      test_shutdown (); +      return; +    } +    if (0 != +        GNUNET_memcmp (&mpub, +                       &master_pub)) +    { +      fprintf (stderr, +               "Exchange master public key does not match key we have configured (aborting)\n"); +      global_ret = 7; +      test_shutdown (); +      return; +    } +    if (GNUNET_OK != +        show_denomkeys (denomkeys)) +    { +      global_ret = 8; +      test_shutdown (); +      GNUNET_JSON_parse_free (spec); +      return; +    } +    GNUNET_JSON_parse_free (spec); +  } +  /* do NOT consume input if next argument is '-' */ +  if ( (NULL != args[0]) && +       (0 == strcmp ("-", +                     args[0])) ) +  { +    next (args + 1); +    return; +  } +  json_decref (in); +  in = NULL; +  next (args); +} + + +/** + * Sign @a denomkeys with offline key. + * + * @param denomkeys keys to output + * @return #GNUNET_OK on success + */ +static int +sign_denomkeys (const json_t *denomkeys) +{ +  size_t index; +  json_t *value; + +  json_array_foreach (denomkeys, index, value) { +    const char *err_name; +    unsigned int err_line; +    struct TALER_DenominationPublicKey denom_pub; +    struct GNUNET_TIME_Absolute stamp_start; +    struct GNUNET_TIME_Absolute stamp_expire_withdraw; +    struct GNUNET_TIME_Absolute stamp_expire_deposit; +    struct GNUNET_TIME_Absolute stamp_expire_legal; +    struct TALER_Amount coin_value; +    struct TALER_Amount fee_withdraw; +    struct TALER_Amount fee_deposit; +    struct TALER_Amount fee_refresh; +    struct TALER_Amount fee_refund; +    struct TALER_MasterSignatureP master_sig; +    struct GNUNET_JSON_Specification spec[] = { +      GNUNET_JSON_spec_rsa_public_key ("denom_pub", +                                       &denom_pub.rsa_public_key), +      TALER_JSON_spec_amount ("value", +                              &coin_value), +      TALER_JSON_spec_amount ("fee_withdraw", +                              &fee_withdraw), +      TALER_JSON_spec_amount ("fee_deposit", +                              &fee_deposit), +      TALER_JSON_spec_amount ("fee_refresh", +                              &fee_refresh), +      TALER_JSON_spec_amount ("fee_refund", +                              &fee_refund), +      GNUNET_JSON_spec_absolute_time ("stamp_start", +                                      &stamp_start), +      GNUNET_JSON_spec_absolute_time ("stamp_expire_withdraw", +                                      &stamp_expire_withdraw), +      GNUNET_JSON_spec_absolute_time ("stamp_expire_deposit", +                                      &stamp_expire_deposit), +      GNUNET_JSON_spec_absolute_time ("stamp_expire_legal", +                                      &stamp_expire_legal), +      GNUNET_JSON_spec_fixed_auto ("master_sig", +                                   &master_sig), +      GNUNET_JSON_spec_end () +    }; +    struct GNUNET_HashCode h_denom_pub; + +    if (GNUNET_OK != +        GNUNET_JSON_parse (value, +                           spec, +                           &err_name, +                           &err_line)) +    { +      fprintf (stderr, +               "Invalid input for denomination key to 'sign': %s#%u at %u (skipping)\n", +               err_name, +               err_line, +               (unsigned int) index); +      GNUNET_JSON_parse_free (spec); +      global_ret = 7; +      test_shutdown (); +      return GNUNET_SYSERR; +    } +    GNUNET_CRYPTO_rsa_public_key_hash (denom_pub.rsa_public_key, +                                       &h_denom_pub); +    if (GNUNET_OK != +        TALER_exchange_offline_denom_validity_verify ( +          &h_denom_pub, +          stamp_start, +          stamp_expire_withdraw, +          stamp_expire_deposit, +          stamp_expire_legal, +          &coin_value, +          &fee_withdraw, +          &fee_deposit, +          &fee_refresh, +          &fee_refund, +          &master_pub, +          &master_sig)) +    { +      fprintf (stderr, +               "Invalid master signature for key %s (aborting)\n", +               TALER_B2S (&h_denom_pub)); +      global_ret = 9; +      test_shutdown (); +      return GNUNET_SYSERR; +    } + +    { +      struct TALER_AuditorSignatureP auditor_sig; + +      TALER_auditor_denom_validity_sign (auditor_url, +                                         &h_denom_pub, +                                         &master_pub, +                                         stamp_start, +                                         stamp_expire_withdraw, +                                         stamp_expire_deposit, +                                         stamp_expire_legal, +                                         &coin_value, +                                         &fee_withdraw, +                                         &fee_deposit, +                                         &fee_refresh, +                                         &fee_refund, +                                         &auditor_priv, +                                         &auditor_sig); +      output_operation ("sign-denomination", +                        json_pack ("{s:o,s:o}", +                                   "h_denomn_pub", +                                   GNUNET_JSON_from_data_auto (&h_denom_pub), +                                   "auditor_sig", +                                   GNUNET_JSON_from_data_auto (&auditor_sig))); +    } +    GNUNET_JSON_parse_free (spec); +  } +  return GNUNET_OK; +} + + +/** + * Sign denomination keys. + * + * @param args the array of command-line arguments to process next + */ +static void +do_sign (char *const *args) +{ +  if (NULL == in) +  { +    json_error_t err; + +    out = json_loadf (stdin, +                      JSON_REJECT_DUPLICATES, +                      &err); +    if (NULL == in) +    { +      fprintf (stderr, +               "Failed to read JSON input: %s at %d:%s (offset: %d)\n", +               err.text, +               err.line, +               err.source, +               err.position); +      global_ret = 2; +      test_shutdown (); +      return; +    } +  } +  if (GNUNET_OK != +      load_offline_key ()) +    return; + +  { +    const char *err_name; +    unsigned int err_line; +    struct TALER_MasterPublicKeyP mpub; +    json_t *denomkeys; +    struct GNUNET_JSON_Specification spec[] = { +      GNUNET_JSON_spec_json ("denoms", +                             &denomkeys), +      GNUNET_JSON_spec_fixed_auto ("master_public_key", +                                   &mpub), +      GNUNET_JSON_spec_end () +    }; + +    if (GNUNET_OK != +        GNUNET_JSON_parse (in, +                           spec, +                           &err_name, +                           &err_line)) +    { +      fprintf (stderr, +               "Invalid input to 'sign': %s#%u (skipping)\n", +               err_name, +               err_line); +      global_ret = 7; +      test_shutdown (); +      return; +    } +    if (0 != +        GNUNET_memcmp (&mpub, +                       &master_pub)) +    { +      fprintf (stderr, +               "Exchange master public key does not match key we have configured (aborting)\n"); +      global_ret = 7; +      test_shutdown (); +      return; +    } +    if (GNUNET_OK != +        sign_denomkeys (denomkeys)) +    { +      global_ret = 8; +      test_shutdown (); +      GNUNET_JSON_parse_free (spec); +      return; +    } +    GNUNET_JSON_parse_free (spec); +  } +  json_decref (in); +  in = NULL; +  next (args); +} + + +static void +work (void *cls) +{ +  char *const *args = cls; +  struct SubCommand cmds[] = { +    { +      .name = "download", +      .help = +        "obtain keys from exchange (to be performed online!)", +      .cb = &do_download +    }, +    { +      .name = "show", +      .help = +        "display keys from exchange for human review (pass '-' as argument to disable consuming input)", +      .cb = &do_show +    }, +    { +      .name = "sign", +      .help = +        "sing all denomination keys from the input", +      .cb = &do_sign +    }, +    { +      .name = "upload", +      .help = +        "upload operation result to exchange (to be performed online!)", +      .cb = &do_upload +    }, +    /* list terminator */ +    { +      .name = NULL, +    } +  }; +  (void) cls; + +  nxt = NULL; +  for (unsigned int i = 0; NULL != cmds[i].name; i++) +  { +    if (0 == strcasecmp (cmds[i].name, +                         args[0])) +    { +      cmds[i].cb (&args[1]); +      return; +    } +  } + +  if (0 != strcasecmp ("help", +                       args[0])) +  { +    fprintf (stderr, +             "Unexpected command `%s'\n", +             args[0]); +    global_ret = 3; +  } +  fprintf (stderr, +           "Supported subcommands:\n"); +  for (unsigned int i = 0; NULL != cmds[i].name; i++) +  { +    fprintf (stderr, +             "\t%s - %s\n", +             cmds[i].name, +             cmds[i].help); +  } +} + + +/** + * Main function that will be run. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, +     char *const *args, +     const char *cfgfile, +     const struct GNUNET_CONFIGURATION_Handle *cfg) +{ +  kcfg = cfg; +  if (GNUNET_OK != +      GNUNET_CONFIGURATION_get_value_string (kcfg, +                                             "auditor", +                                             "BASE_URL", +                                             &auditor_url)) +  { +    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, +                               "auditor", +                               "BASE_URL"); +    global_ret = 1; +    return; +  } +  { +    char *master_public_key_str; + +    if (GNUNET_OK != +        GNUNET_CONFIGURATION_get_value_string (cfg, +                                               "exchange", +                                               "MASTER_PUBLIC_KEY", +                                               &master_public_key_str)) +    { +      GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, +                                 "exchange", +                                 "MASTER_PUBLIC_KEY"); +      global_ret = 1; +      return; +    } +    if (GNUNET_OK != +        GNUNET_CRYPTO_eddsa_public_key_from_string ( +          master_public_key_str, +          strlen (master_public_key_str), +          &master_pub.eddsa_pub)) +    { +      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                  "Invalid master public key given in exchange configuration."); +      GNUNET_free (master_public_key_str); +      global_ret = 1; +      return; +    } +    GNUNET_free (master_public_key_str); +  } +  ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, +                          &rc); +  rc = GNUNET_CURL_gnunet_rc_create (ctx); +  GNUNET_SCHEDULER_add_shutdown (&do_shutdown, +                                 NULL); +  next (args); +} + + +/** + * The main function of the taler-auditor-offline tool.  This tool is used to + * sign denomination keys with the auditor's key.  It uses the long-term + * offline private key of the auditor and generates signatures with it. It + * also supports online operations with the exchange to download its input + * data and to upload its results. Those online operations should be performed + * on another machine in production! + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, +      char *const *argv) +{ +  struct GNUNET_GETOPT_CommandLineOption options[] = { +    GNUNET_GETOPT_OPTION_END +  }; + +  /* force linker to link against libtalerutil; if we do +     not do this, the linker may "optimize" libtalerutil +     away and skip #TALER_OS_init(), which we do need */ +  (void) TALER_project_data_default (); +  GNUNET_assert (GNUNET_OK == +                 GNUNET_log_setup ("taler-auditor-offline", +                                   "WARNING", +                                   NULL)); +  if (GNUNET_OK != +      GNUNET_PROGRAM_run (argc, argv, +                          "taler-auditor-offline", +                          "Operations for offline signing for a Taler exchange", +                          options, +                          &run, NULL)) +    return 1; +  return global_ret; +} + + +/* end of taler-auditor-offline.c */ diff --git a/src/exchange-tools/taler-exchange-offline.c b/src/exchange-tools/taler-exchange-offline.c index d6b16514..5c9e6398 100644 --- a/src/exchange-tools/taler-exchange-offline.c +++ b/src/exchange-tools/taler-exchange-offline.c @@ -2391,6 +2391,9 @@ do_sign (char *const *args)        return;      }    } +  if (GNUNET_OK != +      load_offline_key ()) +    return;    {      const char *err_name; diff --git a/src/exchange/taler-exchange-httpd_auditors.c b/src/exchange/taler-exchange-httpd_auditors.c index f0fbb7eb..62bfc304 100644 --- a/src/exchange/taler-exchange-httpd_auditors.c +++ b/src/exchange/taler-exchange-httpd_auditors.c @@ -144,49 +144,34 @@ add_auditor_denom_sig (void *cls,        TALER_B2S (awc->auditor_pub));      return GNUNET_DB_STATUS_HARD_ERROR;    } +  if (GNUNET_OK != +      TALER_auditor_denom_validity_verify ( +        auditor_url, +        awc->h_denom_pub, +        &TEH_master_public_key, +        meta.start, +        meta.expire_withdraw, +        meta.expire_deposit, +        meta.expire_legal, +        &meta.value, +        &meta.fee_withdraw, +        &meta.fee_deposit, +        &meta.fee_refresh, +        &meta.fee_refund, +        awc->auditor_pub, +        &awc->auditor_sig))    { -    struct TALER_ExchangeKeyValidityPS kv = { -      .purpose.purpose = htonl (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS), -      .purpose.size = htonl (sizeof (kv)), -      .master = TEH_master_public_key, -      .start = GNUNET_TIME_absolute_hton (meta.start), -      .expire_withdraw = GNUNET_TIME_absolute_hton (meta.expire_withdraw), -      .expire_deposit = GNUNET_TIME_absolute_hton (meta.expire_deposit), -      .expire_legal = GNUNET_TIME_absolute_hton (meta.expire_legal), -      .denom_hash = *awc->h_denom_pub -    }; - -    TALER_amount_hton (&kv.value, -                       &meta.value); -    TALER_amount_hton (&kv.fee_withdraw, -                       &meta.fee_withdraw); -    TALER_amount_hton (&kv.fee_deposit, -                       &meta.fee_deposit); -    TALER_amount_hton (&kv.fee_refresh, -                       &meta.fee_refresh); -    TALER_amount_hton (&kv.fee_refund, -                       &meta.fee_refund); -    GNUNET_CRYPTO_hash (auditor_url, -                        strlen (auditor_url) + 1, -                        &kv.auditor_url_hash);      GNUNET_free (auditor_url); -    if (GNUNET_OK != -        GNUNET_CRYPTO_eddsa_verify ( -          TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS, -          &kv, -          &awc->auditor_sig.eddsa_sig, -          &TEH_master_public_key.eddsa_pub)) -    { -      /* signature invalid */ -      GNUNET_break_op (0); -      *mhd_ret = TALER_MHD_reply_with_error ( -        connection, -        MHD_HTTP_FORBIDDEN, -        TALER_EC_EXCHANGE_AUDITORS_AUDITOR_SIGNATURE_INVALID, -        NULL); -      return GNUNET_DB_STATUS_HARD_ERROR; -    } +    /* signature invalid */ +    GNUNET_break_op (0); +    *mhd_ret = TALER_MHD_reply_with_error ( +      connection, +      MHD_HTTP_FORBIDDEN, +      TALER_EC_EXCHANGE_AUDITORS_AUDITOR_SIGNATURE_INVALID, +      NULL); +    return GNUNET_DB_STATUS_HARD_ERROR;    } +  GNUNET_free (auditor_url);    qs = TEH_plugin->insert_auditor_denom_sig (TEH_plugin->cls,                                               session, diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h index 757dee67..1c77bfe6 100644 --- a/src/include/taler_crypto_lib.h +++ b/src/include/taler_crypto_lib.h @@ -1294,6 +1294,79 @@ TALER_exchange_secmod_rsa_verify (    const struct TALER_SecurityModuleSignatureP *secm_sig); +/** + * Create denomination key validity signature by the auditor. + * + * @param auditor_url BASE URL of the auditor's API + * @param h_denom_pub hash of the denomination's public key + * @param master_pub master public key of the exchange + * @param stamp_start when does the exchange begin signing with this key + * @param stamp_expire_withdraw when does the exchange end signing with this key + * @param stamp_expire_deposit how long does the exchange accept the deposit of coins with this key + * @param stamp_expire_legal how long does the exchange preserve information for legal disputes with this key + * @param coin_value what is the value of coins signed with this key + * @param fee_withdraw what withdraw fee does the exchange charge for this denomination + * @param fee_deposit what deposit fee does the exchange charge for this denomination + * @param fee_refresh what refresh fee does the exchange charge for this denomination + * @param fee_refund what refund fee does the exchange charge for this denomination + * @param auditor_priv private key to sign with + * @param[out] auditor_sig where to write the signature + */ +void +TALER_auditor_denom_validity_sign ( +  const char *auditor_url, +  const struct GNUNET_HashCode *h_denom_pub, +  const struct TALER_MasterPublicKeyP *master_pub, +  struct GNUNET_TIME_Absolute stamp_start, +  struct GNUNET_TIME_Absolute stamp_expire_withdraw, +  struct GNUNET_TIME_Absolute stamp_expire_deposit, +  struct GNUNET_TIME_Absolute stamp_expire_legal, +  const struct TALER_Amount *coin_value, +  const struct TALER_Amount *fee_withdraw, +  const struct TALER_Amount *fee_deposit, +  const struct TALER_Amount *fee_refresh, +  const struct TALER_Amount *fee_refund, +  const struct TALER_AuditorPrivateKeyP *auditor_priv, +  struct TALER_AuditorSignatureP *auditor_sig); + + +/** + * Verify denomination key validity signature from auditor. + * + * @param auditor_url BASE URL of the auditor's API + * @param h_denom_pub hash of the denomination's public key + * @param master_pub master public key of the exchange + * @param stamp_start when does the exchange begin signing with this key + * @param stamp_expire_withdraw when does the exchange end signing with this key + * @param stamp_expire_deposit how long does the exchange accept the deposit of coins with this key + * @param stamp_expire_legal how long does the exchange preserve information for legal disputes with this key + * @param coin_value what is the value of coins signed with this key + * @param fee_withdraw what withdraw fee does the exchange charge for this denomination + * @param fee_deposit what deposit fee does the exchange charge for this denomination + * @param fee_refresh what refresh fee does the exchange charge for this denomination + * @param fee_refund what refund fee does the exchange charge for this denomination + * @param auditor_pub public key to verify against + * @param auditor_sig the signature the signature + * @return #GNUNET_OK if the signature is valid + */ +int +TALER_auditor_denom_validity_verify ( +  const char *auditor_url, +  const struct GNUNET_HashCode *h_denom_pub, +  const struct TALER_MasterPublicKeyP *master_pub, +  struct GNUNET_TIME_Absolute stamp_start, +  struct GNUNET_TIME_Absolute stamp_expire_withdraw, +  struct GNUNET_TIME_Absolute stamp_expire_deposit, +  struct GNUNET_TIME_Absolute stamp_expire_legal, +  const struct TALER_Amount *coin_value, +  const struct TALER_Amount *fee_withdraw, +  const struct TALER_Amount *fee_deposit, +  const struct TALER_Amount *fee_refresh, +  const struct TALER_Amount *fee_refund, +  const struct TALER_AuditorPublicKeyP *auditor_pub, +  const struct TALER_AuditorSignatureP *auditor_sig); + +  /* **************** /wire account offline signing **************** */ diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index 512dfb35..5691e58d 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -393,7 +393,7 @@ struct TALER_EXCHANGE_HttpResponse  /**   * Function called with information about who is auditing - * a particular exchange and what key the exchange is using. + * a particular exchange and what keys the exchange is using.   *   * @param cls closure   * @param hr HTTP response data diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h index c30f21d6..5f380812 100644 --- a/src/include/taler_signatures.h +++ b/src/include/taler_signatures.h @@ -1041,7 +1041,7 @@ struct TALER_ExchangeKeyValidityPS    /**     * The long-term offline master key of the exchange, affirmed by the -   * auditor.  Hashed string, including 0-terminator. +   * auditor.     */    struct TALER_MasterPublicKeyP master; diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c index e630adf9..9d4ebf56 100644 --- a/src/lib/exchange_api_handle.c +++ b/src/lib/exchange_api_handle.c @@ -519,7 +519,6 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,    unsigned int off;    unsigned int i;    const char *auditor_url; -  struct TALER_ExchangeKeyValidityPS kv;    struct GNUNET_JSON_Specification spec[] = {      GNUNET_JSON_spec_fixed_auto ("auditor_pub",                                   &auditor->auditor_pub), @@ -539,12 +538,6 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,      return GNUNET_SYSERR;    }    auditor->auditor_url = GNUNET_strdup (auditor_url); -  kv.purpose.purpose = htonl (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS); -  kv.purpose.size = htonl (sizeof (struct TALER_ExchangeKeyValidityPS)); -  GNUNET_CRYPTO_hash (auditor_url, -                      strlen (auditor_url) + 1, -                      &kv.auditor_url_hash); -  kv.master = key_data->master_pub;    len = json_array_size (keys);    auditor->denom_keys = GNUNET_new_array (len,                                            struct @@ -590,27 +583,22 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,      }      if (check_sigs)      { -      kv.start = GNUNET_TIME_absolute_hton (dk->valid_from); -      kv.expire_withdraw = GNUNET_TIME_absolute_hton (dk->withdraw_valid_until); -      kv.expire_deposit = GNUNET_TIME_absolute_hton (dk->expire_deposit); -      kv.expire_legal = GNUNET_TIME_absolute_hton (dk->expire_legal); -      TALER_amount_hton (&kv.value, -                         &dk->value); -      TALER_amount_hton (&kv.fee_withdraw, -                         &dk->fee_withdraw); -      TALER_amount_hton (&kv.fee_deposit, -                         &dk->fee_deposit); -      TALER_amount_hton (&kv.fee_refresh, -                         &dk->fee_refresh); -      TALER_amount_hton (&kv.fee_refund, -                         &dk->fee_refund); -      kv.denom_hash = dk->h_key; -        if (GNUNET_OK != -          GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS, -                                      &kv, -                                      &auditor_sig.eddsa_sig, -                                      &auditor->auditor_pub.eddsa_pub)) +          TALER_auditor_denom_validity_verify ( +            auditor_url, +            &dk->h_key, +            &key_data->master_pub, +            dk->valid_from, +            dk->withdraw_valid_until, +            dk->expire_deposit, +            dk->expire_legal, +            &dk->value, +            &dk->fee_withdraw, +            &dk->fee_deposit, +            &dk->fee_refresh, +            &dk->fee_refund, +            &auditor->auditor_pub, +            &auditor_sig))        {          GNUNET_break_op (0);          GNUNET_JSON_parse_free (spec); diff --git a/src/testing/testing_api_cmd_auditor_add_denom_sig.c b/src/testing/testing_api_cmd_auditor_add_denom_sig.c index 8d5aace4..efa4a9d7 100644 --- a/src/testing/testing_api_cmd_auditor_add_denom_sig.c +++ b/src/testing/testing_api_cmd_auditor_add_denom_sig.c @@ -139,36 +139,25 @@ auditor_add_run (void *cls,    }    else    { -    struct TALER_ExchangeKeyValidityPS kv = { -      .purpose.purpose = htonl (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS), -      .purpose.size = htonl (sizeof (struct TALER_ExchangeKeyValidityPS)), -      .start = GNUNET_TIME_absolute_hton (dk->valid_from), -      .expire_withdraw = GNUNET_TIME_absolute_hton ( -        dk->withdraw_valid_until), -      .expire_deposit = GNUNET_TIME_absolute_hton (dk->expire_deposit), -      .expire_legal = GNUNET_TIME_absolute_hton (dk->expire_legal), -      .denom_hash = dk->h_key -    }; +    struct TALER_MasterPublicKeyP master_pub; -    TALER_amount_hton (&kv.value, -                       &dk->value); -    TALER_amount_hton (&kv.fee_withdraw, -                       &dk->fee_withdraw); -    TALER_amount_hton (&kv.fee_deposit, -                       &dk->fee_deposit); -    TALER_amount_hton (&kv.fee_refresh, -                       &dk->fee_refresh); -    TALER_amount_hton (&kv.fee_refund, -                       &dk->fee_refund);      GNUNET_CRYPTO_eddsa_key_get_public (&is->master_priv.eddsa_priv, -                                        &kv.master.eddsa_pub); -    GNUNET_CRYPTO_hash (is->auditor_url, -                        strlen (is->auditor_url) + 1, -                        &kv.auditor_url_hash); -    /* Finally sign ... */ -    GNUNET_CRYPTO_eddsa_sign (&is->auditor_priv.eddsa_priv, -                              &kv, -                              &auditor_sig.eddsa_sig); +                                        &master_pub.eddsa_pub); +    TALER_auditor_denom_validity_sign ( +      is->auditor_url, +      &dk->h_key, +      &master_pub, +      dk->valid_from, +      dk->withdraw_valid_until, +      dk->expire_deposit, +      dk->expire_legal, +      &dk->value, +      &dk->fee_withdraw, +      &dk->fee_deposit, +      &dk->fee_refresh, +      &dk->fee_refund, +      &is->auditor_priv, +      &auditor_sig);    }    ds->dh = TALER_EXCHANGE_add_auditor_denomination (      is->ctx, diff --git a/src/util/Makefile.am b/src/util/Makefile.am index bf460a57..9dcc4035 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -60,6 +60,7 @@ lib_LTLIBRARIES = \  libtalerutil_la_SOURCES = \    amount.c \ +  auditor_signatures.c \    config.c \    crypto.c \    crypto_helper_denom.c \ diff --git a/src/util/auditor_signatures.c b/src/util/auditor_signatures.c new file mode 100644 index 00000000..837b31c6 --- /dev/null +++ b/src/util/auditor_signatures.c @@ -0,0 +1,122 @@ +/* +  This file is part of TALER +  Copyright (C) 2020 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 +  Foundation; either version 3, or (at your option) any later version. + +  TALER is distributed in the hope that it will be useful, but WITHOUT ANY +  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +  A PARTICULAR PURPOSE.  See the GNU General Public License for more details. + +  You should have received a copy of the GNU General Public License along with +  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file auditor_signatures.c + * @brief Utility functions for Taler auditor signatures + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_util.h" +#include "taler_signatures.h" + + +void +TALER_auditor_denom_validity_sign ( +  const char *auditor_url, +  const struct GNUNET_HashCode *h_denom_pub, +  const struct TALER_MasterPublicKeyP *master_pub, +  struct GNUNET_TIME_Absolute stamp_start, +  struct GNUNET_TIME_Absolute stamp_expire_withdraw, +  struct GNUNET_TIME_Absolute stamp_expire_deposit, +  struct GNUNET_TIME_Absolute stamp_expire_legal, +  const struct TALER_Amount *coin_value, +  const struct TALER_Amount *fee_withdraw, +  const struct TALER_Amount *fee_deposit, +  const struct TALER_Amount *fee_refresh, +  const struct TALER_Amount *fee_refund, +  const struct TALER_AuditorPrivateKeyP *auditor_priv, +  struct TALER_AuditorSignatureP *auditor_sig) +{ +  struct TALER_ExchangeKeyValidityPS kv = { +    .purpose.purpose = htonl (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS), +    .purpose.size = htonl (sizeof (kv)), +    .start = GNUNET_TIME_absolute_hton (stamp_start), +    .expire_withdraw = GNUNET_TIME_absolute_hton (stamp_expire_withdraw), +    .expire_deposit = GNUNET_TIME_absolute_hton (stamp_expire_deposit), +    .expire_legal = GNUNET_TIME_absolute_hton (stamp_expire_legal), +    .denom_hash = *h_denom_pub, +    .master = *master_pub, +  }; + +  TALER_amount_hton (&kv.value, +                     coin_value); +  TALER_amount_hton (&kv.fee_withdraw, +                     fee_withdraw); +  TALER_amount_hton (&kv.fee_deposit, +                     fee_deposit); +  TALER_amount_hton (&kv.fee_refresh, +                     fee_refresh); +  TALER_amount_hton (&kv.fee_refund, +                     fee_refund); +  GNUNET_CRYPTO_hash (auditor_url, +                      strlen (auditor_url) + 1, +                      &kv.auditor_url_hash); +  GNUNET_CRYPTO_eddsa_sign (&auditor_priv->eddsa_priv, +                            &kv, +                            &auditor_sig->eddsa_sig); +} + + +int +TALER_auditor_denom_validity_verify ( +  const char *auditor_url, +  const struct GNUNET_HashCode *h_denom_pub, +  const struct TALER_MasterPublicKeyP *master_pub, +  struct GNUNET_TIME_Absolute stamp_start, +  struct GNUNET_TIME_Absolute stamp_expire_withdraw, +  struct GNUNET_TIME_Absolute stamp_expire_deposit, +  struct GNUNET_TIME_Absolute stamp_expire_legal, +  const struct TALER_Amount *coin_value, +  const struct TALER_Amount *fee_withdraw, +  const struct TALER_Amount *fee_deposit, +  const struct TALER_Amount *fee_refresh, +  const struct TALER_Amount *fee_refund, +  const struct TALER_AuditorPublicKeyP *auditor_pub, +  const struct TALER_AuditorSignatureP *auditor_sig) +{ +  struct TALER_ExchangeKeyValidityPS kv = { +    .purpose.purpose = htonl (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS), +    .purpose.size = htonl (sizeof (kv)), +    .start = GNUNET_TIME_absolute_hton (stamp_start), +    .expire_withdraw = GNUNET_TIME_absolute_hton (stamp_expire_withdraw), +    .expire_deposit = GNUNET_TIME_absolute_hton (stamp_expire_deposit), +    .expire_legal = GNUNET_TIME_absolute_hton (stamp_expire_legal), +    .denom_hash = *h_denom_pub, +    .master = *master_pub, +  }; + +  TALER_amount_hton (&kv.value, +                     coin_value); +  TALER_amount_hton (&kv.fee_withdraw, +                     fee_withdraw); +  TALER_amount_hton (&kv.fee_deposit, +                     fee_deposit); +  TALER_amount_hton (&kv.fee_refresh, +                     fee_refresh); +  TALER_amount_hton (&kv.fee_refund, +                     fee_refund); +  GNUNET_CRYPTO_hash (auditor_url, +                      strlen (auditor_url) + 1, +                      &kv.auditor_url_hash); +  return +    GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS, +                                &kv, +                                &auditor_sig->eddsa_sig, +                                &auditor_pub->eddsa_pub); +} + + +/* end of auditor_signatures.c */ | 
