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


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