LCOV - code coverage report
Current view: top level - lib - exchange_api_handle.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 72.9 % 760 554
Test Date: 2026-04-04 21:36:01 Functions: 100.0 % 26 26

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

Generated by: LCOV version 2.0-1