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


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