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

Generated by: LCOV version 2.0-1