exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

exchange_api_handle.c (75424B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014-2023 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it
      6   under the terms of the GNU General Public License as published
      7   by the Free Software Foundation; either version 3, or (at your
      8   option) any later version.
      9 
     10   TALER is distributed in the hope that it will be useful, but
     11   WITHOUT ANY WARRANTY; without even the implied warranty of
     12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13   GNU General Public License for more details.
     14 
     15   You should have received a copy of the GNU General Public
     16   License along with TALER; see the file COPYING.  If not, see
     17   <http://www.gnu.org/licenses/>
     18 */
     19 
     20 /**
     21  * @file lib/exchange_api_handle.c
     22  * @brief Implementation of the "handle" component of the exchange's HTTP API
     23  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
     24  * @author Christian Grothoff
     25  */
     26 #include <microhttpd.h>
     27 #include <gnunet/gnunet_curl_lib.h>
     28 #include "taler/taler_json_lib.h"
     29 #include "taler/taler_auditor_service.h"
     30 #include "taler/taler_signatures.h"
     31 #include "taler/taler_extensions.h"
     32 #include "exchange_api_handle.h"
     33 #include "taler/taler_curl_lib.h"
     34 
     35 /**
     36  * Which version of the Taler protocol is implemented
     37  * by this library?  Used to determine compatibility.
     38  */
     39 #define EXCHANGE_PROTOCOL_CURRENT 33
     40 
     41 /**
     42  * How many versions are we backwards compatible with?
     43  */
     44 #define EXCHANGE_PROTOCOL_AGE 0
     45 
     46 /**
     47  * Set to 1 for extra debug logging.
     48  */
     49 #define DEBUG 0
     50 
     51 /**
     52  * Current version for (local) JSON serialization of persisted
     53  * /keys data.
     54  */
     55 #define EXCHANGE_SERIALIZATION_FORMAT_VERSION 0
     56 
     57 /**
     58  * How far off do we allow key lifetimes to be?
     59  */
     60 #define LIFETIME_TOLERANCE GNUNET_TIME_UNIT_HOURS
     61 
     62 /**
     63  * Element in the `struct SignatureContext` array.
     64  */
     65 struct SignatureElement
     66 {
     67 
     68   /**
     69    * Offset of the denomination in the group array,
     70    * for sorting (2nd rank, ascending).
     71    */
     72   unsigned int offset;
     73 
     74   /**
     75    * Offset of the group in the denominations array,
     76    * for sorting (2nd rank, ascending).
     77    */
     78   unsigned int group_offset;
     79 
     80   /**
     81    * Pointer to actual master signature to hash over.
     82    */
     83   struct TALER_MasterSignatureP master_sig;
     84 };
     85 
     86 /**
     87  * Context for collecting the array of master signatures
     88  * needed to verify the exchange_sig online signature.
     89  */
     90 struct SignatureContext
     91 {
     92   /**
     93    * Array of signatures to hash over.
     94    */
     95   struct SignatureElement *elements;
     96 
     97   /**
     98    * Write offset in the @e elements array.
     99    */
    100   unsigned int elements_pos;
    101 
    102   /**
    103    * Allocated space for @e elements.
    104    */
    105   unsigned int elements_size;
    106 };
    107 
    108 
    109 /**
    110  * Determine order to sort two elements by before
    111  * we hash the master signatures.  Used for
    112  * sorting with qsort().
    113  *
    114  * @param a pointer to a `struct SignatureElement`
    115  * @param b pointer to a `struct SignatureElement`
    116  * @return 0 if equal, -1 if a < b, 1 if a > b.
    117  */
    118 static int
    119 signature_context_sort_cb (const void *a,
    120                            const void *b)
    121 {
    122   const struct SignatureElement *sa = a;
    123   const struct SignatureElement *sb = b;
    124 
    125   if (sa->group_offset < sb->group_offset)
    126     return -1;
    127   if (sa->group_offset > sb->group_offset)
    128     return 1;
    129   if (sa->offset < sb->offset)
    130     return -1;
    131   if (sa->offset > sb->offset)
    132     return 1;
    133   /* We should never have two disjoint elements
    134      with same time and offset */
    135   GNUNET_assert (sa == sb);
    136   return 0;
    137 }
    138 
    139 
    140 /**
    141  * Append a @a master_sig to the @a sig_ctx using the
    142  * given attributes for (later) sorting.
    143  *
    144  * @param[in,out] sig_ctx signature context to update
    145  * @param group_offset offset for the group
    146  * @param offset offset for the entry
    147  * @param master_sig master signature for the entry
    148  */
    149 static void
    150 append_signature (struct SignatureContext *sig_ctx,
    151                   unsigned int group_offset,
    152                   unsigned int offset,
    153                   const struct TALER_MasterSignatureP *master_sig)
    154 {
    155   struct SignatureElement *element;
    156   unsigned int new_size;
    157 
    158   if (sig_ctx->elements_pos == sig_ctx->elements_size)
    159   {
    160     if (0 == sig_ctx->elements_size)
    161       new_size = 1024;
    162     else
    163       new_size = sig_ctx->elements_size * 2;
    164     GNUNET_array_grow (sig_ctx->elements,
    165                        sig_ctx->elements_size,
    166                        new_size);
    167   }
    168   element = &sig_ctx->elements[sig_ctx->elements_pos++];
    169   element->offset = offset;
    170   element->group_offset = group_offset;
    171   element->master_sig = *master_sig;
    172 }
    173 
    174 
    175 /**
    176  * Frees @a wfm array.
    177  *
    178  * @param wfm fee array to release
    179  * @param wfm_len length of the @a wfm array
    180  */
    181 static void
    182 free_fees (struct TALER_EXCHANGE_WireFeesByMethod *wfm,
    183            unsigned int wfm_len)
    184 {
    185   for (unsigned int i = 0; i<wfm_len; i++)
    186   {
    187     struct TALER_EXCHANGE_WireFeesByMethod *wfmi = &wfm[i];
    188 
    189     while (NULL != wfmi->fees_head)
    190     {
    191       struct TALER_EXCHANGE_WireAggregateFees *fe
    192         = wfmi->fees_head;
    193 
    194       wfmi->fees_head = fe->next;
    195       GNUNET_free (fe);
    196     }
    197     GNUNET_free (wfmi->method);
    198   }
    199   GNUNET_free (wfm);
    200 }
    201 
    202 
    203 /**
    204  * Parse wire @a fees and return array.
    205  *
    206  * @param master_pub master public key to use to check signatures
    207  * @param currency currency amounts are expected in
    208  * @param fees json AggregateTransferFee to parse
    209  * @param[out] fees_len set to length of returned array
    210  * @return NULL on error
    211  */
    212 static struct TALER_EXCHANGE_WireFeesByMethod *
    213 parse_fees (const struct TALER_MasterPublicKeyP *master_pub,
    214             const char *currency,
    215             const json_t *fees,
    216             unsigned int *fees_len)
    217 {
    218   struct TALER_EXCHANGE_WireFeesByMethod *fbm;
    219   size_t fbml = json_object_size (fees);
    220   unsigned int i = 0;
    221   const char *key;
    222   const json_t *fee_array;
    223 
    224   if (UINT_MAX < fbml)
    225   {
    226     GNUNET_break (0);
    227     return NULL;
    228   }
    229   fbm = GNUNET_new_array (fbml,
    230                           struct TALER_EXCHANGE_WireFeesByMethod);
    231   *fees_len = (unsigned int) fbml;
    232   json_object_foreach ((json_t *) fees, key, fee_array) {
    233     struct TALER_EXCHANGE_WireFeesByMethod *fe = &fbm[i++];
    234     size_t idx;
    235     json_t *fee;
    236 
    237     fe->method = GNUNET_strdup (key);
    238     fe->fees_head = NULL;
    239     json_array_foreach (fee_array, idx, fee)
    240     {
    241       struct TALER_EXCHANGE_WireAggregateFees *wa
    242         = GNUNET_new (struct TALER_EXCHANGE_WireAggregateFees);
    243       struct GNUNET_JSON_Specification spec[] = {
    244         GNUNET_JSON_spec_fixed_auto ("sig",
    245                                      &wa->master_sig),
    246         TALER_JSON_spec_amount ("wire_fee",
    247                                 currency,
    248                                 &wa->fees.wire),
    249         TALER_JSON_spec_amount ("closing_fee",
    250                                 currency,
    251                                 &wa->fees.closing),
    252         GNUNET_JSON_spec_timestamp ("start_date",
    253                                     &wa->start_date),
    254         GNUNET_JSON_spec_timestamp ("end_date",
    255                                     &wa->end_date),
    256         GNUNET_JSON_spec_end ()
    257       };
    258 
    259       wa->next = fe->fees_head;
    260       fe->fees_head = wa;
    261       if (GNUNET_OK !=
    262           GNUNET_JSON_parse (fee,
    263                              spec,
    264                              NULL,
    265                              NULL))
    266       {
    267         GNUNET_break_op (0);
    268         free_fees (fbm,
    269                    i);
    270         return NULL;
    271       }
    272       if (GNUNET_OK !=
    273           TALER_exchange_offline_wire_fee_verify (
    274             key,
    275             wa->start_date,
    276             wa->end_date,
    277             &wa->fees,
    278             master_pub,
    279             &wa->master_sig))
    280       {
    281         GNUNET_break_op (0);
    282         free_fees (fbm,
    283                    i);
    284         return NULL;
    285       }
    286     } /* for all fees over time */
    287   } /* for all methods */
    288   GNUNET_assert (i == fbml);
    289   return fbm;
    290 }
    291 
    292 
    293 void
    294 TALER_EXCHANGE_get_auditors_for_dc_ (
    295   struct TALER_EXCHANGE_Keys *keys,
    296   TEAH_AuditorCallback ac,
    297   void *ac_cls)
    298 {
    299   if (0 == keys->num_auditors)
    300   {
    301     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    302                 "No auditor available. Not submitting deposit confirmations.\n")
    303     ;
    304     return;
    305   }
    306   for (unsigned int i = 0; i<keys->num_auditors; i++)
    307   {
    308     const struct TALER_EXCHANGE_AuditorInformation *auditor
    309       = &keys->auditors[i];
    310 
    311     ac (ac_cls,
    312         auditor->auditor_url,
    313         &auditor->auditor_pub);
    314   }
    315 }
    316 
    317 
    318 #define EXITIF(cond)                                              \
    319         do {                                                            \
    320           if (cond) { GNUNET_break (0); goto EXITIF_exit; }             \
    321         } while (0)
    322 
    323 
    324 /**
    325  * Parse a exchange's signing key encoded in JSON.
    326  *
    327  * @param[out] sign_key where to return the result
    328  * @param check_sigs should we check signatures?
    329  * @param sign_key_obj json to parse
    330  * @param master_key master key to use to verify signature
    331  * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
    332  *        invalid or the @a sign_key_obj is malformed.
    333  */
    334 static enum GNUNET_GenericReturnValue
    335 parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key,
    336                     bool check_sigs,
    337                     const json_t *sign_key_obj,
    338                     const struct TALER_MasterPublicKeyP *master_key)
    339 {
    340   struct GNUNET_JSON_Specification spec[] = {
    341     GNUNET_JSON_spec_fixed_auto ("master_sig",
    342                                  &sign_key->master_sig),
    343     GNUNET_JSON_spec_fixed_auto ("key",
    344                                  &sign_key->key),
    345     GNUNET_JSON_spec_timestamp ("stamp_start",
    346                                 &sign_key->valid_from),
    347     GNUNET_JSON_spec_timestamp ("stamp_expire",
    348                                 &sign_key->valid_until),
    349     GNUNET_JSON_spec_timestamp ("stamp_end",
    350                                 &sign_key->valid_legal),
    351     GNUNET_JSON_spec_end ()
    352   };
    353 
    354   if (GNUNET_OK !=
    355       GNUNET_JSON_parse (sign_key_obj,
    356                          spec,
    357                          NULL, NULL))
    358   {
    359     GNUNET_break_op (0);
    360     return GNUNET_SYSERR;
    361   }
    362   if (! check_sigs)
    363     return GNUNET_OK;
    364   if (GNUNET_OK !=
    365       TALER_exchange_offline_signkey_validity_verify (
    366         &sign_key->key,
    367         sign_key->valid_from,
    368         sign_key->valid_until,
    369         sign_key->valid_legal,
    370         master_key,
    371         &sign_key->master_sig))
    372   {
    373     GNUNET_break_op (0);
    374     return GNUNET_SYSERR;
    375   }
    376   return GNUNET_OK;
    377 }
    378 
    379 
    380 /**
    381  * Parse a exchange's denomination key encoded in JSON partially.
    382  *
    383  * Only the values for master_sig, timestamps and the cipher-specific public
    384  * key are parsed.  All other fields (fees, age_mask, value) MUST have been set
    385  * prior to calling this function, otherwise the signature verification
    386  * performed within this function will fail.
    387  *
    388  * @param[out] denom_key where to return the result
    389  * @param cipher cipher type to parse
    390  * @param check_sigs should we check signatures?
    391  * @param denom_key_obj json to parse
    392  * @param master_key master key to use to verify signature
    393  * @param group_offset offset for the group
    394  * @param index index of this denomination key in the group
    395  * @param sig_ctx where to write details about encountered
    396  *        master signatures, NULL if not used
    397  * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
    398  *        invalid or the json malformed.
    399  */
    400 static enum GNUNET_GenericReturnValue
    401 parse_json_denomkey_partially (
    402   struct TALER_EXCHANGE_DenomPublicKey *denom_key,
    403   enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher,
    404   bool check_sigs,
    405   const json_t *denom_key_obj,
    406   struct TALER_MasterPublicKeyP *master_key,
    407   unsigned int group_offset,
    408   unsigned int index,
    409   struct SignatureContext *sig_ctx)
    410 {
    411   struct GNUNET_JSON_Specification spec[] = {
    412     GNUNET_JSON_spec_fixed_auto ("master_sig",
    413                                  &denom_key->master_sig),
    414     GNUNET_JSON_spec_timestamp ("stamp_expire_deposit",
    415                                 &denom_key->expire_deposit),
    416     GNUNET_JSON_spec_timestamp ("stamp_expire_withdraw",
    417                                 &denom_key->withdraw_valid_until),
    418     GNUNET_JSON_spec_timestamp ("stamp_start",
    419                                 &denom_key->valid_from),
    420     GNUNET_JSON_spec_timestamp ("stamp_expire_legal",
    421                                 &denom_key->expire_legal),
    422     GNUNET_JSON_spec_mark_optional (
    423       GNUNET_JSON_spec_bool ("lost",
    424                              &denom_key->lost),
    425       NULL),
    426     TALER_JSON_spec_denom_pub_cipher (NULL,
    427                                       cipher,
    428                                       &denom_key->key),
    429     GNUNET_JSON_spec_end ()
    430   };
    431 
    432   if (GNUNET_OK !=
    433       GNUNET_JSON_parse (denom_key_obj,
    434                          spec,
    435                          NULL, NULL))
    436   {
    437     GNUNET_break_op (0);
    438     return GNUNET_SYSERR;
    439   }
    440   TALER_denom_pub_hash (&denom_key->key,
    441                         &denom_key->h_key);
    442   if (NULL != sig_ctx)
    443     append_signature (sig_ctx,
    444                       group_offset,
    445                       index,
    446                       &denom_key->master_sig);
    447   if (! check_sigs)
    448     return GNUNET_OK;
    449   EXITIF (GNUNET_SYSERR ==
    450           TALER_exchange_offline_denom_validity_verify (
    451             &denom_key->h_key,
    452             denom_key->valid_from,
    453             denom_key->withdraw_valid_until,
    454             denom_key->expire_deposit,
    455             denom_key->expire_legal,
    456             &denom_key->value,
    457             &denom_key->fees,
    458             master_key,
    459             &denom_key->master_sig));
    460   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    461               "Learned denomination key %s\n",
    462               GNUNET_h2s (&denom_key->h_key.hash));
    463   return GNUNET_OK;
    464 EXITIF_exit:
    465   GNUNET_JSON_parse_free (spec);
    466   /* invalidate denom_key, just to be sure */
    467   memset (denom_key,
    468           0,
    469           sizeof (*denom_key));
    470   return GNUNET_SYSERR;
    471 }
    472 
    473 
    474 /**
    475  * Parse a exchange's auditor information encoded in JSON.
    476  *
    477  * @param[out] auditor where to return the result
    478  * @param check_sigs should we check signatures
    479  * @param auditor_obj json to parse
    480  * @param key_data information about denomination keys
    481  * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
    482  *        invalid or the json malformed.
    483  */
    484 static enum GNUNET_GenericReturnValue
    485 parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,
    486                     bool check_sigs,
    487                     const json_t *auditor_obj,
    488                     const struct TALER_EXCHANGE_Keys *key_data)
    489 {
    490   const json_t *keys;
    491   json_t *key;
    492   size_t off;
    493   size_t pos;
    494   const char *auditor_url;
    495   const char *auditor_name;
    496   struct GNUNET_JSON_Specification spec[] = {
    497     GNUNET_JSON_spec_fixed_auto ("auditor_pub",
    498                                  &auditor->auditor_pub),
    499     TALER_JSON_spec_web_url ("auditor_url",
    500                              &auditor_url),
    501     GNUNET_JSON_spec_string ("auditor_name",
    502                              &auditor_name),
    503     GNUNET_JSON_spec_array_const ("denomination_keys",
    504                                   &keys),
    505     GNUNET_JSON_spec_end ()
    506   };
    507 
    508   if (GNUNET_OK !=
    509       GNUNET_JSON_parse (auditor_obj,
    510                          spec,
    511                          NULL, NULL))
    512   {
    513     GNUNET_break_op (0);
    514 #if DEBUG
    515     json_dumpf (auditor_obj,
    516                 stderr,
    517                 JSON_INDENT (2));
    518 #endif
    519     return GNUNET_SYSERR;
    520   }
    521   auditor->auditor_url = GNUNET_strdup (auditor_url);
    522   auditor->auditor_name = GNUNET_strdup (auditor_name);
    523   auditor->denom_keys
    524     = GNUNET_new_array (json_array_size (keys),
    525                         struct TALER_EXCHANGE_AuditorDenominationInfo);
    526   pos = 0;
    527   json_array_foreach (keys, off, key) {
    528     struct TALER_AuditorSignatureP auditor_sig;
    529     struct TALER_DenominationHashP denom_h;
    530     const struct TALER_EXCHANGE_DenomPublicKey *dk = NULL;
    531     unsigned int dk_off = UINT_MAX;
    532     struct GNUNET_JSON_Specification kspec[] = {
    533       GNUNET_JSON_spec_fixed_auto ("auditor_sig",
    534                                    &auditor_sig),
    535       GNUNET_JSON_spec_fixed_auto ("denom_pub_h",
    536                                    &denom_h),
    537       GNUNET_JSON_spec_end ()
    538     };
    539 
    540     if (GNUNET_OK !=
    541         GNUNET_JSON_parse (key,
    542                            kspec,
    543                            NULL, NULL))
    544     {
    545       GNUNET_break_op (0);
    546       continue;
    547     }
    548     for (unsigned int j = 0; j<key_data->num_denom_keys; j++)
    549     {
    550       if (0 == GNUNET_memcmp (&denom_h,
    551                               &key_data->denom_keys[j].h_key))
    552       {
    553         dk = &key_data->denom_keys[j];
    554         dk_off = j;
    555         break;
    556       }
    557     }
    558     if (NULL == dk)
    559     {
    560       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    561                   "Auditor signed denomination %s, which we do not know. Ignoring signature.\n",
    562                   GNUNET_h2s (&denom_h.hash));
    563       continue;
    564     }
    565     if (check_sigs)
    566     {
    567       if (GNUNET_OK !=
    568           TALER_auditor_denom_validity_verify (
    569             auditor_url,
    570             &dk->h_key,
    571             &key_data->master_pub,
    572             dk->valid_from,
    573             dk->withdraw_valid_until,
    574             dk->expire_deposit,
    575             dk->expire_legal,
    576             &dk->value,
    577             &dk->fees,
    578             &auditor->auditor_pub,
    579             &auditor_sig))
    580       {
    581         GNUNET_break_op (0);
    582         return GNUNET_SYSERR;
    583       }
    584     }
    585     auditor->denom_keys[pos].denom_key_offset = dk_off;
    586     auditor->denom_keys[pos].auditor_sig = auditor_sig;
    587     pos++;
    588   }
    589   if (pos > UINT_MAX)
    590   {
    591     GNUNET_break (0);
    592     return GNUNET_SYSERR;
    593   }
    594   auditor->num_denom_keys = (unsigned int) pos;
    595   return GNUNET_OK;
    596 }
    597 
    598 
    599 /**
    600  * Parse a exchange's global fee information encoded in JSON.
    601  *
    602  * @param[out] gf where to return the result
    603  * @param check_sigs should we check signatures
    604  * @param fee_obj json to parse
    605  * @param key_data already parsed information about the exchange
    606  * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
    607  *        invalid or the json malformed.
    608  */
    609 static enum GNUNET_GenericReturnValue
    610 parse_global_fee (struct TALER_EXCHANGE_GlobalFee *gf,
    611                   bool check_sigs,
    612                   const json_t *fee_obj,
    613                   const struct TALER_EXCHANGE_Keys *key_data)
    614 {
    615   struct GNUNET_JSON_Specification spec[] = {
    616     GNUNET_JSON_spec_timestamp ("start_date",
    617                                 &gf->start_date),
    618     GNUNET_JSON_spec_timestamp ("end_date",
    619                                 &gf->end_date),
    620     GNUNET_JSON_spec_relative_time ("purse_timeout",
    621                                     &gf->purse_timeout),
    622     GNUNET_JSON_spec_relative_time ("history_expiration",
    623                                     &gf->history_expiration),
    624     GNUNET_JSON_spec_uint32 ("purse_account_limit",
    625                              &gf->purse_account_limit),
    626     TALER_JSON_SPEC_GLOBAL_FEES (key_data->currency,
    627                                  &gf->fees),
    628     GNUNET_JSON_spec_fixed_auto ("master_sig",
    629                                  &gf->master_sig),
    630     GNUNET_JSON_spec_end ()
    631   };
    632 
    633   if (GNUNET_OK !=
    634       GNUNET_JSON_parse (fee_obj,
    635                          spec,
    636                          NULL, NULL))
    637   {
    638     GNUNET_break_op (0);
    639 #if DEBUG
    640     json_dumpf (fee_obj,
    641                 stderr,
    642                 JSON_INDENT (2));
    643 #endif
    644     return GNUNET_SYSERR;
    645   }
    646   if (check_sigs)
    647   {
    648     if (GNUNET_OK !=
    649         TALER_exchange_offline_global_fee_verify (
    650           gf->start_date,
    651           gf->end_date,
    652           &gf->fees,
    653           gf->purse_timeout,
    654           gf->history_expiration,
    655           gf->purse_account_limit,
    656           &key_data->master_pub,
    657           &gf->master_sig))
    658     {
    659       GNUNET_break_op (0);
    660       GNUNET_JSON_parse_free (spec);
    661       return GNUNET_SYSERR;
    662     }
    663   }
    664   GNUNET_JSON_parse_free (spec);
    665   return GNUNET_OK;
    666 }
    667 
    668 
    669 /**
    670  * Compare two denomination keys.  Ignores revocation data.
    671  *
    672  * @param denom1 first denomination key
    673  * @param denom2 second denomination key
    674  * @return 0 if the two keys are equal (not necessarily
    675  *  the same object), non-zero otherwise.
    676  */
    677 static unsigned int
    678 denoms_cmp (const struct TALER_EXCHANGE_DenomPublicKey *denom1,
    679             const struct TALER_EXCHANGE_DenomPublicKey *denom2)
    680 {
    681   struct TALER_EXCHANGE_DenomPublicKey tmp1;
    682   struct TALER_EXCHANGE_DenomPublicKey tmp2;
    683 
    684   if (0 !=
    685       TALER_denom_pub_cmp (&denom1->key,
    686                            &denom2->key))
    687     return 1;
    688   tmp1 = *denom1;
    689   tmp2 = *denom2;
    690   tmp1.revoked = false;
    691   tmp2.revoked = false;
    692   memset (&tmp1.key,
    693           0,
    694           sizeof (tmp1.key));
    695   memset (&tmp2.key,
    696           0,
    697           sizeof (tmp2.key));
    698   return GNUNET_memcmp (&tmp1,
    699                         &tmp2);
    700 }
    701 
    702 
    703 /**
    704  * Decode the JSON array in @a hard_limits from the /keys response
    705  * and store the data in `hard_limits` array the @a key_data.
    706  *
    707  * @param[in] hard_limits JSON array to parse
    708  * @param[out] key_data where to store the results we decoded
    709  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
    710  * (malformed JSON)
    711  */
    712 static enum GNUNET_GenericReturnValue
    713 parse_hard_limits (const json_t *hard_limits,
    714                    struct TALER_EXCHANGE_Keys *key_data)
    715 {
    716   json_t *obj;
    717   size_t off;
    718 
    719   key_data->hard_limits_length
    720     = (unsigned int) json_array_size (hard_limits);
    721   if ( ((size_t) key_data->hard_limits_length)
    722        != json_array_size (hard_limits))
    723   {
    724     GNUNET_break (0);
    725     return GNUNET_SYSERR;
    726   }
    727   key_data->hard_limits
    728     = GNUNET_new_array (key_data->hard_limits_length,
    729                         struct TALER_EXCHANGE_AccountLimit);
    730 
    731   json_array_foreach (hard_limits, off, obj)
    732   {
    733     struct TALER_EXCHANGE_AccountLimit *al
    734       = &key_data->hard_limits[off];
    735     struct GNUNET_JSON_Specification spec[] = {
    736       TALER_JSON_spec_kycte ("operation_type",
    737                              &al->operation_type),
    738       TALER_JSON_spec_amount_any ("threshold",
    739                                   &al->threshold),
    740       GNUNET_JSON_spec_relative_time ("timeframe",
    741                                       &al->timeframe),
    742       GNUNET_JSON_spec_mark_optional (
    743         GNUNET_JSON_spec_bool ("soft_limit",
    744                                &al->soft_limit),
    745         NULL),
    746       GNUNET_JSON_spec_end ()
    747     };
    748 
    749     if (GNUNET_OK !=
    750         GNUNET_JSON_parse (obj,
    751                            spec,
    752                            NULL, NULL))
    753     {
    754       GNUNET_break_op (0);
    755       return GNUNET_SYSERR;
    756     }
    757   }
    758   return GNUNET_OK;
    759 }
    760 
    761 
    762 /**
    763  * Decode the JSON array in @a zero_limits from the /keys response
    764  * and store the data in `zero_limits` array the @a key_data.
    765  *
    766  * @param[in] zero_limits JSON array to parse
    767  * @param[out] key_data where to store the results we decoded
    768  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
    769  * (malformed JSON)
    770  */
    771 static enum GNUNET_GenericReturnValue
    772 parse_zero_limits (const json_t *zero_limits,
    773                    struct TALER_EXCHANGE_Keys *key_data)
    774 {
    775   json_t *obj;
    776   size_t off;
    777 
    778   key_data->zero_limits_length
    779     = (unsigned int) json_array_size (zero_limits);
    780   if ( ((size_t) key_data->zero_limits_length)
    781        != json_array_size (zero_limits))
    782   {
    783     GNUNET_break (0);
    784     return GNUNET_SYSERR;
    785   }
    786   key_data->zero_limits
    787     = GNUNET_new_array (key_data->zero_limits_length,
    788                         struct TALER_EXCHANGE_ZeroLimitedOperation);
    789 
    790   json_array_foreach (zero_limits, off, obj)
    791   {
    792     struct TALER_EXCHANGE_ZeroLimitedOperation *zol
    793       = &key_data->zero_limits[off];
    794     struct GNUNET_JSON_Specification spec[] = {
    795       TALER_JSON_spec_kycte ("operation_type",
    796                              &zol->operation_type),
    797       GNUNET_JSON_spec_end ()
    798     };
    799 
    800     if (GNUNET_OK !=
    801         GNUNET_JSON_parse (obj,
    802                            spec,
    803                            NULL, NULL))
    804     {
    805       GNUNET_break_op (0);
    806       return GNUNET_SYSERR;
    807     }
    808   }
    809   return GNUNET_OK;
    810 }
    811 
    812 
    813 /**
    814  * Parse the wads (partner exchange) array from /keys and store the
    815  * data in @a key_data.
    816  *
    817  * @param[in] wads_array JSON array to parse
    818  * @param check_sig true if we should verify signatures
    819  * @param[out] key_data where to store the results
    820  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
    821  */
    822 static enum GNUNET_GenericReturnValue
    823 parse_wads (const json_t *wads_array,
    824             bool check_sig,
    825             struct TALER_EXCHANGE_Keys *key_data)
    826 {
    827   size_t n = json_array_size (wads_array);
    828   json_t *wad_obj;
    829   size_t index;
    830 
    831   if (n > UINT_MAX)
    832   {
    833     GNUNET_break (0);
    834     return GNUNET_SYSERR;
    835   }
    836   if (0 == n)
    837     return GNUNET_OK;
    838   key_data->num_wad_partners = (unsigned int) n;
    839   key_data->wad_partners
    840     = GNUNET_new_array (n,
    841                         struct TALER_EXCHANGE_WadPartner);
    842   json_array_foreach (wads_array, index, wad_obj)
    843   {
    844     struct TALER_EXCHANGE_WadPartner *wp
    845       = &key_data->wad_partners[index];
    846     const char *partner_base_url;
    847     struct GNUNET_JSON_Specification spec[] = {
    848       TALER_JSON_spec_web_url ("partner_base_url",
    849                                &partner_base_url),
    850       GNUNET_JSON_spec_fixed_auto ("partner_master_pub",
    851                                    &wp->partner_master_pub),
    852       TALER_JSON_spec_amount ("wad_fee",
    853                               key_data->currency,
    854                               &wp->wad_fee),
    855       GNUNET_JSON_spec_relative_time ("wad_frequency",
    856                                       &wp->wad_frequency),
    857       GNUNET_JSON_spec_timestamp ("start_date",
    858                                   &wp->start_date),
    859       GNUNET_JSON_spec_timestamp ("end_date",
    860                                   &wp->end_date),
    861       GNUNET_JSON_spec_fixed_auto ("master_sig",
    862                                    &wp->master_sig),
    863       GNUNET_JSON_spec_end ()
    864     };
    865 
    866     if (GNUNET_OK !=
    867         GNUNET_JSON_parse (wad_obj,
    868                            spec,
    869                            NULL, NULL))
    870     {
    871       GNUNET_break_op (0);
    872       return GNUNET_SYSERR;
    873     }
    874     wp->partner_base_url = GNUNET_strdup (partner_base_url);
    875     if (check_sig &&
    876         GNUNET_OK !=
    877         TALER_exchange_offline_partner_details_verify (
    878           &wp->partner_master_pub,
    879           wp->start_date,
    880           wp->end_date,
    881           wp->wad_frequency,
    882           &wp->wad_fee,
    883           partner_base_url,
    884           &key_data->master_pub,
    885           &wp->master_sig))
    886     {
    887       GNUNET_break_op (0);
    888       return GNUNET_SYSERR;
    889     }
    890   }
    891   return GNUNET_OK;
    892 }
    893 
    894 
    895 /**
    896  * Decode the JSON in @a resp_obj from the /keys response
    897  * and store the data in the @a key_data.
    898  *
    899  * @param[in] resp_obj JSON object to parse
    900  * @param check_sig true if we should check the signature
    901  * @param[out] key_data where to store the results we decoded
    902  * @param[out] vc where to store version compatibility data
    903  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
    904  * (malformed JSON)
    905  */
    906 enum GNUNET_GenericReturnValue
    907 TALER_EXCHANGE_decode_keys_json_ (
    908   const json_t *resp_obj,
    909   bool check_sig,
    910   struct TALER_EXCHANGE_Keys *key_data,
    911   enum TALER_EXCHANGE_VersionCompatibility *vc)
    912 {
    913   struct TALER_ExchangeSignatureP exchange_sig;
    914   struct TALER_ExchangePublicKeyP exchange_pub;
    915   const json_t *wblwk = NULL;
    916   const json_t *global_fees;
    917   const json_t *sign_keys_array;
    918   const json_t *denominations_by_group;
    919   const json_t *auditors_array;
    920   const json_t *recoup_array = NULL;
    921   const json_t *manifests = NULL;
    922   bool no_extensions = false;
    923   bool no_signature = false;
    924   const json_t *accounts;
    925   const json_t *fees;
    926   const json_t *wads;
    927   const char *shopping_url = NULL;
    928   const char *bank_compliance_language = NULL;
    929   struct SignatureContext sig_ctx = { 0 };
    930 
    931   if (JSON_OBJECT != json_typeof (resp_obj))
    932   {
    933     GNUNET_break_op (0);
    934     return GNUNET_SYSERR;
    935   }
    936 #if DEBUG
    937   json_dumpf (resp_obj,
    938               stderr,
    939               JSON_INDENT (2));
    940 #endif
    941   /* check the version first */
    942   {
    943     struct TALER_JSON_ProtocolVersion pv;
    944     struct GNUNET_JSON_Specification spec[] = {
    945       TALER_JSON_spec_version ("version",
    946                                &pv),
    947       GNUNET_JSON_spec_end ()
    948     };
    949 
    950     if (GNUNET_OK !=
    951         GNUNET_JSON_parse (resp_obj,
    952                            spec,
    953                            NULL, NULL))
    954     {
    955       GNUNET_break_op (0);
    956       return GNUNET_SYSERR;
    957     }
    958     *vc = TALER_EXCHANGE_VC_MATCH;
    959     if (EXCHANGE_PROTOCOL_CURRENT < pv.current)
    960     {
    961       *vc |= TALER_EXCHANGE_VC_NEWER;
    962       if (EXCHANGE_PROTOCOL_CURRENT < pv.current - pv.age)
    963         *vc |= TALER_EXCHANGE_VC_INCOMPATIBLE;
    964     }
    965     if (EXCHANGE_PROTOCOL_CURRENT > pv.current)
    966     {
    967       *vc |= TALER_EXCHANGE_VC_OLDER;
    968       if (EXCHANGE_PROTOCOL_CURRENT - EXCHANGE_PROTOCOL_AGE > pv.current)
    969         *vc |= TALER_EXCHANGE_VC_INCOMPATIBLE;
    970     }
    971   }
    972 
    973   {
    974     const char *ver;
    975     const char *currency;
    976     const char *asset_type;
    977     struct GNUNET_JSON_Specification mspec[] = {
    978       GNUNET_JSON_spec_fixed_auto (
    979         "exchange_sig",
    980         &exchange_sig),
    981       GNUNET_JSON_spec_fixed_auto (
    982         "exchange_pub",
    983         &exchange_pub),
    984       GNUNET_JSON_spec_fixed_auto (
    985         "master_public_key",
    986         &key_data->master_pub),
    987       GNUNET_JSON_spec_array_const ("accounts",
    988                                     &accounts),
    989       GNUNET_JSON_spec_object_const ("wire_fees",
    990                                      &fees),
    991       GNUNET_JSON_spec_array_const ("wads",
    992                                     &wads),
    993       GNUNET_JSON_spec_timestamp (
    994         "list_issue_date",
    995         &key_data->list_issue_date),
    996       GNUNET_JSON_spec_relative_time (
    997         "reserve_closing_delay",
    998         &key_data->reserve_closing_delay),
    999       GNUNET_JSON_spec_string (
   1000         "currency",
   1001         &currency),
   1002       GNUNET_JSON_spec_string (
   1003         "asset_type",
   1004         &asset_type),
   1005       GNUNET_JSON_spec_array_const (
   1006         "global_fees",
   1007         &global_fees),
   1008       GNUNET_JSON_spec_array_const (
   1009         "signkeys",
   1010         &sign_keys_array),
   1011       GNUNET_JSON_spec_array_const (
   1012         "denominations",
   1013         &denominations_by_group),
   1014       GNUNET_JSON_spec_mark_optional (
   1015         GNUNET_JSON_spec_array_const (
   1016           "recoup",
   1017           &recoup_array),
   1018         NULL),
   1019       GNUNET_JSON_spec_array_const (
   1020         "auditors",
   1021         &auditors_array),
   1022       GNUNET_JSON_spec_bool (
   1023         "kyc_enabled",
   1024         &key_data->kyc_enabled),
   1025       GNUNET_JSON_spec_mark_optional (
   1026         GNUNET_JSON_spec_object_const ("extensions",
   1027                                        &manifests),
   1028         &no_extensions),
   1029       GNUNET_JSON_spec_mark_optional (
   1030         GNUNET_JSON_spec_fixed_auto (
   1031           "extensions_sig",
   1032           &key_data->extensions_sig),
   1033         &no_signature),
   1034       GNUNET_JSON_spec_string ("version",
   1035                                &ver),
   1036       GNUNET_JSON_spec_mark_optional (
   1037         GNUNET_JSON_spec_array_const (
   1038           "wallet_balance_limit_without_kyc",
   1039           &wblwk),
   1040         NULL),
   1041       GNUNET_JSON_spec_mark_optional (
   1042         GNUNET_JSON_spec_string ("shopping_url",
   1043                                  &shopping_url),
   1044         NULL),
   1045       GNUNET_JSON_spec_mark_optional (
   1046         GNUNET_JSON_spec_string ("bank_compliance_language",
   1047                                  &bank_compliance_language),
   1048         NULL),
   1049       GNUNET_JSON_spec_mark_optional (
   1050         GNUNET_JSON_spec_bool ("disable_direct_deposit",
   1051                                &key_data->disable_direct_deposit),
   1052         NULL),
   1053       GNUNET_JSON_spec_end ()
   1054     };
   1055     const char *emsg;
   1056     unsigned int eline;
   1057 
   1058     if (GNUNET_OK !=
   1059         GNUNET_JSON_parse (resp_obj,
   1060                            (check_sig) ? mspec : &mspec[2],
   1061                            &emsg,
   1062                            &eline))
   1063     {
   1064       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1065                   "Parsing /keys failed for `%s' (%u)\n",
   1066                   emsg,
   1067                   eline);
   1068       EXITIF (1);
   1069     }
   1070     {
   1071       const json_t *hard_limits = NULL;
   1072       const json_t *zero_limits = NULL;
   1073       bool no_tiny_amount = false;
   1074       struct GNUNET_JSON_Specification sspec[] = {
   1075         TALER_JSON_spec_currency_specification (
   1076           "currency_specification",
   1077           currency,
   1078           &key_data->cspec),
   1079         TALER_JSON_spec_amount (
   1080           "stefan_abs",
   1081           currency,
   1082           &key_data->stefan_abs),
   1083         TALER_JSON_spec_amount (
   1084           "stefan_log",
   1085           currency,
   1086           &key_data->stefan_log),
   1087         GNUNET_JSON_spec_mark_optional (
   1088           TALER_JSON_spec_amount (
   1089             "tiny_amount",
   1090             currency,
   1091             &key_data->tiny_amount),
   1092           &no_tiny_amount),
   1093         GNUNET_JSON_spec_mark_optional (
   1094           GNUNET_JSON_spec_array_const (
   1095             "hard_limits",
   1096             &hard_limits),
   1097           NULL),
   1098         GNUNET_JSON_spec_mark_optional (
   1099           GNUNET_JSON_spec_array_const (
   1100             "zero_limits",
   1101             &zero_limits),
   1102           NULL),
   1103         GNUNET_JSON_spec_double (
   1104           "stefan_lin",
   1105           &key_data->stefan_lin),
   1106         GNUNET_JSON_spec_end ()
   1107       };
   1108 
   1109       if (GNUNET_OK !=
   1110           GNUNET_JSON_parse (resp_obj,
   1111                              sspec,
   1112                              &emsg,
   1113                              &eline))
   1114       {
   1115         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1116                     "Parsing /keys failed for `%s' (%u)\n",
   1117                     emsg,
   1118                     eline);
   1119         EXITIF (1);
   1120       }
   1121       if ( (NULL != hard_limits) &&
   1122            (GNUNET_OK !=
   1123             parse_hard_limits (hard_limits,
   1124                                key_data)) )
   1125       {
   1126         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1127                     "Parsing hard limits of /keys failed\n");
   1128         EXITIF (1);
   1129       }
   1130       if ( (NULL != zero_limits) &&
   1131            (GNUNET_OK !=
   1132             parse_zero_limits (zero_limits,
   1133                                key_data)) )
   1134       {
   1135         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1136                     "Parsing hard limits of /keys failed\n");
   1137         EXITIF (1);
   1138       }
   1139       key_data->tiny_amount_available = ! no_tiny_amount;
   1140     }
   1141 
   1142     key_data->currency = GNUNET_strdup (currency);
   1143     key_data->version = GNUNET_strdup (ver);
   1144     key_data->asset_type = GNUNET_strdup (asset_type);
   1145     if (NULL != shopping_url)
   1146       key_data->shopping_url = GNUNET_strdup (shopping_url);
   1147     if (NULL != bank_compliance_language)
   1148       key_data->bank_compliance_language
   1149         = GNUNET_strdup (bank_compliance_language);
   1150     if (! no_extensions)
   1151       key_data->extensions = json_incref ((json_t *) manifests);
   1152   }
   1153 
   1154   /* parse the global fees */
   1155   EXITIF (json_array_size (global_fees) > UINT_MAX);
   1156   key_data->num_global_fees
   1157     = (unsigned int) json_array_size (global_fees);
   1158   if (0 != key_data->num_global_fees)
   1159   {
   1160     json_t *global_fee;
   1161     size_t index;
   1162 
   1163     key_data->global_fees
   1164       = GNUNET_new_array (key_data->num_global_fees,
   1165                           struct TALER_EXCHANGE_GlobalFee);
   1166     json_array_foreach (global_fees, index, global_fee)
   1167     {
   1168       EXITIF (GNUNET_SYSERR ==
   1169               parse_global_fee (&key_data->global_fees[index],
   1170                                 check_sig,
   1171                                 global_fee,
   1172                                 key_data));
   1173     }
   1174   }
   1175 
   1176   /* parse the signing keys */
   1177   EXITIF (json_array_size (sign_keys_array) > UINT_MAX);
   1178   key_data->num_sign_keys
   1179     = (unsigned int) json_array_size (sign_keys_array);
   1180   if (0 != key_data->num_sign_keys)
   1181   {
   1182     json_t *sign_key_obj;
   1183     size_t index;
   1184 
   1185     key_data->sign_keys
   1186       = GNUNET_new_array (key_data->num_sign_keys,
   1187                           struct TALER_EXCHANGE_SigningPublicKey);
   1188     json_array_foreach (sign_keys_array, index, sign_key_obj) {
   1189       EXITIF (GNUNET_SYSERR ==
   1190               parse_json_signkey (&key_data->sign_keys[index],
   1191                                   check_sig,
   1192                                   sign_key_obj,
   1193                                   &key_data->master_pub));
   1194     }
   1195   }
   1196 
   1197   /* Parse balance limits */
   1198   if (NULL != wblwk)
   1199   {
   1200     EXITIF (json_array_size (wblwk) > UINT_MAX);
   1201     key_data->wblwk_length
   1202       = (unsigned int) json_array_size (wblwk);
   1203     key_data->wallet_balance_limit_without_kyc
   1204       = GNUNET_new_array (key_data->wblwk_length,
   1205                           struct TALER_Amount);
   1206     for (unsigned int i = 0; i<key_data->wblwk_length; i++)
   1207     {
   1208       struct TALER_Amount *a = &key_data->wallet_balance_limit_without_kyc[i];
   1209       const json_t *aj = json_array_get (wblwk,
   1210                                          i);
   1211       struct GNUNET_JSON_Specification spec[] = {
   1212         TALER_JSON_spec_amount (NULL,
   1213                                 key_data->currency,
   1214                                 a),
   1215         GNUNET_JSON_spec_end ()
   1216       };
   1217 
   1218       EXITIF (GNUNET_OK !=
   1219               GNUNET_JSON_parse (aj,
   1220                                  spec,
   1221                                  NULL, NULL));
   1222     }
   1223   }
   1224 
   1225   /* Parse wire accounts */
   1226   key_data->fees = parse_fees (&key_data->master_pub,
   1227                                key_data->currency,
   1228                                fees,
   1229                                &key_data->fees_len);
   1230   EXITIF (NULL == key_data->fees);
   1231   /* parse accounts */
   1232   EXITIF (json_array_size (accounts) > UINT_MAX);
   1233   GNUNET_array_grow (key_data->accounts,
   1234                      key_data->accounts_len,
   1235                      json_array_size (accounts));
   1236   EXITIF (GNUNET_OK !=
   1237           TALER_EXCHANGE_parse_accounts (&key_data->master_pub,
   1238                                          accounts,
   1239                                          key_data->accounts_len,
   1240                                          key_data->accounts));
   1241 
   1242   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1243               "Parsed %u wire accounts from JSON\n",
   1244               key_data->accounts_len);
   1245 
   1246   /* Parse wad partners */
   1247   EXITIF (GNUNET_OK !=
   1248           parse_wads (wads,
   1249                       check_sig,
   1250                       key_data));
   1251 
   1252 
   1253   /* Parse the supported extension(s): age-restriction. */
   1254   /* FIXME[Oec]: maybe lift all this into a FP in TALER_Extension ? */
   1255   if (! no_extensions)
   1256   {
   1257     if (no_signature)
   1258     {
   1259       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1260                   "found extensions without signature\n");
   1261     }
   1262     else
   1263     {
   1264       /* We have an extensions object. Verify its signature. */
   1265       EXITIF (GNUNET_OK !=
   1266               TALER_extensions_verify_manifests_signature (
   1267                 manifests,
   1268                 &key_data->extensions_sig,
   1269                 &key_data->master_pub));
   1270 
   1271       /* Parse and set the the configuration of the extensions accordingly */
   1272       EXITIF (GNUNET_OK !=
   1273               TALER_extensions_load_manifests (manifests));
   1274     }
   1275 
   1276     /* Assuming we might have now a new value for age_mask, set it in key_data */
   1277     key_data->age_mask = TALER_extensions_get_age_restriction_mask ();
   1278   }
   1279 
   1280   /*
   1281    * Parse the denomination keys, merging with the
   1282    * possibly EXISTING array as required (/keys cherry picking).
   1283    *
   1284    * The denominations are grouped by common values of
   1285    *    {cipher, value, fee, age_mask}.
   1286    */
   1287   {
   1288     json_t *group_obj;
   1289     unsigned int group_idx;
   1290 
   1291     json_array_foreach (denominations_by_group,
   1292                         group_idx,
   1293                         group_obj)
   1294     {
   1295       /* First, parse { cipher, fees, value, age_mask, hash } of the current
   1296          group. */
   1297       struct TALER_DenominationGroup group = {0};
   1298       const json_t *denom_keys_array;
   1299       struct GNUNET_JSON_Specification group_spec[] = {
   1300         TALER_JSON_spec_denomination_group (NULL,
   1301                                             key_data->currency,
   1302                                             &group),
   1303         GNUNET_JSON_spec_array_const ("denoms",
   1304                                       &denom_keys_array),
   1305         GNUNET_JSON_spec_end ()
   1306       };
   1307       json_t *denom_key_obj;
   1308       unsigned int index;
   1309 
   1310       EXITIF (GNUNET_SYSERR ==
   1311               GNUNET_JSON_parse (group_obj,
   1312                                  group_spec,
   1313                                  NULL,
   1314                                  NULL));
   1315 
   1316       /* Now, parse the individual denominations */
   1317       json_array_foreach (denom_keys_array,
   1318                           index,
   1319                           denom_key_obj)
   1320       {
   1321         /* Set the common fields from the group for this particular
   1322            denomination.  Required to make the validity check inside
   1323            parse_json_denomkey_partially pass */
   1324         struct TALER_EXCHANGE_DenomPublicKey dk = {
   1325           .value = group.value,
   1326           .fees = group.fees,
   1327           .key.age_mask = group.age_mask
   1328         };
   1329         bool found = false;
   1330 
   1331         EXITIF (GNUNET_SYSERR ==
   1332                 parse_json_denomkey_partially (&dk,
   1333                                                group.cipher,
   1334                                                check_sig,
   1335                                                denom_key_obj,
   1336                                                &key_data->master_pub,
   1337                                                group_idx,
   1338                                                index,
   1339                                                check_sig
   1340                                                ? &sig_ctx
   1341                                                : NULL));
   1342         for (unsigned int j = 0;
   1343              j<key_data->num_denom_keys;
   1344              j++)
   1345         {
   1346           if (0 == denoms_cmp (&dk,
   1347                                &key_data->denom_keys[j]))
   1348           {
   1349             found = true;
   1350             break;
   1351           }
   1352         }
   1353 
   1354         if (found)
   1355         {
   1356           /* 0:0:0 did not support /keys cherry picking */
   1357           TALER_LOG_DEBUG ("Skipping denomination key: already know it\n");
   1358           TALER_denom_pub_free (&dk.key);
   1359           continue;
   1360         }
   1361 
   1362         if (key_data->denom_keys_size == key_data->num_denom_keys)
   1363           GNUNET_array_grow (key_data->denom_keys,
   1364                              key_data->denom_keys_size,
   1365                              key_data->denom_keys_size * 2 + 2);
   1366         GNUNET_assert (key_data->denom_keys_size >
   1367                        key_data->num_denom_keys);
   1368         GNUNET_assert (key_data->num_denom_keys < UINT_MAX);
   1369         key_data->denom_keys[key_data->num_denom_keys++] = dk;
   1370 
   1371         /* Update "last_denom_issue_date" */
   1372         TALER_LOG_DEBUG ("Adding denomination key that is valid_until %s\n",
   1373                          GNUNET_TIME_timestamp2s (dk.valid_from));
   1374         key_data->last_denom_issue_date
   1375           = GNUNET_TIME_timestamp_max (key_data->last_denom_issue_date,
   1376                                        dk.valid_from);
   1377       };   /* end of json_array_foreach over denominations */
   1378     } /* end of json_array_foreach over groups of denominations */
   1379   } /* end of scope for group_ojb/group_idx */
   1380 
   1381   /* parse the auditor information */
   1382   {
   1383     json_t *auditor_info;
   1384     unsigned int index;
   1385 
   1386     /* Merge with the existing auditor information we have (/keys cherry picking) */
   1387     json_array_foreach (auditors_array, index, auditor_info)
   1388     {
   1389       struct TALER_EXCHANGE_AuditorInformation ai;
   1390       bool found = false;
   1391 
   1392       memset (&ai,
   1393               0,
   1394               sizeof (ai));
   1395       EXITIF (GNUNET_SYSERR ==
   1396               parse_json_auditor (&ai,
   1397                                   check_sig,
   1398                                   auditor_info,
   1399                                   key_data));
   1400       for (unsigned int j = 0; j<key_data->num_auditors; j++)
   1401       {
   1402         struct TALER_EXCHANGE_AuditorInformation *aix = &key_data->auditors[j];
   1403 
   1404         if (0 == GNUNET_memcmp (&ai.auditor_pub,
   1405                                 &aix->auditor_pub))
   1406         {
   1407           found = true;
   1408           /* Merge denomination key signatures of downloaded /keys into existing
   1409              auditor information 'aix'. */
   1410           TALER_LOG_DEBUG (
   1411             "Merging %u new audited keys with %u known audited keys\n",
   1412             aix->num_denom_keys,
   1413             ai.num_denom_keys);
   1414           for (unsigned int i = 0; i<ai.num_denom_keys; i++)
   1415           {
   1416             bool kfound = false;
   1417 
   1418             for (unsigned int k = 0; k<aix->num_denom_keys; k++)
   1419             {
   1420               if (aix->denom_keys[k].denom_key_offset ==
   1421                   ai.denom_keys[i].denom_key_offset)
   1422               {
   1423                 kfound = true;
   1424                 break;
   1425               }
   1426             }
   1427             if (! kfound)
   1428               GNUNET_array_append (aix->denom_keys,
   1429                                    aix->num_denom_keys,
   1430                                    ai.denom_keys[i]);
   1431           }
   1432           break;
   1433         }
   1434       }
   1435       if (found)
   1436       {
   1437         GNUNET_array_grow (ai.denom_keys,
   1438                            ai.num_denom_keys,
   1439                            0);
   1440         GNUNET_free (ai.auditor_url);
   1441         GNUNET_free (ai.auditor_name);
   1442         continue; /* we are done */
   1443       }
   1444       if (key_data->auditors_size == key_data->num_auditors)
   1445         GNUNET_array_grow (key_data->auditors,
   1446                            key_data->auditors_size,
   1447                            key_data->auditors_size * 2 + 2);
   1448       GNUNET_assert (key_data->auditors_size >
   1449                      key_data->num_auditors);
   1450       GNUNET_assert (NULL != ai.auditor_url);
   1451       GNUNET_assert (key_data->num_auditors < UINT_MAX);
   1452       key_data->auditors[key_data->num_auditors++] = ai;
   1453     };
   1454   }
   1455 
   1456   /* parse the revocation/recoup information */
   1457   if (NULL != recoup_array)
   1458   {
   1459     json_t *recoup_info;
   1460     unsigned int index;
   1461 
   1462     json_array_foreach (recoup_array, index, recoup_info)
   1463     {
   1464       struct TALER_DenominationHashP h_denom_pub;
   1465       struct GNUNET_JSON_Specification spec[] = {
   1466         GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
   1467                                      &h_denom_pub),
   1468         GNUNET_JSON_spec_end ()
   1469       };
   1470 
   1471       EXITIF (GNUNET_OK !=
   1472               GNUNET_JSON_parse (recoup_info,
   1473                                  spec,
   1474                                  NULL, NULL));
   1475       for (unsigned int j = 0;
   1476            j<key_data->num_denom_keys;
   1477            j++)
   1478       {
   1479         if (0 == GNUNET_memcmp (&h_denom_pub,
   1480                                 &key_data->denom_keys[j].h_key))
   1481         {
   1482           key_data->denom_keys[j].revoked = true;
   1483           break;
   1484         }
   1485       }
   1486     }
   1487   }
   1488 
   1489   if (check_sig)
   1490   {
   1491     struct GNUNET_HashContext *hash_context;
   1492     struct GNUNET_HashCode hc;
   1493 
   1494     hash_context = GNUNET_CRYPTO_hash_context_start ();
   1495     qsort (sig_ctx.elements,
   1496            sig_ctx.elements_pos,
   1497            sizeof (struct SignatureElement),
   1498            &signature_context_sort_cb);
   1499     for (unsigned int i = 0; i<sig_ctx.elements_pos; i++)
   1500     {
   1501       struct SignatureElement *element = &sig_ctx.elements[i];
   1502 
   1503       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1504                   "Adding %u,%u,%s\n",
   1505                   element->group_offset,
   1506                   element->offset,
   1507                   TALER_B2S (&element->master_sig));
   1508       GNUNET_CRYPTO_hash_context_read (hash_context,
   1509                                        &element->master_sig,
   1510                                        sizeof (element->master_sig));
   1511     }
   1512     GNUNET_array_grow (sig_ctx.elements,
   1513                        sig_ctx.elements_size,
   1514                        0);
   1515     GNUNET_CRYPTO_hash_context_finish (hash_context,
   1516                                        &hc);
   1517     EXITIF (GNUNET_OK !=
   1518             TALER_EXCHANGE_test_signing_key (key_data,
   1519                                              &exchange_pub));
   1520     EXITIF (GNUNET_OK !=
   1521             TALER_exchange_online_key_set_verify (
   1522               key_data->list_issue_date,
   1523               &hc,
   1524               &exchange_pub,
   1525               &exchange_sig));
   1526   }
   1527   return GNUNET_OK;
   1528 
   1529 EXITIF_exit:
   1530   *vc = TALER_EXCHANGE_VC_PROTOCOL_ERROR;
   1531   return GNUNET_SYSERR;
   1532 }
   1533 
   1534 
   1535 enum GNUNET_GenericReturnValue
   1536 TALER_EXCHANGE_test_signing_key (
   1537   const struct TALER_EXCHANGE_Keys *keys,
   1538   const struct TALER_ExchangePublicKeyP *pub)
   1539 {
   1540   struct GNUNET_TIME_Absolute now;
   1541 
   1542   /* we will check using a tolerance of 1h for the time */
   1543   now = GNUNET_TIME_absolute_get ();
   1544   for (unsigned int i = 0; i<keys->num_sign_keys; i++)
   1545     if ( (GNUNET_TIME_absolute_cmp (
   1546             keys->sign_keys[i].valid_from.abs_time,
   1547             <=,
   1548             GNUNET_TIME_absolute_add (now,
   1549                                       LIFETIME_TOLERANCE))) &&
   1550          (GNUNET_TIME_absolute_cmp (
   1551             keys->sign_keys[i].valid_until.abs_time,
   1552             >,
   1553             GNUNET_TIME_absolute_subtract (now,
   1554                                            LIFETIME_TOLERANCE))) &&
   1555          (0 == GNUNET_memcmp (pub,
   1556                               &keys->sign_keys[i].key)) )
   1557       return GNUNET_OK;
   1558   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1559               "Signing key not valid at time %s\n",
   1560               GNUNET_TIME_absolute2s (now));
   1561   return GNUNET_SYSERR;
   1562 }
   1563 
   1564 
   1565 const struct TALER_EXCHANGE_DenomPublicKey *
   1566 TALER_EXCHANGE_get_denomination_key (
   1567   const struct TALER_EXCHANGE_Keys *keys,
   1568   const struct TALER_DenominationPublicKey *pk)
   1569 {
   1570   for (unsigned int i = 0; i<keys->num_denom_keys; i++)
   1571     if (0 ==
   1572         TALER_denom_pub_cmp (pk,
   1573                              &keys->denom_keys[i].key))
   1574       return &keys->denom_keys[i];
   1575   return NULL;
   1576 }
   1577 
   1578 
   1579 const struct TALER_EXCHANGE_GlobalFee *
   1580 TALER_EXCHANGE_get_global_fee (
   1581   const struct TALER_EXCHANGE_Keys *keys,
   1582   struct GNUNET_TIME_Timestamp ts)
   1583 {
   1584   for (unsigned int i = 0; i<keys->num_global_fees; i++)
   1585   {
   1586     const struct TALER_EXCHANGE_GlobalFee *gf = &keys->global_fees[i];
   1587 
   1588     if (GNUNET_TIME_timestamp_cmp (ts,
   1589                                    >=,
   1590                                    gf->start_date) &&
   1591         GNUNET_TIME_timestamp_cmp (ts,
   1592                                    <,
   1593                                    gf->end_date))
   1594       return gf;
   1595   }
   1596   return NULL;
   1597 }
   1598 
   1599 
   1600 struct TALER_EXCHANGE_DenomPublicKey *
   1601 TALER_EXCHANGE_copy_denomination_key (
   1602   const struct TALER_EXCHANGE_DenomPublicKey *key)
   1603 {
   1604   struct TALER_EXCHANGE_DenomPublicKey *copy;
   1605 
   1606   copy = GNUNET_new (struct TALER_EXCHANGE_DenomPublicKey);
   1607   *copy = *key;
   1608   TALER_denom_pub_copy (&copy->key,
   1609                         &key->key);
   1610   return copy;
   1611 }
   1612 
   1613 
   1614 void
   1615 TALER_EXCHANGE_destroy_denomination_key (
   1616   struct TALER_EXCHANGE_DenomPublicKey *key)
   1617 {
   1618   TALER_denom_pub_free (&key->key);
   1619   GNUNET_free (key);
   1620 }
   1621 
   1622 
   1623 const struct TALER_EXCHANGE_DenomPublicKey *
   1624 TALER_EXCHANGE_get_denomination_key_by_hash (
   1625   const struct TALER_EXCHANGE_Keys *keys,
   1626   const struct TALER_DenominationHashP *hc)
   1627 {
   1628   /* FIXME-optimization: should we maybe use a hash map here? */
   1629   for (unsigned int i = 0; i<keys->num_denom_keys; i++)
   1630     if (0 == GNUNET_memcmp (hc,
   1631                             &keys->denom_keys[i].h_key))
   1632       return &keys->denom_keys[i];
   1633   return NULL;
   1634 }
   1635 
   1636 
   1637 struct TALER_EXCHANGE_Keys *
   1638 TALER_EXCHANGE_keys_incref (struct TALER_EXCHANGE_Keys *keys)
   1639 {
   1640   GNUNET_assert (keys->rc < UINT_MAX);
   1641   keys->rc++;
   1642   return keys;
   1643 }
   1644 
   1645 
   1646 void
   1647 TALER_EXCHANGE_keys_decref (struct TALER_EXCHANGE_Keys *keys)
   1648 {
   1649   if (NULL == keys)
   1650     return;
   1651   GNUNET_assert (0 < keys->rc);
   1652   keys->rc--;
   1653   if (0 != keys->rc)
   1654     return;
   1655   GNUNET_array_grow (keys->sign_keys,
   1656                      keys->num_sign_keys,
   1657                      0);
   1658   for (unsigned int i = 0; i<keys->num_denom_keys; i++)
   1659     TALER_denom_pub_free (&keys->denom_keys[i].key);
   1660   keys->num_denom_keys = 0;
   1661   GNUNET_array_grow (keys->denom_keys,
   1662                      keys->denom_keys_size,
   1663                      0);
   1664   for (unsigned int i = 0; i<keys->num_auditors; i++)
   1665   {
   1666     GNUNET_array_grow (keys->auditors[i].denom_keys,
   1667                        keys->auditors[i].num_denom_keys,
   1668                        0);
   1669     GNUNET_free (keys->auditors[i].auditor_url);
   1670     GNUNET_free (keys->auditors[i].auditor_name);
   1671   }
   1672   GNUNET_array_grow (keys->auditors,
   1673                      keys->auditors_size,
   1674                      0);
   1675   TALER_EXCHANGE_free_accounts (keys->accounts_len,
   1676                                 keys->accounts);
   1677   GNUNET_array_grow (keys->accounts,
   1678                      keys->accounts_len,
   1679                      0);
   1680   free_fees (keys->fees,
   1681              keys->fees_len);
   1682   GNUNET_array_grow (keys->hard_limits,
   1683                      keys->hard_limits_length,
   1684                      0);
   1685   GNUNET_array_grow (keys->zero_limits,
   1686                      keys->zero_limits_length,
   1687                      0);
   1688   json_decref (keys->extensions);
   1689   GNUNET_free (keys->cspec.name);
   1690   json_decref (keys->cspec.map_alt_unit_names);
   1691   GNUNET_array_grow (keys->cspec.common_amounts,
   1692                      keys->cspec.num_common_amounts,
   1693                      0);
   1694   GNUNET_free (keys->wallet_balance_limit_without_kyc);
   1695   GNUNET_free (keys->version);
   1696   GNUNET_free (keys->currency);
   1697   GNUNET_free (keys->asset_type);
   1698   GNUNET_free (keys->shopping_url);
   1699   GNUNET_free (keys->bank_compliance_language);
   1700   for (unsigned int i = 0; i < keys->num_wad_partners; i++)
   1701     GNUNET_free (keys->wad_partners[i].partner_base_url);
   1702   GNUNET_free (keys->wad_partners);
   1703   GNUNET_free (keys->global_fees);
   1704   GNUNET_free (keys->exchange_url);
   1705   GNUNET_free (keys);
   1706 }
   1707 
   1708 
   1709 struct TALER_EXCHANGE_Keys *
   1710 TALER_EXCHANGE_keys_from_json (const json_t *j)
   1711 {
   1712   const json_t *jkeys;
   1713   const char *url;
   1714   uint32_t version;
   1715   struct GNUNET_TIME_Timestamp expire
   1716     = GNUNET_TIME_UNIT_ZERO_TS;
   1717   struct GNUNET_JSON_Specification spec[] = {
   1718     GNUNET_JSON_spec_uint32 ("version",
   1719                              &version),
   1720     GNUNET_JSON_spec_object_const ("keys",
   1721                                    &jkeys),
   1722     TALER_JSON_spec_web_url ("exchange_url",
   1723                              &url),
   1724     GNUNET_JSON_spec_mark_optional (
   1725       GNUNET_JSON_spec_timestamp ("expire",
   1726                                   &expire),
   1727       NULL),
   1728     GNUNET_JSON_spec_end ()
   1729   };
   1730   struct TALER_EXCHANGE_Keys *keys;
   1731   enum TALER_EXCHANGE_VersionCompatibility compat;
   1732 
   1733   if (NULL == j)
   1734     return NULL;
   1735   if (GNUNET_OK !=
   1736       GNUNET_JSON_parse (j,
   1737                          spec,
   1738                          NULL, NULL))
   1739   {
   1740     GNUNET_break_op (0);
   1741     return NULL;
   1742   }
   1743   if (0 != version)
   1744   {
   1745     return NULL; /* unsupported version */
   1746   }
   1747   keys = GNUNET_new (struct TALER_EXCHANGE_Keys);
   1748   if (GNUNET_OK !=
   1749       TALER_EXCHANGE_decode_keys_json_ (jkeys,
   1750                                         false,
   1751                                         keys,
   1752                                         &compat))
   1753   {
   1754     GNUNET_break (0);
   1755     return NULL;
   1756   }
   1757   keys->rc = 1;
   1758   keys->key_data_expiration = expire;
   1759   keys->exchange_url = GNUNET_strdup (url);
   1760   return keys;
   1761 }
   1762 
   1763 
   1764 /**
   1765  * Data we track per denomination group.
   1766  */
   1767 struct GroupData
   1768 {
   1769   /**
   1770    * The json blob with the group meta-data and list of denominations
   1771    */
   1772   json_t *json;
   1773 
   1774   /**
   1775    * Meta data for this group.
   1776    */
   1777   struct TALER_DenominationGroup meta;
   1778 };
   1779 
   1780 
   1781 /**
   1782  * Add denomination group represented by @a value
   1783  * to list of denominations in @a cls. Also frees
   1784  * the @a value.
   1785  *
   1786  * @param[in,out] cls a `json_t *` with an array to build
   1787  * @param key unused
   1788  * @param value a `struct GroupData *`
   1789  * @return #GNUNET_OK (continue to iterate)
   1790  */
   1791 static enum GNUNET_GenericReturnValue
   1792 add_grp (void *cls,
   1793          const struct GNUNET_HashCode *key,
   1794          void *value)
   1795 {
   1796   json_t *denominations_by_group = cls;
   1797   struct GroupData *gd = value;
   1798   const char *cipher;
   1799   json_t *ge;
   1800   bool age_restricted = gd->meta.age_mask.bits != 0;
   1801 
   1802   (void) key;
   1803   switch (gd->meta.cipher)
   1804   {
   1805   case GNUNET_CRYPTO_BSA_RSA:
   1806     cipher = age_restricted ? "RSA+age_restricted" : "RSA";
   1807     break;
   1808   case GNUNET_CRYPTO_BSA_CS:
   1809     cipher = age_restricted ? "CS+age_restricted" : "CS";
   1810     break;
   1811   default:
   1812     GNUNET_assert (false);
   1813   }
   1814 
   1815   ge = GNUNET_JSON_PACK (
   1816     GNUNET_JSON_pack_string ("cipher",
   1817                              cipher),
   1818     GNUNET_JSON_pack_array_steal ("denoms",
   1819                                   gd->json),
   1820     TALER_JSON_PACK_DENOM_FEES ("fee",
   1821                                 &gd->meta.fees),
   1822     GNUNET_JSON_pack_allow_null (
   1823       age_restricted
   1824           ? GNUNET_JSON_pack_uint64 ("age_mask",
   1825                                      gd->meta.age_mask.bits)
   1826           : GNUNET_JSON_pack_string ("dummy",
   1827                                      NULL)),
   1828     TALER_JSON_pack_amount ("value",
   1829                             &gd->meta.value));
   1830   GNUNET_assert (0 ==
   1831                  json_array_append_new (denominations_by_group,
   1832                                         ge));
   1833   GNUNET_free (gd);
   1834   return GNUNET_OK;
   1835 }
   1836 
   1837 
   1838 /**
   1839  * Convert array of account restrictions @a ars to JSON.
   1840  *
   1841  * @param ar_len length of @a ars
   1842  * @param ars account restrictions to convert
   1843  * @return JSON representation
   1844  */
   1845 static json_t *
   1846 ar_to_json (unsigned int ar_len,
   1847             const struct TALER_EXCHANGE_AccountRestriction ars[static ar_len])
   1848 {
   1849   json_t *rval;
   1850 
   1851   rval = json_array ();
   1852   GNUNET_assert (NULL != rval);
   1853   for (unsigned int i = 0; i<ar_len; i++)
   1854   {
   1855     const struct TALER_EXCHANGE_AccountRestriction *ar = &ars[i];
   1856 
   1857     switch (ar->type)
   1858     {
   1859     case TALER_EXCHANGE_AR_INVALID:
   1860       GNUNET_break (0);
   1861       json_decref (rval);
   1862       return NULL;
   1863     case TALER_EXCHANGE_AR_DENY:
   1864       GNUNET_assert (
   1865         0 ==
   1866         json_array_append_new (
   1867           rval,
   1868           GNUNET_JSON_PACK (
   1869             GNUNET_JSON_pack_string ("type",
   1870                                      "deny"))));
   1871       break;
   1872     case TALER_EXCHANGE_AR_REGEX:
   1873       GNUNET_assert (
   1874         0 ==
   1875         json_array_append_new (
   1876           rval,
   1877           GNUNET_JSON_PACK (
   1878             GNUNET_JSON_pack_string (
   1879               "type",
   1880               "regex"),
   1881             GNUNET_JSON_pack_string (
   1882               "payto_regex",
   1883               ar->details.regex.posix_egrep),
   1884             GNUNET_JSON_pack_string (
   1885               "human_hint",
   1886               ar->details.regex.human_hint),
   1887             GNUNET_JSON_pack_object_incref (
   1888               "human_hint_i18n",
   1889               (json_t *) ar->details.regex.human_hint_i18n)
   1890             )));
   1891       break;
   1892     }
   1893   }
   1894   return rval;
   1895 }
   1896 
   1897 
   1898 json_t *
   1899 TALER_EXCHANGE_keys_to_json (const struct TALER_EXCHANGE_Keys *kd)
   1900 {
   1901   struct GNUNET_TIME_Timestamp now;
   1902   json_t *keys;
   1903   json_t *signkeys;
   1904   json_t *denominations_by_group;
   1905   json_t *auditors;
   1906   json_t *recoup;
   1907   json_t *wire_fees;
   1908   json_t *accounts;
   1909   json_t *global_fees;
   1910   json_t *wblwk = NULL;
   1911   json_t *wads_json;
   1912   json_t *hard_limits;
   1913   json_t *zero_limits;
   1914 
   1915   now = GNUNET_TIME_timestamp_get ();
   1916   signkeys = json_array ();
   1917   GNUNET_assert (NULL != signkeys);
   1918   for (unsigned int i = 0; i<kd->num_sign_keys; i++)
   1919   {
   1920     const struct TALER_EXCHANGE_SigningPublicKey *sk = &kd->sign_keys[i];
   1921     json_t *signkey;
   1922 
   1923     if (GNUNET_TIME_timestamp_cmp (now,
   1924                                    >,
   1925                                    sk->valid_until))
   1926       continue; /* skip keys that have expired */
   1927     signkey = GNUNET_JSON_PACK (
   1928       GNUNET_JSON_pack_data_auto ("key",
   1929                                   &sk->key),
   1930       GNUNET_JSON_pack_data_auto ("master_sig",
   1931                                   &sk->master_sig),
   1932       GNUNET_JSON_pack_timestamp ("stamp_start",
   1933                                   sk->valid_from),
   1934       GNUNET_JSON_pack_timestamp ("stamp_expire",
   1935                                   sk->valid_until),
   1936       GNUNET_JSON_pack_timestamp ("stamp_end",
   1937                                   sk->valid_legal));
   1938     GNUNET_assert (NULL != signkey);
   1939     GNUNET_assert (0 ==
   1940                    json_array_append_new (signkeys,
   1941                                           signkey));
   1942   }
   1943 
   1944   denominations_by_group = json_array ();
   1945   GNUNET_assert (NULL != denominations_by_group);
   1946   {
   1947     struct GNUNET_CONTAINER_MultiHashMap *dbg;
   1948 
   1949     dbg = GNUNET_CONTAINER_multihashmap_create (128,
   1950                                                 false);
   1951     for (unsigned int i = 0; i<kd->num_denom_keys; i++)
   1952     {
   1953       const struct TALER_EXCHANGE_DenomPublicKey *dk = &kd->denom_keys[i];
   1954       struct TALER_DenominationGroup meta = {
   1955         .cipher = dk->key.bsign_pub_key->cipher,
   1956         .value = dk->value,
   1957         .fees = dk->fees,
   1958         .age_mask = dk->key.age_mask
   1959       };
   1960       struct GNUNET_HashCode key;
   1961       struct GroupData *gd;
   1962       json_t *denom;
   1963       struct GNUNET_JSON_PackSpec key_spec;
   1964 
   1965       if (GNUNET_TIME_timestamp_cmp (now,
   1966                                      >,
   1967                                      dk->expire_deposit))
   1968         continue; /* skip keys that have expired */
   1969       TALER_denomination_group_get_key (&meta,
   1970                                         &key);
   1971       gd = GNUNET_CONTAINER_multihashmap_get (dbg,
   1972                                               &key);
   1973       if (NULL == gd)
   1974       {
   1975         gd = GNUNET_new (struct GroupData);
   1976         gd->meta = meta;
   1977         gd->json = json_array ();
   1978         GNUNET_assert (NULL != gd->json);
   1979         GNUNET_assert (
   1980           GNUNET_OK ==
   1981           GNUNET_CONTAINER_multihashmap_put (dbg,
   1982                                              &key,
   1983                                              gd,
   1984                                              GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
   1985 
   1986       }
   1987       switch (meta.cipher)
   1988       {
   1989       case GNUNET_CRYPTO_BSA_RSA:
   1990         key_spec =
   1991           GNUNET_JSON_pack_rsa_public_key (
   1992             "rsa_pub",
   1993             dk->key.bsign_pub_key->details.rsa_public_key);
   1994         break;
   1995       case GNUNET_CRYPTO_BSA_CS:
   1996         key_spec =
   1997           GNUNET_JSON_pack_data_varsize (
   1998             "cs_pub",
   1999             &dk->key.bsign_pub_key->details.cs_public_key,
   2000             sizeof (dk->key.bsign_pub_key->details.cs_public_key));
   2001         break;
   2002       default:
   2003         GNUNET_assert (false);
   2004       }
   2005       denom = GNUNET_JSON_PACK (
   2006         GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
   2007                                     dk->expire_deposit),
   2008         GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
   2009                                     dk->withdraw_valid_until),
   2010         GNUNET_JSON_pack_timestamp ("stamp_start",
   2011                                     dk->valid_from),
   2012         GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
   2013                                     dk->expire_legal),
   2014         GNUNET_JSON_pack_data_auto ("master_sig",
   2015                                     &dk->master_sig),
   2016         key_spec
   2017         );
   2018       GNUNET_assert (0 ==
   2019                      json_array_append_new (gd->json,
   2020                                             denom));
   2021     }
   2022     GNUNET_CONTAINER_multihashmap_iterate (dbg,
   2023                                            &add_grp,
   2024                                            denominations_by_group);
   2025     GNUNET_CONTAINER_multihashmap_destroy (dbg);
   2026   }
   2027 
   2028   auditors = json_array ();
   2029   GNUNET_assert (NULL != auditors);
   2030   for (unsigned int i = 0; i<kd->num_auditors; i++)
   2031   {
   2032     const struct TALER_EXCHANGE_AuditorInformation *ai = &kd->auditors[i];
   2033     json_t *a;
   2034     json_t *adenoms;
   2035 
   2036     adenoms = json_array ();
   2037     GNUNET_assert (NULL != adenoms);
   2038     for (unsigned int j = 0; j<ai->num_denom_keys; j++)
   2039     {
   2040       const struct TALER_EXCHANGE_AuditorDenominationInfo *adi =
   2041         &ai->denom_keys[j];
   2042       const struct TALER_EXCHANGE_DenomPublicKey *dk =
   2043         &kd->denom_keys[adi->denom_key_offset];
   2044       json_t *k;
   2045 
   2046       GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys);
   2047       if (GNUNET_TIME_timestamp_cmp (now,
   2048                                      >,
   2049                                      dk->expire_deposit))
   2050         continue; /* skip auditor signatures for denomination keys that have expired */
   2051       GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys);
   2052       k = GNUNET_JSON_PACK (
   2053         GNUNET_JSON_pack_data_auto ("denom_pub_h",
   2054                                     &dk->h_key),
   2055         GNUNET_JSON_pack_data_auto ("auditor_sig",
   2056                                     &adi->auditor_sig));
   2057       GNUNET_assert (0 ==
   2058                      json_array_append_new (adenoms,
   2059                                             k));
   2060     }
   2061 
   2062     a = GNUNET_JSON_PACK (
   2063       GNUNET_JSON_pack_data_auto ("auditor_pub",
   2064                                   &ai->auditor_pub),
   2065       GNUNET_JSON_pack_string ("auditor_url",
   2066                                ai->auditor_url),
   2067       GNUNET_JSON_pack_string ("auditor_name",
   2068                                ai->auditor_name),
   2069       GNUNET_JSON_pack_array_steal ("denomination_keys",
   2070                                     adenoms));
   2071     GNUNET_assert (0 ==
   2072                    json_array_append_new (auditors,
   2073                                           a));
   2074   }
   2075 
   2076   global_fees = json_array ();
   2077   GNUNET_assert (NULL != global_fees);
   2078   for (unsigned int i = 0; i<kd->num_global_fees; i++)
   2079   {
   2080     const struct TALER_EXCHANGE_GlobalFee *gf
   2081       = &kd->global_fees[i];
   2082 
   2083     if (GNUNET_TIME_absolute_is_past (gf->end_date.abs_time))
   2084       continue;
   2085     GNUNET_assert (
   2086       0 ==
   2087       json_array_append_new (
   2088         global_fees,
   2089         GNUNET_JSON_PACK (
   2090           GNUNET_JSON_pack_timestamp ("start_date",
   2091                                       gf->start_date),
   2092           GNUNET_JSON_pack_timestamp ("end_date",
   2093                                       gf->end_date),
   2094           TALER_JSON_PACK_GLOBAL_FEES (&gf->fees),
   2095           GNUNET_JSON_pack_time_rel ("history_expiration",
   2096                                      gf->history_expiration),
   2097           GNUNET_JSON_pack_time_rel ("purse_timeout",
   2098                                      gf->purse_timeout),
   2099           GNUNET_JSON_pack_uint64 ("purse_account_limit",
   2100                                    gf->purse_account_limit),
   2101           GNUNET_JSON_pack_data_auto ("master_sig",
   2102                                       &gf->master_sig))));
   2103   }
   2104 
   2105   accounts = json_array ();
   2106   GNUNET_assert (NULL != accounts);
   2107   for (unsigned int i = 0; i<kd->accounts_len; i++)
   2108   {
   2109     const struct TALER_EXCHANGE_WireAccount *acc
   2110       = &kd->accounts[i];
   2111     json_t *credit_restrictions;
   2112     json_t *debit_restrictions;
   2113 
   2114     credit_restrictions
   2115       = ar_to_json (acc->credit_restrictions_length,
   2116                     acc->credit_restrictions);
   2117     GNUNET_assert (NULL != credit_restrictions);
   2118     debit_restrictions
   2119       = ar_to_json (acc->debit_restrictions_length,
   2120                     acc->debit_restrictions);
   2121     GNUNET_assert (NULL != debit_restrictions);
   2122     GNUNET_assert (
   2123       0 ==
   2124       json_array_append_new (
   2125         accounts,
   2126         GNUNET_JSON_PACK (
   2127           TALER_JSON_pack_full_payto ("payto_uri",
   2128                                       acc->fpayto_uri),
   2129           GNUNET_JSON_pack_allow_null (
   2130             GNUNET_JSON_pack_string ("conversion_url",
   2131                                      acc->conversion_url)),
   2132           GNUNET_JSON_pack_allow_null (
   2133             GNUNET_JSON_pack_string ("open_banking_gateway",
   2134                                      acc->open_banking_gateway)),
   2135           GNUNET_JSON_pack_allow_null (
   2136             GNUNET_JSON_pack_string ("wire_transfer_gateway",
   2137                                      acc->wire_transfer_gateway)),
   2138           GNUNET_JSON_pack_int64 ("priority",
   2139                                   acc->priority),
   2140           GNUNET_JSON_pack_allow_null (
   2141             GNUNET_JSON_pack_string ("bank_label",
   2142                                      acc->bank_label)),
   2143           GNUNET_JSON_pack_array_steal ("debit_restrictions",
   2144                                         debit_restrictions),
   2145           GNUNET_JSON_pack_array_steal ("credit_restrictions",
   2146                                         credit_restrictions),
   2147           GNUNET_JSON_pack_data_auto ("master_sig",
   2148                                       &acc->master_sig))));
   2149   }
   2150   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2151               "Serialized %u/%u wire accounts to JSON\n",
   2152               (unsigned int) json_array_size (accounts),
   2153               kd->accounts_len);
   2154 
   2155   wire_fees = json_object ();
   2156   GNUNET_assert (NULL != wire_fees);
   2157   for (unsigned int i = 0; i<kd->fees_len; i++)
   2158   {
   2159     const struct TALER_EXCHANGE_WireFeesByMethod *fbw
   2160       = &kd->fees[i];
   2161     json_t *wf;
   2162 
   2163     wf = json_array ();
   2164     GNUNET_assert (NULL != wf);
   2165     for (struct TALER_EXCHANGE_WireAggregateFees *p = fbw->fees_head;
   2166          NULL != p;
   2167          p = p->next)
   2168     {
   2169       GNUNET_assert (
   2170         0 ==
   2171         json_array_append_new (
   2172           wf,
   2173           GNUNET_JSON_PACK (
   2174             TALER_JSON_pack_amount ("wire_fee",
   2175                                     &p->fees.wire),
   2176             TALER_JSON_pack_amount ("closing_fee",
   2177                                     &p->fees.closing),
   2178             GNUNET_JSON_pack_timestamp ("start_date",
   2179                                         p->start_date),
   2180             GNUNET_JSON_pack_timestamp ("end_date",
   2181                                         p->end_date),
   2182             GNUNET_JSON_pack_data_auto ("sig",
   2183                                         &p->master_sig))));
   2184     }
   2185     GNUNET_assert (0 ==
   2186                    json_object_set_new (wire_fees,
   2187                                         fbw->method,
   2188                                         wf));
   2189   }
   2190 
   2191   recoup = json_array ();
   2192   GNUNET_assert (NULL != recoup);
   2193   for (unsigned int i = 0; i<kd->num_denom_keys; i++)
   2194   {
   2195     const struct TALER_EXCHANGE_DenomPublicKey *dk
   2196       = &kd->denom_keys[i];
   2197     if (! dk->revoked)
   2198       continue;
   2199     GNUNET_assert (0 ==
   2200                    json_array_append_new (
   2201                      recoup,
   2202                      GNUNET_JSON_PACK (
   2203                        GNUNET_JSON_pack_data_auto ("h_denom_pub",
   2204                                                    &dk->h_key))));
   2205   }
   2206 
   2207   wblwk = json_array ();
   2208   GNUNET_assert (NULL != wblwk);
   2209   for (unsigned int i = 0; i<kd->wblwk_length; i++)
   2210   {
   2211     const struct TALER_Amount *a = &kd->wallet_balance_limit_without_kyc[i];
   2212 
   2213     GNUNET_assert (0 ==
   2214                    json_array_append_new (
   2215                      wblwk,
   2216                      TALER_JSON_from_amount (a)));
   2217   }
   2218 
   2219   hard_limits = json_array ();
   2220   for (unsigned int i = 0; i < kd->hard_limits_length; i++)
   2221   {
   2222     const struct TALER_EXCHANGE_AccountLimit *al
   2223       = &kd->hard_limits[i];
   2224     json_t *j;
   2225 
   2226     j = GNUNET_JSON_PACK (
   2227       TALER_JSON_pack_amount ("threshold",
   2228                               &al->threshold),
   2229       GNUNET_JSON_pack_time_rel ("timeframe",
   2230                                  al->timeframe),
   2231       TALER_JSON_pack_kycte ("operation_type",
   2232                              al->operation_type),
   2233       GNUNET_JSON_pack_bool ("soft_limit",
   2234                              al->soft_limit)
   2235       );
   2236     GNUNET_assert (0 ==
   2237                    json_array_append_new (
   2238                      hard_limits,
   2239                      j));
   2240   }
   2241 
   2242   zero_limits = json_array ();
   2243   for (unsigned int i = 0; i < kd->zero_limits_length; i++)
   2244   {
   2245     const struct TALER_EXCHANGE_ZeroLimitedOperation *zol
   2246       = &kd->zero_limits[i];
   2247     json_t *j;
   2248 
   2249     j = GNUNET_JSON_PACK (
   2250       TALER_JSON_pack_kycte ("operation_type",
   2251                              zol->operation_type)
   2252       );
   2253     GNUNET_assert (0 ==
   2254                    json_array_append_new (
   2255                      zero_limits,
   2256                      j));
   2257   }
   2258 
   2259   wads_json = json_array ();
   2260   GNUNET_assert (NULL != wads_json);
   2261   for (unsigned int i = 0; i < kd->num_wad_partners; i++)
   2262   {
   2263     const struct TALER_EXCHANGE_WadPartner *wp
   2264       = &kd->wad_partners[i];
   2265 
   2266     GNUNET_assert (
   2267       0 ==
   2268       json_array_append_new (
   2269         wads_json,
   2270         GNUNET_JSON_PACK (
   2271           GNUNET_JSON_pack_string ("partner_base_url",
   2272                                    wp->partner_base_url),
   2273           GNUNET_JSON_pack_data_auto ("partner_master_pub",
   2274                                       &wp->partner_master_pub),
   2275           TALER_JSON_pack_amount ("wad_fee",
   2276                                   &wp->wad_fee),
   2277           GNUNET_JSON_pack_time_rel ("wad_frequency",
   2278                                      wp->wad_frequency),
   2279           GNUNET_JSON_pack_timestamp ("start_date",
   2280                                       wp->start_date),
   2281           GNUNET_JSON_pack_timestamp ("end_date",
   2282                                       wp->end_date),
   2283           GNUNET_JSON_pack_data_auto ("master_sig",
   2284                                       &wp->master_sig))));
   2285   }
   2286 
   2287   keys = GNUNET_JSON_PACK (
   2288     GNUNET_JSON_pack_string ("version",
   2289                              kd->version),
   2290     GNUNET_JSON_pack_string ("currency",
   2291                              kd->currency),
   2292     GNUNET_JSON_pack_object_steal ("currency_specification",
   2293                                    TALER_JSON_currency_specs_to_json (
   2294                                      &kd->cspec)),
   2295     TALER_JSON_pack_amount ("stefan_abs",
   2296                             &kd->stefan_abs),
   2297     TALER_JSON_pack_amount ("stefan_log",
   2298                             &kd->stefan_log),
   2299     GNUNET_JSON_pack_double ("stefan_lin",
   2300                              kd->stefan_lin),
   2301     GNUNET_JSON_pack_allow_null (
   2302       kd->tiny_amount_available
   2303       ? TALER_JSON_pack_amount ("tiny_amount",
   2304                                 &kd->tiny_amount)
   2305       : GNUNET_JSON_pack_string ("dummy",
   2306                                  NULL)),
   2307     GNUNET_JSON_pack_string ("asset_type",
   2308                              kd->asset_type),
   2309     GNUNET_JSON_pack_allow_null (
   2310       GNUNET_JSON_pack_string ("shopping_url",
   2311                                kd->shopping_url)),
   2312     GNUNET_JSON_pack_allow_null (
   2313       GNUNET_JSON_pack_string ("bank_compliance_language",
   2314                                kd->bank_compliance_language)),
   2315     GNUNET_JSON_pack_bool ("disable_direct_deposit",
   2316                            kd->disable_direct_deposit),
   2317     GNUNET_JSON_pack_data_auto ("master_public_key",
   2318                                 &kd->master_pub),
   2319     GNUNET_JSON_pack_time_rel ("reserve_closing_delay",
   2320                                kd->reserve_closing_delay),
   2321     GNUNET_JSON_pack_timestamp ("list_issue_date",
   2322                                 kd->list_issue_date),
   2323     GNUNET_JSON_pack_array_steal ("global_fees",
   2324                                   global_fees),
   2325     GNUNET_JSON_pack_array_steal ("signkeys",
   2326                                   signkeys),
   2327     GNUNET_JSON_pack_object_steal ("wire_fees",
   2328                                    wire_fees),
   2329     GNUNET_JSON_pack_array_steal ("accounts",
   2330                                   accounts),
   2331     GNUNET_JSON_pack_array_steal ("wads",
   2332                                   wads_json),
   2333     GNUNET_JSON_pack_array_steal ("hard_limits",
   2334                                   hard_limits),
   2335     GNUNET_JSON_pack_array_steal ("zero_limits",
   2336                                   zero_limits),
   2337     GNUNET_JSON_pack_array_steal ("denominations",
   2338                                   denominations_by_group),
   2339     GNUNET_JSON_pack_allow_null (
   2340       GNUNET_JSON_pack_array_steal ("recoup",
   2341                                     recoup)),
   2342     GNUNET_JSON_pack_array_steal ("auditors",
   2343                                   auditors),
   2344     GNUNET_JSON_pack_bool ("kyc_enabled",
   2345                            kd->kyc_enabled),
   2346     GNUNET_JSON_pack_allow_null (
   2347       GNUNET_JSON_pack_object_incref ("extensions",
   2348                                       kd->extensions)),
   2349     GNUNET_JSON_pack_allow_null (
   2350       GNUNET_is_zero (&kd->extensions_sig)
   2351       ? GNUNET_JSON_pack_string ("dummy",
   2352                                  NULL)
   2353       : GNUNET_JSON_pack_data_auto ("extensions_sig",
   2354                                     &kd->extensions_sig)),
   2355     GNUNET_JSON_pack_allow_null (
   2356       GNUNET_JSON_pack_array_steal ("wallet_balance_limit_without_kyc",
   2357                                     wblwk))
   2358 
   2359     );
   2360   return GNUNET_JSON_PACK (
   2361     GNUNET_JSON_pack_uint64 ("version",
   2362                              EXCHANGE_SERIALIZATION_FORMAT_VERSION),
   2363     GNUNET_JSON_pack_allow_null (
   2364       GNUNET_JSON_pack_timestamp ("expire",
   2365                                   kd->key_data_expiration)),
   2366     GNUNET_JSON_pack_string ("exchange_url",
   2367                              kd->exchange_url),
   2368     GNUNET_JSON_pack_object_steal ("keys",
   2369                                    keys));
   2370 }
   2371 
   2372 
   2373 /* end of exchange_api_handle.c */