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 (75931B)


      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 35
     40 
     41 /**
     42  * How many versions are we backwards compatible with?
     43  */
     44 #define EXCHANGE_PROTOCOL_AGE 1
     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_mark_optional (
   1000         GNUNET_JSON_spec_relative_time (
   1001           "default_p2p_push_expiration",
   1002           &key_data->default_p2p_push_expiration),
   1003         NULL),
   1004       GNUNET_JSON_spec_string (
   1005         "currency",
   1006         &currency),
   1007       GNUNET_JSON_spec_string (
   1008         "asset_type",
   1009         &asset_type),
   1010       GNUNET_JSON_spec_array_const (
   1011         "global_fees",
   1012         &global_fees),
   1013       GNUNET_JSON_spec_array_const (
   1014         "signkeys",
   1015         &sign_keys_array),
   1016       GNUNET_JSON_spec_array_const (
   1017         "denominations",
   1018         &denominations_by_group),
   1019       GNUNET_JSON_spec_mark_optional (
   1020         GNUNET_JSON_spec_array_const (
   1021           "recoup",
   1022           &recoup_array),
   1023         NULL),
   1024       GNUNET_JSON_spec_array_const (
   1025         "auditors",
   1026         &auditors_array),
   1027       GNUNET_JSON_spec_bool (
   1028         "kyc_enabled",
   1029         &key_data->kyc_enabled),
   1030       GNUNET_JSON_spec_mark_optional (
   1031         GNUNET_JSON_spec_object_const ("extensions",
   1032                                        &manifests),
   1033         &no_extensions),
   1034       GNUNET_JSON_spec_mark_optional (
   1035         GNUNET_JSON_spec_fixed_auto (
   1036           "extensions_sig",
   1037           &key_data->extensions_sig),
   1038         &no_signature),
   1039       GNUNET_JSON_spec_string ("version",
   1040                                &ver),
   1041       GNUNET_JSON_spec_mark_optional (
   1042         GNUNET_JSON_spec_array_const (
   1043           "wallet_balance_limit_without_kyc",
   1044           &wblwk),
   1045         NULL),
   1046       GNUNET_JSON_spec_mark_optional (
   1047         GNUNET_JSON_spec_string ("shopping_url",
   1048                                  &shopping_url),
   1049         NULL),
   1050       GNUNET_JSON_spec_mark_optional (
   1051         GNUNET_JSON_spec_string ("bank_compliance_language",
   1052                                  &bank_compliance_language),
   1053         NULL),
   1054       GNUNET_JSON_spec_mark_optional (
   1055         GNUNET_JSON_spec_bool ("disable_direct_deposit",
   1056                                &key_data->disable_direct_deposit),
   1057         NULL),
   1058       GNUNET_JSON_spec_end ()
   1059     };
   1060     const char *emsg;
   1061     unsigned int eline;
   1062 
   1063     if (GNUNET_OK !=
   1064         GNUNET_JSON_parse (resp_obj,
   1065                            (check_sig) ? mspec : &mspec[2],
   1066                            &emsg,
   1067                            &eline))
   1068     {
   1069       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1070                   "Parsing /keys failed for `%s' (%u)\n",
   1071                   emsg,
   1072                   eline);
   1073       EXITIF (1);
   1074     }
   1075     {
   1076       const json_t *hard_limits = NULL;
   1077       const json_t *zero_limits = NULL;
   1078       bool no_tiny_amount = false;
   1079       struct GNUNET_JSON_Specification sspec[] = {
   1080         TALER_JSON_spec_currency_specification (
   1081           "currency_specification",
   1082           currency,
   1083           &key_data->cspec),
   1084         TALER_JSON_spec_amount (
   1085           "stefan_abs",
   1086           currency,
   1087           &key_data->stefan_abs),
   1088         TALER_JSON_spec_amount (
   1089           "stefan_log",
   1090           currency,
   1091           &key_data->stefan_log),
   1092         GNUNET_JSON_spec_mark_optional (
   1093           TALER_JSON_spec_amount (
   1094             "tiny_amount",
   1095             currency,
   1096             &key_data->tiny_amount),
   1097           &no_tiny_amount),
   1098         GNUNET_JSON_spec_mark_optional (
   1099           GNUNET_JSON_spec_array_const (
   1100             "hard_limits",
   1101             &hard_limits),
   1102           NULL),
   1103         GNUNET_JSON_spec_mark_optional (
   1104           GNUNET_JSON_spec_array_const (
   1105             "zero_limits",
   1106             &zero_limits),
   1107           NULL),
   1108         GNUNET_JSON_spec_double (
   1109           "stefan_lin",
   1110           &key_data->stefan_lin),
   1111         GNUNET_JSON_spec_end ()
   1112       };
   1113 
   1114       if (GNUNET_OK !=
   1115           GNUNET_JSON_parse (resp_obj,
   1116                              sspec,
   1117                              &emsg,
   1118                              &eline))
   1119       {
   1120         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1121                     "Parsing /keys failed for `%s' (%u)\n",
   1122                     emsg,
   1123                     eline);
   1124         EXITIF (1);
   1125       }
   1126       if ( (NULL != hard_limits) &&
   1127            (GNUNET_OK !=
   1128             parse_hard_limits (hard_limits,
   1129                                key_data)) )
   1130       {
   1131         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1132                     "Parsing hard limits of /keys failed\n");
   1133         EXITIF (1);
   1134       }
   1135       if ( (NULL != zero_limits) &&
   1136            (GNUNET_OK !=
   1137             parse_zero_limits (zero_limits,
   1138                                key_data)) )
   1139       {
   1140         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1141                     "Parsing hard limits of /keys failed\n");
   1142         EXITIF (1);
   1143       }
   1144       key_data->tiny_amount_available = ! no_tiny_amount;
   1145     }
   1146 
   1147     key_data->currency = GNUNET_strdup (currency);
   1148     key_data->version = GNUNET_strdup (ver);
   1149     key_data->asset_type = GNUNET_strdup (asset_type);
   1150     if (NULL != shopping_url)
   1151       key_data->shopping_url = GNUNET_strdup (shopping_url);
   1152     if (NULL != bank_compliance_language)
   1153       key_data->bank_compliance_language
   1154         = GNUNET_strdup (bank_compliance_language);
   1155     if (! no_extensions)
   1156       key_data->extensions = json_incref ((json_t *) manifests);
   1157   }
   1158 
   1159   /* parse the global fees */
   1160   EXITIF (json_array_size (global_fees) > UINT_MAX);
   1161   key_data->num_global_fees
   1162     = (unsigned int) json_array_size (global_fees);
   1163   if (0 != key_data->num_global_fees)
   1164   {
   1165     json_t *global_fee;
   1166     size_t index;
   1167 
   1168     key_data->global_fees
   1169       = GNUNET_new_array (key_data->num_global_fees,
   1170                           struct TALER_EXCHANGE_GlobalFee);
   1171     json_array_foreach (global_fees, index, global_fee)
   1172     {
   1173       EXITIF (GNUNET_SYSERR ==
   1174               parse_global_fee (&key_data->global_fees[index],
   1175                                 check_sig,
   1176                                 global_fee,
   1177                                 key_data));
   1178     }
   1179   }
   1180 
   1181   /* parse the signing keys */
   1182   EXITIF (json_array_size (sign_keys_array) > UINT_MAX);
   1183   key_data->num_sign_keys
   1184     = (unsigned int) json_array_size (sign_keys_array);
   1185   if (0 != key_data->num_sign_keys)
   1186   {
   1187     json_t *sign_key_obj;
   1188     size_t index;
   1189 
   1190     key_data->sign_keys
   1191       = GNUNET_new_array (key_data->num_sign_keys,
   1192                           struct TALER_EXCHANGE_SigningPublicKey);
   1193     json_array_foreach (sign_keys_array, index, sign_key_obj) {
   1194       EXITIF (GNUNET_SYSERR ==
   1195               parse_json_signkey (&key_data->sign_keys[index],
   1196                                   check_sig,
   1197                                   sign_key_obj,
   1198                                   &key_data->master_pub));
   1199     }
   1200   }
   1201 
   1202   /* Parse balance limits */
   1203   if (NULL != wblwk)
   1204   {
   1205     EXITIF (json_array_size (wblwk) > UINT_MAX);
   1206     key_data->wblwk_length
   1207       = (unsigned int) json_array_size (wblwk);
   1208     key_data->wallet_balance_limit_without_kyc
   1209       = GNUNET_new_array (key_data->wblwk_length,
   1210                           struct TALER_Amount);
   1211     for (unsigned int i = 0; i<key_data->wblwk_length; i++)
   1212     {
   1213       struct TALER_Amount *a = &key_data->wallet_balance_limit_without_kyc[i];
   1214       const json_t *aj = json_array_get (wblwk,
   1215                                          i);
   1216       struct GNUNET_JSON_Specification spec[] = {
   1217         TALER_JSON_spec_amount (NULL,
   1218                                 key_data->currency,
   1219                                 a),
   1220         GNUNET_JSON_spec_end ()
   1221       };
   1222 
   1223       EXITIF (GNUNET_OK !=
   1224               GNUNET_JSON_parse (aj,
   1225                                  spec,
   1226                                  NULL, NULL));
   1227     }
   1228   }
   1229 
   1230   /* Parse wire accounts */
   1231   key_data->fees = parse_fees (&key_data->master_pub,
   1232                                key_data->currency,
   1233                                fees,
   1234                                &key_data->fees_len);
   1235   EXITIF (NULL == key_data->fees);
   1236   /* parse accounts */
   1237   EXITIF (json_array_size (accounts) > UINT_MAX);
   1238   GNUNET_array_grow (key_data->accounts,
   1239                      key_data->accounts_len,
   1240                      json_array_size (accounts));
   1241   EXITIF (GNUNET_OK !=
   1242           TALER_EXCHANGE_parse_accounts (&key_data->master_pub,
   1243                                          accounts,
   1244                                          key_data->accounts_len,
   1245                                          key_data->accounts));
   1246 
   1247   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1248               "Parsed %u wire accounts from JSON\n",
   1249               key_data->accounts_len);
   1250 
   1251   /* Parse wad partners */
   1252   EXITIF (GNUNET_OK !=
   1253           parse_wads (wads,
   1254                       check_sig,
   1255                       key_data));
   1256 
   1257 
   1258   /* Parse the supported extension(s): age-restriction. */
   1259   /* FIXME[Oec]: maybe lift all this into a FP in TALER_Extension ? */
   1260   if (! no_extensions)
   1261   {
   1262     if (no_signature)
   1263     {
   1264       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1265                   "found extensions without signature\n");
   1266     }
   1267     else
   1268     {
   1269       /* We have an extensions object. Verify its signature. */
   1270       EXITIF (GNUNET_OK !=
   1271               TALER_extensions_verify_manifests_signature (
   1272                 manifests,
   1273                 &key_data->extensions_sig,
   1274                 &key_data->master_pub));
   1275 
   1276       /* Parse and set the the configuration of the extensions accordingly */
   1277       EXITIF (GNUNET_OK !=
   1278               TALER_extensions_load_manifests (manifests));
   1279     }
   1280 
   1281     /* Assuming we might have now a new value for age_mask, set it in key_data */
   1282     key_data->age_mask = TALER_extensions_get_age_restriction_mask ();
   1283   }
   1284 
   1285   /*
   1286    * Parse the denomination keys, merging with the
   1287    * possibly EXISTING array as required (/keys cherry picking).
   1288    *
   1289    * The denominations are grouped by common values of
   1290    *    {cipher, value, fee, age_mask}.
   1291    */
   1292   {
   1293     json_t *group_obj;
   1294     unsigned int group_idx;
   1295 
   1296     json_array_foreach (denominations_by_group,
   1297                         group_idx,
   1298                         group_obj)
   1299     {
   1300       /* First, parse { cipher, fees, value, age_mask, hash } of the current
   1301          group. */
   1302       struct TALER_DenominationGroup group = {0};
   1303       const json_t *denom_keys_array;
   1304       struct GNUNET_JSON_Specification group_spec[] = {
   1305         TALER_JSON_spec_denomination_group (NULL,
   1306                                             key_data->currency,
   1307                                             &group),
   1308         GNUNET_JSON_spec_array_const ("denoms",
   1309                                       &denom_keys_array),
   1310         GNUNET_JSON_spec_end ()
   1311       };
   1312       json_t *denom_key_obj;
   1313       unsigned int index;
   1314 
   1315       EXITIF (GNUNET_SYSERR ==
   1316               GNUNET_JSON_parse (group_obj,
   1317                                  group_spec,
   1318                                  NULL,
   1319                                  NULL));
   1320 
   1321       /* Now, parse the individual denominations */
   1322       json_array_foreach (denom_keys_array,
   1323                           index,
   1324                           denom_key_obj)
   1325       {
   1326         /* Set the common fields from the group for this particular
   1327            denomination.  Required to make the validity check inside
   1328            parse_json_denomkey_partially pass */
   1329         struct TALER_EXCHANGE_DenomPublicKey dk = {
   1330           .value = group.value,
   1331           .fees = group.fees,
   1332           .key.age_mask = group.age_mask
   1333         };
   1334         bool found = false;
   1335 
   1336         EXITIF (GNUNET_SYSERR ==
   1337                 parse_json_denomkey_partially (&dk,
   1338                                                group.cipher,
   1339                                                check_sig,
   1340                                                denom_key_obj,
   1341                                                &key_data->master_pub,
   1342                                                group_idx,
   1343                                                index,
   1344                                                check_sig
   1345                                                ? &sig_ctx
   1346                                                : NULL));
   1347         for (unsigned int j = 0;
   1348              j<key_data->num_denom_keys;
   1349              j++)
   1350         {
   1351           if (0 == denoms_cmp (&dk,
   1352                                &key_data->denom_keys[j]))
   1353           {
   1354             found = true;
   1355             break;
   1356           }
   1357         }
   1358 
   1359         if (found)
   1360         {
   1361           /* 0:0:0 did not support /keys cherry picking */
   1362           TALER_LOG_DEBUG ("Skipping denomination key: already know it\n");
   1363           TALER_denom_pub_free (&dk.key);
   1364           continue;
   1365         }
   1366 
   1367         if (key_data->denom_keys_size == key_data->num_denom_keys)
   1368           GNUNET_array_grow (key_data->denom_keys,
   1369                              key_data->denom_keys_size,
   1370                              key_data->denom_keys_size * 2 + 2);
   1371         GNUNET_assert (key_data->denom_keys_size >
   1372                        key_data->num_denom_keys);
   1373         GNUNET_assert (key_data->num_denom_keys < UINT_MAX);
   1374         key_data->denom_keys[key_data->num_denom_keys++] = dk;
   1375 
   1376         /* Update "last_denom_issue_date" */
   1377         TALER_LOG_DEBUG ("Adding denomination key that is valid_until %s\n",
   1378                          GNUNET_TIME_timestamp2s (dk.valid_from));
   1379         key_data->last_denom_issue_date
   1380           = GNUNET_TIME_timestamp_max (key_data->last_denom_issue_date,
   1381                                        dk.valid_from);
   1382       };   /* end of json_array_foreach over denominations */
   1383     } /* end of json_array_foreach over groups of denominations */
   1384   } /* end of scope for group_ojb/group_idx */
   1385 
   1386   /* parse the auditor information */
   1387   {
   1388     json_t *auditor_info;
   1389     unsigned int index;
   1390 
   1391     /* Merge with the existing auditor information we have (/keys cherry picking) */
   1392     json_array_foreach (auditors_array, index, auditor_info)
   1393     {
   1394       struct TALER_EXCHANGE_AuditorInformation ai;
   1395       bool found = false;
   1396 
   1397       memset (&ai,
   1398               0,
   1399               sizeof (ai));
   1400       EXITIF (GNUNET_SYSERR ==
   1401               parse_json_auditor (&ai,
   1402                                   check_sig,
   1403                                   auditor_info,
   1404                                   key_data));
   1405       for (unsigned int j = 0; j<key_data->num_auditors; j++)
   1406       {
   1407         struct TALER_EXCHANGE_AuditorInformation *aix = &key_data->auditors[j];
   1408 
   1409         if (0 == GNUNET_memcmp (&ai.auditor_pub,
   1410                                 &aix->auditor_pub))
   1411         {
   1412           found = true;
   1413           /* Merge denomination key signatures of downloaded /keys into existing
   1414              auditor information 'aix'. */
   1415           TALER_LOG_DEBUG (
   1416             "Merging %u new audited keys with %u known audited keys\n",
   1417             aix->num_denom_keys,
   1418             ai.num_denom_keys);
   1419           for (unsigned int i = 0; i<ai.num_denom_keys; i++)
   1420           {
   1421             bool kfound = false;
   1422 
   1423             for (unsigned int k = 0; k<aix->num_denom_keys; k++)
   1424             {
   1425               if (aix->denom_keys[k].denom_key_offset ==
   1426                   ai.denom_keys[i].denom_key_offset)
   1427               {
   1428                 kfound = true;
   1429                 break;
   1430               }
   1431             }
   1432             if (! kfound)
   1433               GNUNET_array_append (aix->denom_keys,
   1434                                    aix->num_denom_keys,
   1435                                    ai.denom_keys[i]);
   1436           }
   1437           break;
   1438         }
   1439       }
   1440       if (found)
   1441       {
   1442         GNUNET_array_grow (ai.denom_keys,
   1443                            ai.num_denom_keys,
   1444                            0);
   1445         GNUNET_free (ai.auditor_url);
   1446         GNUNET_free (ai.auditor_name);
   1447         continue; /* we are done */
   1448       }
   1449       if (key_data->auditors_size == key_data->num_auditors)
   1450         GNUNET_array_grow (key_data->auditors,
   1451                            key_data->auditors_size,
   1452                            key_data->auditors_size * 2 + 2);
   1453       GNUNET_assert (key_data->auditors_size >
   1454                      key_data->num_auditors);
   1455       GNUNET_assert (NULL != ai.auditor_url);
   1456       GNUNET_assert (key_data->num_auditors < UINT_MAX);
   1457       key_data->auditors[key_data->num_auditors++] = ai;
   1458     };
   1459   }
   1460 
   1461   /* parse the revocation/recoup information */
   1462   if (NULL != recoup_array)
   1463   {
   1464     json_t *recoup_info;
   1465     unsigned int index;
   1466 
   1467     json_array_foreach (recoup_array, index, recoup_info)
   1468     {
   1469       struct TALER_DenominationHashP h_denom_pub;
   1470       struct GNUNET_JSON_Specification spec[] = {
   1471         GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
   1472                                      &h_denom_pub),
   1473         GNUNET_JSON_spec_end ()
   1474       };
   1475 
   1476       EXITIF (GNUNET_OK !=
   1477               GNUNET_JSON_parse (recoup_info,
   1478                                  spec,
   1479                                  NULL, NULL));
   1480       for (unsigned int j = 0;
   1481            j<key_data->num_denom_keys;
   1482            j++)
   1483       {
   1484         if (0 == GNUNET_memcmp (&h_denom_pub,
   1485                                 &key_data->denom_keys[j].h_key))
   1486         {
   1487           key_data->denom_keys[j].revoked = true;
   1488           break;
   1489         }
   1490       }
   1491     }
   1492   }
   1493 
   1494   if (check_sig)
   1495   {
   1496     struct GNUNET_HashContext *hash_context;
   1497     struct GNUNET_HashCode hc;
   1498 
   1499     hash_context = GNUNET_CRYPTO_hash_context_start ();
   1500     qsort (sig_ctx.elements,
   1501            sig_ctx.elements_pos,
   1502            sizeof (struct SignatureElement),
   1503            &signature_context_sort_cb);
   1504     for (unsigned int i = 0; i<sig_ctx.elements_pos; i++)
   1505     {
   1506       struct SignatureElement *element = &sig_ctx.elements[i];
   1507 
   1508       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1509                   "Adding %u,%u,%s\n",
   1510                   element->group_offset,
   1511                   element->offset,
   1512                   TALER_B2S (&element->master_sig));
   1513       GNUNET_CRYPTO_hash_context_read (hash_context,
   1514                                        &element->master_sig,
   1515                                        sizeof (element->master_sig));
   1516     }
   1517     GNUNET_array_grow (sig_ctx.elements,
   1518                        sig_ctx.elements_size,
   1519                        0);
   1520     GNUNET_CRYPTO_hash_context_finish (hash_context,
   1521                                        &hc);
   1522     EXITIF (GNUNET_OK !=
   1523             TALER_EXCHANGE_test_signing_key (key_data,
   1524                                              &exchange_pub));
   1525     EXITIF (GNUNET_OK !=
   1526             TALER_exchange_online_key_set_verify (
   1527               key_data->list_issue_date,
   1528               &hc,
   1529               &exchange_pub,
   1530               &exchange_sig));
   1531   }
   1532   return GNUNET_OK;
   1533 
   1534 EXITIF_exit:
   1535   *vc = TALER_EXCHANGE_VC_PROTOCOL_ERROR;
   1536   return GNUNET_SYSERR;
   1537 }
   1538 
   1539 
   1540 enum GNUNET_GenericReturnValue
   1541 TALER_EXCHANGE_test_signing_key (
   1542   const struct TALER_EXCHANGE_Keys *keys,
   1543   const struct TALER_ExchangePublicKeyP *pub)
   1544 {
   1545   struct GNUNET_TIME_Absolute now;
   1546 
   1547   /* we will check using a tolerance of 1h for the time */
   1548   now = GNUNET_TIME_absolute_get ();
   1549   for (unsigned int i = 0; i<keys->num_sign_keys; i++)
   1550     if ( (GNUNET_TIME_absolute_cmp (
   1551             keys->sign_keys[i].valid_from.abs_time,
   1552             <=,
   1553             GNUNET_TIME_absolute_add (now,
   1554                                       LIFETIME_TOLERANCE))) &&
   1555          (GNUNET_TIME_absolute_cmp (
   1556             keys->sign_keys[i].valid_until.abs_time,
   1557             >,
   1558             GNUNET_TIME_absolute_subtract (now,
   1559                                            LIFETIME_TOLERANCE))) &&
   1560          (0 == GNUNET_memcmp (pub,
   1561                               &keys->sign_keys[i].key)) )
   1562       return GNUNET_OK;
   1563   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1564               "Signing key not valid at time %s\n",
   1565               GNUNET_TIME_absolute2s (now));
   1566   return GNUNET_SYSERR;
   1567 }
   1568 
   1569 
   1570 const struct TALER_EXCHANGE_DenomPublicKey *
   1571 TALER_EXCHANGE_get_denomination_key (
   1572   const struct TALER_EXCHANGE_Keys *keys,
   1573   const struct TALER_DenominationPublicKey *pk)
   1574 {
   1575   for (unsigned int i = 0; i<keys->num_denom_keys; i++)
   1576     if (0 ==
   1577         TALER_denom_pub_cmp (pk,
   1578                              &keys->denom_keys[i].key))
   1579       return &keys->denom_keys[i];
   1580   return NULL;
   1581 }
   1582 
   1583 
   1584 const struct TALER_EXCHANGE_GlobalFee *
   1585 TALER_EXCHANGE_get_global_fee (
   1586   const struct TALER_EXCHANGE_Keys *keys,
   1587   struct GNUNET_TIME_Timestamp ts)
   1588 {
   1589   for (unsigned int i = 0; i<keys->num_global_fees; i++)
   1590   {
   1591     const struct TALER_EXCHANGE_GlobalFee *gf = &keys->global_fees[i];
   1592 
   1593     if (GNUNET_TIME_timestamp_cmp (ts,
   1594                                    >=,
   1595                                    gf->start_date) &&
   1596         GNUNET_TIME_timestamp_cmp (ts,
   1597                                    <,
   1598                                    gf->end_date))
   1599       return gf;
   1600   }
   1601   return NULL;
   1602 }
   1603 
   1604 
   1605 struct TALER_EXCHANGE_DenomPublicKey *
   1606 TALER_EXCHANGE_copy_denomination_key (
   1607   const struct TALER_EXCHANGE_DenomPublicKey *key)
   1608 {
   1609   struct TALER_EXCHANGE_DenomPublicKey *copy;
   1610 
   1611   copy = GNUNET_new (struct TALER_EXCHANGE_DenomPublicKey);
   1612   *copy = *key;
   1613   TALER_denom_pub_copy (&copy->key,
   1614                         &key->key);
   1615   return copy;
   1616 }
   1617 
   1618 
   1619 void
   1620 TALER_EXCHANGE_destroy_denomination_key (
   1621   struct TALER_EXCHANGE_DenomPublicKey *key)
   1622 {
   1623   TALER_denom_pub_free (&key->key);
   1624   GNUNET_free (key);
   1625 }
   1626 
   1627 
   1628 const struct TALER_EXCHANGE_DenomPublicKey *
   1629 TALER_EXCHANGE_get_denomination_key_by_hash (
   1630   const struct TALER_EXCHANGE_Keys *keys,
   1631   const struct TALER_DenominationHashP *hc)
   1632 {
   1633   /* FIXME-optimization: should we maybe use a hash map here? */
   1634   for (unsigned int i = 0; i<keys->num_denom_keys; i++)
   1635     if (0 == GNUNET_memcmp (hc,
   1636                             &keys->denom_keys[i].h_key))
   1637       return &keys->denom_keys[i];
   1638   return NULL;
   1639 }
   1640 
   1641 
   1642 struct TALER_EXCHANGE_Keys *
   1643 TALER_EXCHANGE_keys_incref (struct TALER_EXCHANGE_Keys *keys)
   1644 {
   1645   GNUNET_assert (keys->rc < UINT_MAX);
   1646   keys->rc++;
   1647   return keys;
   1648 }
   1649 
   1650 
   1651 void
   1652 TALER_EXCHANGE_keys_decref (struct TALER_EXCHANGE_Keys *keys)
   1653 {
   1654   if (NULL == keys)
   1655     return;
   1656   GNUNET_assert (0 < keys->rc);
   1657   keys->rc--;
   1658   if (0 != keys->rc)
   1659     return;
   1660   GNUNET_array_grow (keys->sign_keys,
   1661                      keys->num_sign_keys,
   1662                      0);
   1663   for (unsigned int i = 0; i<keys->num_denom_keys; i++)
   1664     TALER_denom_pub_free (&keys->denom_keys[i].key);
   1665   keys->num_denom_keys = 0;
   1666   GNUNET_array_grow (keys->denom_keys,
   1667                      keys->denom_keys_size,
   1668                      0);
   1669   for (unsigned int i = 0; i<keys->num_auditors; i++)
   1670   {
   1671     GNUNET_array_grow (keys->auditors[i].denom_keys,
   1672                        keys->auditors[i].num_denom_keys,
   1673                        0);
   1674     GNUNET_free (keys->auditors[i].auditor_url);
   1675     GNUNET_free (keys->auditors[i].auditor_name);
   1676   }
   1677   GNUNET_array_grow (keys->auditors,
   1678                      keys->auditors_size,
   1679                      0);
   1680   TALER_EXCHANGE_free_accounts (keys->accounts_len,
   1681                                 keys->accounts);
   1682   GNUNET_array_grow (keys->accounts,
   1683                      keys->accounts_len,
   1684                      0);
   1685   free_fees (keys->fees,
   1686              keys->fees_len);
   1687   GNUNET_array_grow (keys->hard_limits,
   1688                      keys->hard_limits_length,
   1689                      0);
   1690   GNUNET_array_grow (keys->zero_limits,
   1691                      keys->zero_limits_length,
   1692                      0);
   1693   json_decref (keys->extensions);
   1694   GNUNET_free (keys->cspec.name);
   1695   json_decref (keys->cspec.map_alt_unit_names);
   1696   GNUNET_array_grow (keys->cspec.common_amounts,
   1697                      keys->cspec.num_common_amounts,
   1698                      0);
   1699   GNUNET_free (keys->wallet_balance_limit_without_kyc);
   1700   GNUNET_free (keys->version);
   1701   GNUNET_free (keys->currency);
   1702   GNUNET_free (keys->asset_type);
   1703   GNUNET_free (keys->shopping_url);
   1704   GNUNET_free (keys->bank_compliance_language);
   1705   for (unsigned int i = 0; i < keys->num_wad_partners; i++)
   1706     GNUNET_free (keys->wad_partners[i].partner_base_url);
   1707   GNUNET_free (keys->wad_partners);
   1708   GNUNET_free (keys->global_fees);
   1709   GNUNET_free (keys->exchange_url);
   1710   GNUNET_free (keys);
   1711 }
   1712 
   1713 
   1714 struct TALER_EXCHANGE_Keys *
   1715 TALER_EXCHANGE_keys_from_json (const json_t *j)
   1716 {
   1717   const json_t *jkeys;
   1718   const char *url;
   1719   uint32_t version;
   1720   struct GNUNET_TIME_Timestamp expire
   1721     = GNUNET_TIME_UNIT_ZERO_TS;
   1722   struct GNUNET_JSON_Specification spec[] = {
   1723     GNUNET_JSON_spec_uint32 ("version",
   1724                              &version),
   1725     GNUNET_JSON_spec_object_const ("keys",
   1726                                    &jkeys),
   1727     TALER_JSON_spec_web_url ("exchange_url",
   1728                              &url),
   1729     GNUNET_JSON_spec_mark_optional (
   1730       GNUNET_JSON_spec_timestamp ("expire",
   1731                                   &expire),
   1732       NULL),
   1733     GNUNET_JSON_spec_end ()
   1734   };
   1735   struct TALER_EXCHANGE_Keys *keys;
   1736   enum TALER_EXCHANGE_VersionCompatibility compat;
   1737 
   1738   if (NULL == j)
   1739     return NULL;
   1740   if (GNUNET_OK !=
   1741       GNUNET_JSON_parse (j,
   1742                          spec,
   1743                          NULL, NULL))
   1744   {
   1745     GNUNET_break_op (0);
   1746     return NULL;
   1747   }
   1748   if (0 != version)
   1749   {
   1750     return NULL; /* unsupported version */
   1751   }
   1752   keys = GNUNET_new (struct TALER_EXCHANGE_Keys);
   1753   if (GNUNET_OK !=
   1754       TALER_EXCHANGE_decode_keys_json_ (jkeys,
   1755                                         false,
   1756                                         keys,
   1757                                         &compat))
   1758   {
   1759     GNUNET_break (0);
   1760     return NULL;
   1761   }
   1762   keys->rc = 1;
   1763   keys->key_data_expiration = expire;
   1764   keys->exchange_url = GNUNET_strdup (url);
   1765   return keys;
   1766 }
   1767 
   1768 
   1769 /**
   1770  * Data we track per denomination group.
   1771  */
   1772 struct GroupData
   1773 {
   1774   /**
   1775    * The json blob with the group meta-data and list of denominations
   1776    */
   1777   json_t *json;
   1778 
   1779   /**
   1780    * Meta data for this group.
   1781    */
   1782   struct TALER_DenominationGroup meta;
   1783 };
   1784 
   1785 
   1786 /**
   1787  * Add denomination group represented by @a value
   1788  * to list of denominations in @a cls. Also frees
   1789  * the @a value.
   1790  *
   1791  * @param[in,out] cls a `json_t *` with an array to build
   1792  * @param key unused
   1793  * @param value a `struct GroupData *`
   1794  * @return #GNUNET_OK (continue to iterate)
   1795  */
   1796 static enum GNUNET_GenericReturnValue
   1797 add_grp (void *cls,
   1798          const struct GNUNET_HashCode *key,
   1799          void *value)
   1800 {
   1801   json_t *denominations_by_group = cls;
   1802   struct GroupData *gd = value;
   1803   const char *cipher;
   1804   json_t *ge;
   1805   bool age_restricted = gd->meta.age_mask.bits != 0;
   1806 
   1807   (void) key;
   1808   switch (gd->meta.cipher)
   1809   {
   1810   case GNUNET_CRYPTO_BSA_RSA:
   1811     cipher = age_restricted ? "RSA+age_restricted" : "RSA";
   1812     break;
   1813   case GNUNET_CRYPTO_BSA_CS:
   1814     cipher = age_restricted ? "CS+age_restricted" : "CS";
   1815     break;
   1816   default:
   1817     GNUNET_assert (false);
   1818   }
   1819 
   1820   ge = GNUNET_JSON_PACK (
   1821     GNUNET_JSON_pack_string ("cipher",
   1822                              cipher),
   1823     GNUNET_JSON_pack_array_steal ("denoms",
   1824                                   gd->json),
   1825     TALER_JSON_PACK_DENOM_FEES ("fee",
   1826                                 &gd->meta.fees),
   1827     GNUNET_JSON_pack_allow_null (
   1828       age_restricted
   1829           ? GNUNET_JSON_pack_uint64 ("age_mask",
   1830                                      gd->meta.age_mask.bits)
   1831           : GNUNET_JSON_pack_string ("dummy",
   1832                                      NULL)),
   1833     TALER_JSON_pack_amount ("value",
   1834                             &gd->meta.value));
   1835   GNUNET_assert (0 ==
   1836                  json_array_append_new (denominations_by_group,
   1837                                         ge));
   1838   GNUNET_free (gd);
   1839   return GNUNET_OK;
   1840 }
   1841 
   1842 
   1843 /**
   1844  * Convert array of account restrictions @a ars to JSON.
   1845  *
   1846  * @param ar_len length of @a ars
   1847  * @param ars account restrictions to convert
   1848  * @return JSON representation
   1849  */
   1850 static json_t *
   1851 ar_to_json (unsigned int ar_len,
   1852             const struct TALER_EXCHANGE_AccountRestriction ars[static ar_len])
   1853 {
   1854   json_t *rval;
   1855 
   1856   rval = json_array ();
   1857   GNUNET_assert (NULL != rval);
   1858   for (unsigned int i = 0; i<ar_len; i++)
   1859   {
   1860     const struct TALER_EXCHANGE_AccountRestriction *ar = &ars[i];
   1861 
   1862     switch (ar->type)
   1863     {
   1864     case TALER_EXCHANGE_AR_INVALID:
   1865       GNUNET_break (0);
   1866       json_decref (rval);
   1867       return NULL;
   1868     case TALER_EXCHANGE_AR_DENY:
   1869       GNUNET_assert (
   1870         0 ==
   1871         json_array_append_new (
   1872           rval,
   1873           GNUNET_JSON_PACK (
   1874             GNUNET_JSON_pack_string ("type",
   1875                                      "deny"))));
   1876       break;
   1877     case TALER_EXCHANGE_AR_REGEX:
   1878       GNUNET_assert (
   1879         0 ==
   1880         json_array_append_new (
   1881           rval,
   1882           GNUNET_JSON_PACK (
   1883             GNUNET_JSON_pack_string (
   1884               "type",
   1885               "regex"),
   1886             GNUNET_JSON_pack_string (
   1887               "payto_regex",
   1888               ar->details.regex.posix_egrep),
   1889             GNUNET_JSON_pack_string (
   1890               "human_hint",
   1891               ar->details.regex.human_hint),
   1892             GNUNET_JSON_pack_object_incref (
   1893               "human_hint_i18n",
   1894               (json_t *) ar->details.regex.human_hint_i18n)
   1895             )));
   1896       break;
   1897     }
   1898   }
   1899   return rval;
   1900 }
   1901 
   1902 
   1903 json_t *
   1904 TALER_EXCHANGE_keys_to_json (const struct TALER_EXCHANGE_Keys *kd)
   1905 {
   1906   struct GNUNET_TIME_Timestamp now;
   1907   json_t *keys;
   1908   json_t *signkeys;
   1909   json_t *denominations_by_group;
   1910   json_t *auditors;
   1911   json_t *recoup;
   1912   json_t *wire_fees;
   1913   json_t *accounts;
   1914   json_t *global_fees;
   1915   json_t *wblwk = NULL;
   1916   json_t *wads_json;
   1917   json_t *hard_limits;
   1918   json_t *zero_limits;
   1919 
   1920   now = GNUNET_TIME_timestamp_get ();
   1921   signkeys = json_array ();
   1922   GNUNET_assert (NULL != signkeys);
   1923   for (unsigned int i = 0; i<kd->num_sign_keys; i++)
   1924   {
   1925     const struct TALER_EXCHANGE_SigningPublicKey *sk = &kd->sign_keys[i];
   1926     json_t *signkey;
   1927 
   1928     if (GNUNET_TIME_timestamp_cmp (now,
   1929                                    >,
   1930                                    sk->valid_until))
   1931       continue; /* skip keys that have expired */
   1932     signkey = GNUNET_JSON_PACK (
   1933       GNUNET_JSON_pack_data_auto ("key",
   1934                                   &sk->key),
   1935       GNUNET_JSON_pack_data_auto ("master_sig",
   1936                                   &sk->master_sig),
   1937       GNUNET_JSON_pack_timestamp ("stamp_start",
   1938                                   sk->valid_from),
   1939       GNUNET_JSON_pack_timestamp ("stamp_expire",
   1940                                   sk->valid_until),
   1941       GNUNET_JSON_pack_timestamp ("stamp_end",
   1942                                   sk->valid_legal));
   1943     GNUNET_assert (NULL != signkey);
   1944     GNUNET_assert (0 ==
   1945                    json_array_append_new (signkeys,
   1946                                           signkey));
   1947   }
   1948 
   1949   denominations_by_group = json_array ();
   1950   GNUNET_assert (NULL != denominations_by_group);
   1951   {
   1952     struct GNUNET_CONTAINER_MultiHashMap *dbg;
   1953 
   1954     dbg = GNUNET_CONTAINER_multihashmap_create (128,
   1955                                                 false);
   1956     for (unsigned int i = 0; i<kd->num_denom_keys; i++)
   1957     {
   1958       const struct TALER_EXCHANGE_DenomPublicKey *dk = &kd->denom_keys[i];
   1959       struct TALER_DenominationGroup meta = {
   1960         .cipher = dk->key.bsign_pub_key->cipher,
   1961         .value = dk->value,
   1962         .fees = dk->fees,
   1963         .age_mask = dk->key.age_mask
   1964       };
   1965       struct GNUNET_HashCode key;
   1966       struct GroupData *gd;
   1967       json_t *denom;
   1968       struct GNUNET_JSON_PackSpec key_spec;
   1969 
   1970       if (GNUNET_TIME_timestamp_cmp (now,
   1971                                      >,
   1972                                      dk->expire_deposit))
   1973         continue; /* skip keys that have expired */
   1974       TALER_denomination_group_get_key (&meta,
   1975                                         &key);
   1976       gd = GNUNET_CONTAINER_multihashmap_get (dbg,
   1977                                               &key);
   1978       if (NULL == gd)
   1979       {
   1980         gd = GNUNET_new (struct GroupData);
   1981         gd->meta = meta;
   1982         gd->json = json_array ();
   1983         GNUNET_assert (NULL != gd->json);
   1984         GNUNET_assert (
   1985           GNUNET_OK ==
   1986           GNUNET_CONTAINER_multihashmap_put (dbg,
   1987                                              &key,
   1988                                              gd,
   1989                                              GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
   1990 
   1991       }
   1992       switch (meta.cipher)
   1993       {
   1994       case GNUNET_CRYPTO_BSA_RSA:
   1995         key_spec =
   1996           GNUNET_JSON_pack_rsa_public_key (
   1997             "rsa_pub",
   1998             dk->key.bsign_pub_key->details.rsa_public_key);
   1999         break;
   2000       case GNUNET_CRYPTO_BSA_CS:
   2001         key_spec =
   2002           GNUNET_JSON_pack_data_varsize (
   2003             "cs_pub",
   2004             &dk->key.bsign_pub_key->details.cs_public_key,
   2005             sizeof (dk->key.bsign_pub_key->details.cs_public_key));
   2006         break;
   2007       default:
   2008         GNUNET_assert (false);
   2009       }
   2010       denom = GNUNET_JSON_PACK (
   2011         GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
   2012                                     dk->expire_deposit),
   2013         GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
   2014                                     dk->withdraw_valid_until),
   2015         GNUNET_JSON_pack_timestamp ("stamp_start",
   2016                                     dk->valid_from),
   2017         GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
   2018                                     dk->expire_legal),
   2019         GNUNET_JSON_pack_data_auto ("master_sig",
   2020                                     &dk->master_sig),
   2021         key_spec
   2022         );
   2023       GNUNET_assert (0 ==
   2024                      json_array_append_new (gd->json,
   2025                                             denom));
   2026     }
   2027     GNUNET_CONTAINER_multihashmap_iterate (dbg,
   2028                                            &add_grp,
   2029                                            denominations_by_group);
   2030     GNUNET_CONTAINER_multihashmap_destroy (dbg);
   2031   }
   2032 
   2033   auditors = json_array ();
   2034   GNUNET_assert (NULL != auditors);
   2035   for (unsigned int i = 0; i<kd->num_auditors; i++)
   2036   {
   2037     const struct TALER_EXCHANGE_AuditorInformation *ai = &kd->auditors[i];
   2038     json_t *a;
   2039     json_t *adenoms;
   2040 
   2041     adenoms = json_array ();
   2042     GNUNET_assert (NULL != adenoms);
   2043     for (unsigned int j = 0; j<ai->num_denom_keys; j++)
   2044     {
   2045       const struct TALER_EXCHANGE_AuditorDenominationInfo *adi =
   2046         &ai->denom_keys[j];
   2047       const struct TALER_EXCHANGE_DenomPublicKey *dk =
   2048         &kd->denom_keys[adi->denom_key_offset];
   2049       json_t *k;
   2050 
   2051       GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys);
   2052       if (GNUNET_TIME_timestamp_cmp (now,
   2053                                      >,
   2054                                      dk->expire_deposit))
   2055         continue; /* skip auditor signatures for denomination keys that have expired */
   2056       GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys);
   2057       k = GNUNET_JSON_PACK (
   2058         GNUNET_JSON_pack_data_auto ("denom_pub_h",
   2059                                     &dk->h_key),
   2060         GNUNET_JSON_pack_data_auto ("auditor_sig",
   2061                                     &adi->auditor_sig));
   2062       GNUNET_assert (0 ==
   2063                      json_array_append_new (adenoms,
   2064                                             k));
   2065     }
   2066 
   2067     a = GNUNET_JSON_PACK (
   2068       GNUNET_JSON_pack_data_auto ("auditor_pub",
   2069                                   &ai->auditor_pub),
   2070       GNUNET_JSON_pack_string ("auditor_url",
   2071                                ai->auditor_url),
   2072       GNUNET_JSON_pack_string ("auditor_name",
   2073                                ai->auditor_name),
   2074       GNUNET_JSON_pack_array_steal ("denomination_keys",
   2075                                     adenoms));
   2076     GNUNET_assert (0 ==
   2077                    json_array_append_new (auditors,
   2078                                           a));
   2079   }
   2080 
   2081   global_fees = json_array ();
   2082   GNUNET_assert (NULL != global_fees);
   2083   for (unsigned int i = 0; i<kd->num_global_fees; i++)
   2084   {
   2085     const struct TALER_EXCHANGE_GlobalFee *gf
   2086       = &kd->global_fees[i];
   2087 
   2088     if (GNUNET_TIME_absolute_is_past (gf->end_date.abs_time))
   2089       continue;
   2090     GNUNET_assert (
   2091       0 ==
   2092       json_array_append_new (
   2093         global_fees,
   2094         GNUNET_JSON_PACK (
   2095           GNUNET_JSON_pack_timestamp ("start_date",
   2096                                       gf->start_date),
   2097           GNUNET_JSON_pack_timestamp ("end_date",
   2098                                       gf->end_date),
   2099           TALER_JSON_PACK_GLOBAL_FEES (&gf->fees),
   2100           GNUNET_JSON_pack_time_rel ("history_expiration",
   2101                                      gf->history_expiration),
   2102           GNUNET_JSON_pack_time_rel ("purse_timeout",
   2103                                      gf->purse_timeout),
   2104           GNUNET_JSON_pack_uint64 ("purse_account_limit",
   2105                                    gf->purse_account_limit),
   2106           GNUNET_JSON_pack_data_auto ("master_sig",
   2107                                       &gf->master_sig))));
   2108   }
   2109 
   2110   accounts = json_array ();
   2111   GNUNET_assert (NULL != accounts);
   2112   for (unsigned int i = 0; i<kd->accounts_len; i++)
   2113   {
   2114     const struct TALER_EXCHANGE_WireAccount *acc
   2115       = &kd->accounts[i];
   2116     json_t *credit_restrictions;
   2117     json_t *debit_restrictions;
   2118 
   2119     credit_restrictions
   2120       = ar_to_json (acc->credit_restrictions_length,
   2121                     acc->credit_restrictions);
   2122     GNUNET_assert (NULL != credit_restrictions);
   2123     debit_restrictions
   2124       = ar_to_json (acc->debit_restrictions_length,
   2125                     acc->debit_restrictions);
   2126     GNUNET_assert (NULL != debit_restrictions);
   2127     GNUNET_assert (
   2128       0 ==
   2129       json_array_append_new (
   2130         accounts,
   2131         GNUNET_JSON_PACK (
   2132           TALER_JSON_pack_full_payto ("payto_uri",
   2133                                       acc->fpayto_uri),
   2134           GNUNET_JSON_pack_allow_null (
   2135             GNUNET_JSON_pack_string ("conversion_url",
   2136                                      acc->conversion_url)),
   2137           GNUNET_JSON_pack_allow_null (
   2138             GNUNET_JSON_pack_string ("open_banking_gateway",
   2139                                      acc->open_banking_gateway)),
   2140           GNUNET_JSON_pack_allow_null (
   2141             GNUNET_JSON_pack_string ("wire_transfer_gateway",
   2142                                      acc->wire_transfer_gateway)),
   2143           GNUNET_JSON_pack_int64 ("priority",
   2144                                   acc->priority),
   2145           GNUNET_JSON_pack_allow_null (
   2146             GNUNET_JSON_pack_string ("bank_label",
   2147                                      acc->bank_label)),
   2148           GNUNET_JSON_pack_array_steal ("debit_restrictions",
   2149                                         debit_restrictions),
   2150           GNUNET_JSON_pack_array_steal ("credit_restrictions",
   2151                                         credit_restrictions),
   2152           GNUNET_JSON_pack_data_auto ("master_sig",
   2153                                       &acc->master_sig))));
   2154   }
   2155   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2156               "Serialized %u/%u wire accounts to JSON\n",
   2157               (unsigned int) json_array_size (accounts),
   2158               kd->accounts_len);
   2159 
   2160   wire_fees = json_object ();
   2161   GNUNET_assert (NULL != wire_fees);
   2162   for (unsigned int i = 0; i<kd->fees_len; i++)
   2163   {
   2164     const struct TALER_EXCHANGE_WireFeesByMethod *fbw
   2165       = &kd->fees[i];
   2166     json_t *wf;
   2167 
   2168     wf = json_array ();
   2169     GNUNET_assert (NULL != wf);
   2170     for (struct TALER_EXCHANGE_WireAggregateFees *p = fbw->fees_head;
   2171          NULL != p;
   2172          p = p->next)
   2173     {
   2174       GNUNET_assert (
   2175         0 ==
   2176         json_array_append_new (
   2177           wf,
   2178           GNUNET_JSON_PACK (
   2179             TALER_JSON_pack_amount ("wire_fee",
   2180                                     &p->fees.wire),
   2181             TALER_JSON_pack_amount ("closing_fee",
   2182                                     &p->fees.closing),
   2183             GNUNET_JSON_pack_timestamp ("start_date",
   2184                                         p->start_date),
   2185             GNUNET_JSON_pack_timestamp ("end_date",
   2186                                         p->end_date),
   2187             GNUNET_JSON_pack_data_auto ("sig",
   2188                                         &p->master_sig))));
   2189     }
   2190     GNUNET_assert (0 ==
   2191                    json_object_set_new (wire_fees,
   2192                                         fbw->method,
   2193                                         wf));
   2194   }
   2195 
   2196   recoup = json_array ();
   2197   GNUNET_assert (NULL != recoup);
   2198   for (unsigned int i = 0; i<kd->num_denom_keys; i++)
   2199   {
   2200     const struct TALER_EXCHANGE_DenomPublicKey *dk
   2201       = &kd->denom_keys[i];
   2202     if (! dk->revoked)
   2203       continue;
   2204     GNUNET_assert (0 ==
   2205                    json_array_append_new (
   2206                      recoup,
   2207                      GNUNET_JSON_PACK (
   2208                        GNUNET_JSON_pack_data_auto ("h_denom_pub",
   2209                                                    &dk->h_key))));
   2210   }
   2211 
   2212   wblwk = json_array ();
   2213   GNUNET_assert (NULL != wblwk);
   2214   for (unsigned int i = 0; i<kd->wblwk_length; i++)
   2215   {
   2216     const struct TALER_Amount *a = &kd->wallet_balance_limit_without_kyc[i];
   2217 
   2218     GNUNET_assert (0 ==
   2219                    json_array_append_new (
   2220                      wblwk,
   2221                      TALER_JSON_from_amount (a)));
   2222   }
   2223 
   2224   hard_limits = json_array ();
   2225   for (unsigned int i = 0; i < kd->hard_limits_length; i++)
   2226   {
   2227     const struct TALER_EXCHANGE_AccountLimit *al
   2228       = &kd->hard_limits[i];
   2229     json_t *j;
   2230 
   2231     j = GNUNET_JSON_PACK (
   2232       TALER_JSON_pack_amount ("threshold",
   2233                               &al->threshold),
   2234       GNUNET_JSON_pack_time_rel ("timeframe",
   2235                                  al->timeframe),
   2236       TALER_JSON_pack_kycte ("operation_type",
   2237                              al->operation_type),
   2238       GNUNET_JSON_pack_bool ("soft_limit",
   2239                              al->soft_limit)
   2240       );
   2241     GNUNET_assert (0 ==
   2242                    json_array_append_new (
   2243                      hard_limits,
   2244                      j));
   2245   }
   2246 
   2247   zero_limits = json_array ();
   2248   for (unsigned int i = 0; i < kd->zero_limits_length; i++)
   2249   {
   2250     const struct TALER_EXCHANGE_ZeroLimitedOperation *zol
   2251       = &kd->zero_limits[i];
   2252     json_t *j;
   2253 
   2254     j = GNUNET_JSON_PACK (
   2255       TALER_JSON_pack_kycte ("operation_type",
   2256                              zol->operation_type)
   2257       );
   2258     GNUNET_assert (0 ==
   2259                    json_array_append_new (
   2260                      zero_limits,
   2261                      j));
   2262   }
   2263 
   2264   wads_json = json_array ();
   2265   GNUNET_assert (NULL != wads_json);
   2266   for (unsigned int i = 0; i < kd->num_wad_partners; i++)
   2267   {
   2268     const struct TALER_EXCHANGE_WadPartner *wp
   2269       = &kd->wad_partners[i];
   2270 
   2271     GNUNET_assert (
   2272       0 ==
   2273       json_array_append_new (
   2274         wads_json,
   2275         GNUNET_JSON_PACK (
   2276           GNUNET_JSON_pack_string ("partner_base_url",
   2277                                    wp->partner_base_url),
   2278           GNUNET_JSON_pack_data_auto ("partner_master_pub",
   2279                                       &wp->partner_master_pub),
   2280           TALER_JSON_pack_amount ("wad_fee",
   2281                                   &wp->wad_fee),
   2282           GNUNET_JSON_pack_time_rel ("wad_frequency",
   2283                                      wp->wad_frequency),
   2284           GNUNET_JSON_pack_timestamp ("start_date",
   2285                                       wp->start_date),
   2286           GNUNET_JSON_pack_timestamp ("end_date",
   2287                                       wp->end_date),
   2288           GNUNET_JSON_pack_data_auto ("master_sig",
   2289                                       &wp->master_sig))));
   2290   }
   2291 
   2292   keys = GNUNET_JSON_PACK (
   2293     GNUNET_JSON_pack_string ("version",
   2294                              kd->version),
   2295     GNUNET_JSON_pack_string ("currency",
   2296                              kd->currency),
   2297     GNUNET_JSON_pack_object_steal ("currency_specification",
   2298                                    TALER_JSON_currency_specs_to_json (
   2299                                      &kd->cspec)),
   2300     TALER_JSON_pack_amount ("stefan_abs",
   2301                             &kd->stefan_abs),
   2302     TALER_JSON_pack_amount ("stefan_log",
   2303                             &kd->stefan_log),
   2304     GNUNET_JSON_pack_double ("stefan_lin",
   2305                              kd->stefan_lin),
   2306     GNUNET_JSON_pack_allow_null (
   2307       kd->tiny_amount_available
   2308       ? TALER_JSON_pack_amount ("tiny_amount",
   2309                                 &kd->tiny_amount)
   2310       : GNUNET_JSON_pack_string ("dummy",
   2311                                  NULL)),
   2312     GNUNET_JSON_pack_string ("asset_type",
   2313                              kd->asset_type),
   2314     GNUNET_JSON_pack_allow_null (
   2315       GNUNET_JSON_pack_string ("shopping_url",
   2316                                kd->shopping_url)),
   2317     GNUNET_JSON_pack_allow_null (
   2318       GNUNET_JSON_pack_string ("bank_compliance_language",
   2319                                kd->bank_compliance_language)),
   2320     GNUNET_JSON_pack_bool ("disable_direct_deposit",
   2321                            kd->disable_direct_deposit),
   2322     GNUNET_JSON_pack_data_auto ("master_public_key",
   2323                                 &kd->master_pub),
   2324     GNUNET_JSON_pack_time_rel ("reserve_closing_delay",
   2325                                kd->reserve_closing_delay),
   2326     GNUNET_JSON_pack_allow_null (
   2327       GNUNET_TIME_relative_is_zero (kd->default_p2p_push_expiration)
   2328       ? GNUNET_JSON_pack_string ("dummy",
   2329                                  NULL)
   2330       : GNUNET_JSON_pack_time_rel ("default_p2p_push_expiration",
   2331                                    kd->default_p2p_push_expiration)),
   2332     GNUNET_JSON_pack_timestamp ("list_issue_date",
   2333                                 kd->list_issue_date),
   2334     GNUNET_JSON_pack_array_steal ("global_fees",
   2335                                   global_fees),
   2336     GNUNET_JSON_pack_array_steal ("signkeys",
   2337                                   signkeys),
   2338     GNUNET_JSON_pack_object_steal ("wire_fees",
   2339                                    wire_fees),
   2340     GNUNET_JSON_pack_array_steal ("accounts",
   2341                                   accounts),
   2342     GNUNET_JSON_pack_array_steal ("wads",
   2343                                   wads_json),
   2344     GNUNET_JSON_pack_array_steal ("hard_limits",
   2345                                   hard_limits),
   2346     GNUNET_JSON_pack_array_steal ("zero_limits",
   2347                                   zero_limits),
   2348     GNUNET_JSON_pack_array_steal ("denominations",
   2349                                   denominations_by_group),
   2350     GNUNET_JSON_pack_allow_null (
   2351       GNUNET_JSON_pack_array_steal ("recoup",
   2352                                     recoup)),
   2353     GNUNET_JSON_pack_array_steal ("auditors",
   2354                                   auditors),
   2355     GNUNET_JSON_pack_bool ("kyc_enabled",
   2356                            kd->kyc_enabled),
   2357     GNUNET_JSON_pack_allow_null (
   2358       GNUNET_JSON_pack_object_incref ("extensions",
   2359                                       kd->extensions)),
   2360     GNUNET_JSON_pack_allow_null (
   2361       GNUNET_is_zero (&kd->extensions_sig)
   2362       ? GNUNET_JSON_pack_string ("dummy",
   2363                                  NULL)
   2364       : GNUNET_JSON_pack_data_auto ("extensions_sig",
   2365                                     &kd->extensions_sig)),
   2366     GNUNET_JSON_pack_allow_null (
   2367       GNUNET_JSON_pack_array_steal ("wallet_balance_limit_without_kyc",
   2368                                     wblwk))
   2369 
   2370     );
   2371   return GNUNET_JSON_PACK (
   2372     GNUNET_JSON_pack_uint64 ("version",
   2373                              EXCHANGE_SERIALIZATION_FORMAT_VERSION),
   2374     GNUNET_JSON_pack_allow_null (
   2375       GNUNET_JSON_pack_timestamp ("expire",
   2376                                   kd->key_data_expiration)),
   2377     GNUNET_JSON_pack_string ("exchange_url",
   2378                              kd->exchange_url),
   2379     GNUNET_JSON_pack_object_steal ("keys",
   2380                                    keys));
   2381 }
   2382 
   2383 
   2384 /* end of exchange_api_handle.c */