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

Generated by: LCOV version 2.0-1