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


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