LCOV - code coverage report
Current view: top level - lib - exchange_api_handle.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 72.9 % 770 561
Test Date: 2026-03-10 12:10:57 Functions: 100.0 % 26 26

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

Generated by: LCOV version 2.0-1