LCOV - code coverage report
Current view: top level - lib - exchange_api_handle.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 72.4 % 751 544
Test Date: 2026-06-14 14:19:22 Functions: 100.0 % 26 26

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

Generated by: LCOV version 2.0-1