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


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