LCOV - code coverage report
Current view: top level - lib - exchange_api_handle.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 72.5 % 761 552
Test Date: 2026-05-12 15:34:29 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 35
      40              : 
      41              : /**
      42              :  * How many versions are we backwards compatible with?
      43              :  */
      44              : #define EXCHANGE_PROTOCOL_AGE 1
      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         1960 : signature_context_sort_cb (const void *a,
     120              :                            const void *b)
     121              : {
     122         1960 :   const struct SignatureElement *sa = a;
     123         1960 :   const struct SignatureElement *sb = b;
     124              : 
     125         1960 :   if (sa->group_offset < sb->group_offset)
     126         1170 :     return -1;
     127          790 :   if (sa->group_offset > sb->group_offset)
     128            0 :     return 1;
     129          790 :   if (sa->offset < sb->offset)
     130          790 :     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          816 : 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          816 :   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          816 :   element = &sig_ctx->elements[sig_ctx->elements_pos++];
     169          816 :   element->offset = offset;
     170          816 :   element->group_offset = group_offset;
     171          816 :   element->master_sig = *master_sig;
     172          816 : }
     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          921 : 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          921 :     GNUNET_JSON_spec_fixed_auto ("master_sig",
     413              :                                  &denom_key->master_sig),
     414          921 :     GNUNET_JSON_spec_timestamp ("stamp_expire_deposit",
     415              :                                 &denom_key->expire_deposit),
     416          921 :     GNUNET_JSON_spec_timestamp ("stamp_expire_withdraw",
     417              :                                 &denom_key->withdraw_valid_until),
     418          921 :     GNUNET_JSON_spec_timestamp ("stamp_start",
     419              :                                 &denom_key->valid_from),
     420          921 :     GNUNET_JSON_spec_timestamp ("stamp_expire_legal",
     421              :                                 &denom_key->expire_legal),
     422          921 :     GNUNET_JSON_spec_mark_optional (
     423              :       GNUNET_JSON_spec_bool ("lost",
     424              :                              &denom_key->lost),
     425              :       NULL),
     426          921 :     TALER_JSON_spec_denom_pub_cipher (NULL,
     427              :                                       cipher,
     428              :                                       &denom_key->key),
     429          921 :     GNUNET_JSON_spec_end ()
     430              :   };
     431              : 
     432          921 :   if (GNUNET_OK !=
     433          921 :       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          921 :   TALER_denom_pub_hash (&denom_key->key,
     441              :                         &denom_key->h_key);
     442          921 :   if (NULL != sig_ctx)
     443          816 :     append_signature (sig_ctx,
     444              :                       group_offset,
     445              :                       index,
     446          816 :                       &denom_key->master_sig);
     447          921 :   if (! check_sigs)
     448          105 :     return GNUNET_OK;
     449          816 :   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          816 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     461              :               "Learned denomination key %s\n",
     462              :               GNUNET_h2s (&denom_key->h_key.hash));
     463          816 :   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        16856 : 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        16856 :   if (0 !=
     685        16856 :       TALER_denom_pub_cmp (&denom1->key,
     686              :                            &denom2->key))
     687         8600 :     return 1;
     688         8256 :   tmp1 = *denom1;
     689         8256 :   tmp2 = *denom2;
     690         8256 :   tmp1.revoked = false;
     691         8256 :   tmp2.revoked = false;
     692         8256 :   memset (&tmp1.key,
     693              :           0,
     694              :           sizeof (tmp1.key));
     695         8256 :   memset (&tmp2.key,
     696              :           0,
     697              :           sizeof (tmp2.key));
     698         8256 :   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            0 :       *vc |= TALER_EXCHANGE_VC_NEWER;
     962            0 :       if (EXCHANGE_PROTOCOL_CURRENT < pv.current - pv.age)
     963            0 :         *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_mark_optional (
    1000              :         GNUNET_JSON_spec_relative_time (
    1001              :           "default_p2p_push_expiration",
    1002              :           &key_data->default_p2p_push_expiration),
    1003              :         NULL),
    1004           42 :       GNUNET_JSON_spec_string (
    1005              :         "currency",
    1006              :         &currency),
    1007           42 :       GNUNET_JSON_spec_string (
    1008              :         "asset_type",
    1009              :         &asset_type),
    1010           42 :       GNUNET_JSON_spec_array_const (
    1011              :         "global_fees",
    1012              :         &global_fees),
    1013           42 :       GNUNET_JSON_spec_array_const (
    1014              :         "signkeys",
    1015              :         &sign_keys_array),
    1016           42 :       GNUNET_JSON_spec_array_const (
    1017              :         "denominations",
    1018              :         &denominations_by_group),
    1019           42 :       GNUNET_JSON_spec_mark_optional (
    1020              :         GNUNET_JSON_spec_array_const (
    1021              :           "recoup",
    1022              :           &recoup_array),
    1023              :         NULL),
    1024           42 :       GNUNET_JSON_spec_array_const (
    1025              :         "auditors",
    1026              :         &auditors_array),
    1027           42 :       GNUNET_JSON_spec_bool (
    1028              :         "kyc_enabled",
    1029              :         &key_data->kyc_enabled),
    1030           42 :       GNUNET_JSON_spec_mark_optional (
    1031              :         GNUNET_JSON_spec_object_const ("extensions",
    1032              :                                        &manifests),
    1033              :         &no_extensions),
    1034           42 :       GNUNET_JSON_spec_mark_optional (
    1035           42 :         GNUNET_JSON_spec_fixed_auto (
    1036              :           "extensions_sig",
    1037              :           &key_data->extensions_sig),
    1038              :         &no_signature),
    1039           42 :       GNUNET_JSON_spec_string ("version",
    1040              :                                &ver),
    1041           42 :       GNUNET_JSON_spec_mark_optional (
    1042              :         GNUNET_JSON_spec_array_const (
    1043              :           "wallet_balance_limit_without_kyc",
    1044              :           &wblwk),
    1045              :         NULL),
    1046           42 :       GNUNET_JSON_spec_mark_optional (
    1047              :         GNUNET_JSON_spec_string ("shopping_url",
    1048              :                                  &shopping_url),
    1049              :         NULL),
    1050           42 :       GNUNET_JSON_spec_mark_optional (
    1051              :         GNUNET_JSON_spec_string ("bank_compliance_language",
    1052              :                                  &bank_compliance_language),
    1053              :         NULL),
    1054           42 :       GNUNET_JSON_spec_mark_optional (
    1055              :         GNUNET_JSON_spec_bool ("disable_direct_deposit",
    1056              :                                &key_data->disable_direct_deposit),
    1057              :         NULL),
    1058           42 :       GNUNET_JSON_spec_end ()
    1059              :     };
    1060              :     const char *emsg;
    1061              :     unsigned int eline;
    1062              : 
    1063           42 :     if (GNUNET_OK !=
    1064           42 :         GNUNET_JSON_parse (resp_obj,
    1065              :                            (check_sig) ? mspec : &mspec[2],
    1066              :                            &emsg,
    1067              :                            &eline))
    1068              :     {
    1069            0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1070              :                   "Parsing /keys failed for `%s' (%u)\n",
    1071              :                   emsg,
    1072              :                   eline);
    1073            0 :       EXITIF (1);
    1074              :     }
    1075              :     {
    1076           42 :       const json_t *hard_limits = NULL;
    1077           42 :       const json_t *zero_limits = NULL;
    1078           42 :       bool no_tiny_amount = false;
    1079              :       struct GNUNET_JSON_Specification sspec[] = {
    1080           42 :         TALER_JSON_spec_currency_specification (
    1081              :           "currency_specification",
    1082              :           currency,
    1083              :           &key_data->cspec),
    1084           42 :         TALER_JSON_spec_amount (
    1085              :           "stefan_abs",
    1086              :           currency,
    1087              :           &key_data->stefan_abs),
    1088           42 :         TALER_JSON_spec_amount (
    1089              :           "stefan_log",
    1090              :           currency,
    1091              :           &key_data->stefan_log),
    1092           42 :         GNUNET_JSON_spec_mark_optional (
    1093              :           TALER_JSON_spec_amount (
    1094              :             "tiny_amount",
    1095              :             currency,
    1096              :             &key_data->tiny_amount),
    1097              :           &no_tiny_amount),
    1098           42 :         GNUNET_JSON_spec_mark_optional (
    1099              :           GNUNET_JSON_spec_array_const (
    1100              :             "hard_limits",
    1101              :             &hard_limits),
    1102              :           NULL),
    1103           42 :         GNUNET_JSON_spec_mark_optional (
    1104              :           GNUNET_JSON_spec_array_const (
    1105              :             "zero_limits",
    1106              :             &zero_limits),
    1107              :           NULL),
    1108           42 :         GNUNET_JSON_spec_double (
    1109              :           "stefan_lin",
    1110              :           &key_data->stefan_lin),
    1111           42 :         GNUNET_JSON_spec_end ()
    1112              :       };
    1113              : 
    1114           42 :       if (GNUNET_OK !=
    1115           42 :           GNUNET_JSON_parse (resp_obj,
    1116              :                              sspec,
    1117              :                              &emsg,
    1118              :                              &eline))
    1119              :       {
    1120            0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1121              :                     "Parsing /keys failed for `%s' (%u)\n",
    1122              :                     emsg,
    1123              :                     eline);
    1124            0 :         EXITIF (1);
    1125              :       }
    1126           84 :       if ( (NULL != hard_limits) &&
    1127              :            (GNUNET_OK !=
    1128           42 :             parse_hard_limits (hard_limits,
    1129              :                                key_data)) )
    1130              :       {
    1131            0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1132              :                     "Parsing hard limits of /keys failed\n");
    1133            0 :         EXITIF (1);
    1134              :       }
    1135           84 :       if ( (NULL != zero_limits) &&
    1136              :            (GNUNET_OK !=
    1137           42 :             parse_zero_limits (zero_limits,
    1138              :                                key_data)) )
    1139              :       {
    1140            0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1141              :                     "Parsing hard limits of /keys failed\n");
    1142            0 :         EXITIF (1);
    1143              :       }
    1144           42 :       key_data->tiny_amount_available = ! no_tiny_amount;
    1145              :     }
    1146              : 
    1147           42 :     key_data->currency = GNUNET_strdup (currency);
    1148           42 :     key_data->version = GNUNET_strdup (ver);
    1149           42 :     key_data->asset_type = GNUNET_strdup (asset_type);
    1150           42 :     if (NULL != shopping_url)
    1151            0 :       key_data->shopping_url = GNUNET_strdup (shopping_url);
    1152           42 :     if (NULL != bank_compliance_language)
    1153              :       key_data->bank_compliance_language
    1154            0 :         = GNUNET_strdup (bank_compliance_language);
    1155           42 :     if (! no_extensions)
    1156           23 :       key_data->extensions = json_incref ((json_t *) manifests);
    1157              :   }
    1158              : 
    1159              :   /* parse the global fees */
    1160           42 :   EXITIF (json_array_size (global_fees) > UINT_MAX);
    1161              :   key_data->num_global_fees
    1162           42 :     = (unsigned int) json_array_size (global_fees);
    1163           42 :   if (0 != key_data->num_global_fees)
    1164              :   {
    1165              :     json_t *global_fee;
    1166              :     size_t index;
    1167              : 
    1168              :     key_data->global_fees
    1169           42 :       = GNUNET_new_array (key_data->num_global_fees,
    1170              :                           struct TALER_EXCHANGE_GlobalFee);
    1171          126 :     json_array_foreach (global_fees, index, global_fee)
    1172              :     {
    1173           84 :       EXITIF (GNUNET_SYSERR ==
    1174              :               parse_global_fee (&key_data->global_fees[index],
    1175              :                                 check_sig,
    1176              :                                 global_fee,
    1177              :                                 key_data));
    1178              :     }
    1179              :   }
    1180              : 
    1181              :   /* parse the signing keys */
    1182           42 :   EXITIF (json_array_size (sign_keys_array) > UINT_MAX);
    1183              :   key_data->num_sign_keys
    1184           42 :     = (unsigned int) json_array_size (sign_keys_array);
    1185           42 :   if (0 != key_data->num_sign_keys)
    1186              :   {
    1187              :     json_t *sign_key_obj;
    1188              :     size_t index;
    1189              : 
    1190              :     key_data->sign_keys
    1191           42 :       = GNUNET_new_array (key_data->num_sign_keys,
    1192              :                           struct TALER_EXCHANGE_SigningPublicKey);
    1193           87 :     json_array_foreach (sign_keys_array, index, sign_key_obj) {
    1194           45 :       EXITIF (GNUNET_SYSERR ==
    1195              :               parse_json_signkey (&key_data->sign_keys[index],
    1196              :                                   check_sig,
    1197              :                                   sign_key_obj,
    1198              :                                   &key_data->master_pub));
    1199              :     }
    1200              :   }
    1201              : 
    1202              :   /* Parse balance limits */
    1203           42 :   if (NULL != wblwk)
    1204              :   {
    1205           42 :     EXITIF (json_array_size (wblwk) > UINT_MAX);
    1206              :     key_data->wblwk_length
    1207           42 :       = (unsigned int) json_array_size (wblwk);
    1208              :     key_data->wallet_balance_limit_without_kyc
    1209           42 :       = GNUNET_new_array (key_data->wblwk_length,
    1210              :                           struct TALER_Amount);
    1211           43 :     for (unsigned int i = 0; i<key_data->wblwk_length; i++)
    1212              :     {
    1213            1 :       struct TALER_Amount *a = &key_data->wallet_balance_limit_without_kyc[i];
    1214            1 :       const json_t *aj = json_array_get (wblwk,
    1215              :                                          i);
    1216              :       struct GNUNET_JSON_Specification spec[] = {
    1217            1 :         TALER_JSON_spec_amount (NULL,
    1218            1 :                                 key_data->currency,
    1219              :                                 a),
    1220            1 :         GNUNET_JSON_spec_end ()
    1221              :       };
    1222              : 
    1223            1 :       EXITIF (GNUNET_OK !=
    1224              :               GNUNET_JSON_parse (aj,
    1225              :                                  spec,
    1226              :                                  NULL, NULL));
    1227              :     }
    1228              :   }
    1229              : 
    1230              :   /* Parse wire accounts */
    1231           84 :   key_data->fees = parse_fees (&key_data->master_pub,
    1232           42 :                                key_data->currency,
    1233              :                                fees,
    1234              :                                &key_data->fees_len);
    1235           42 :   EXITIF (NULL == key_data->fees);
    1236              :   /* parse accounts */
    1237           42 :   EXITIF (json_array_size (accounts) > UINT_MAX);
    1238           42 :   GNUNET_array_grow (key_data->accounts,
    1239              :                      key_data->accounts_len,
    1240              :                      json_array_size (accounts));
    1241           42 :   EXITIF (GNUNET_OK !=
    1242              :           TALER_EXCHANGE_parse_accounts (&key_data->master_pub,
    1243              :                                          accounts,
    1244              :                                          key_data->accounts_len,
    1245              :                                          key_data->accounts));
    1246              : 
    1247           42 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1248              :               "Parsed %u wire accounts from JSON\n",
    1249              :               key_data->accounts_len);
    1250              : 
    1251              :   /* Parse wad partners */
    1252           42 :   EXITIF (GNUNET_OK !=
    1253              :           parse_wads (wads,
    1254              :                       check_sig,
    1255              :                       key_data));
    1256              : 
    1257              : 
    1258              :   /* Parse the supported extension(s): age-restriction. */
    1259              :   /* FIXME[Oec]: maybe lift all this into a FP in TALER_Extension ? */
    1260           42 :   if (! no_extensions)
    1261              :   {
    1262           23 :     if (no_signature)
    1263              :     {
    1264           23 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1265              :                   "found extensions without signature\n");
    1266              :     }
    1267              :     else
    1268              :     {
    1269              :       /* We have an extensions object. Verify its signature. */
    1270            0 :       EXITIF (GNUNET_OK !=
    1271              :               TALER_extensions_verify_manifests_signature (
    1272              :                 manifests,
    1273              :                 &key_data->extensions_sig,
    1274              :                 &key_data->master_pub));
    1275              : 
    1276              :       /* Parse and set the the configuration of the extensions accordingly */
    1277            0 :       EXITIF (GNUNET_OK !=
    1278              :               TALER_extensions_load_manifests (manifests));
    1279              :     }
    1280              : 
    1281              :     /* Assuming we might have now a new value for age_mask, set it in key_data */
    1282           23 :     key_data->age_mask = TALER_extensions_get_age_restriction_mask ();
    1283              :   }
    1284              : 
    1285              :   /*
    1286              :    * Parse the denomination keys, merging with the
    1287              :    * possibly EXISTING array as required (/keys cherry picking).
    1288              :    *
    1289              :    * The denominations are grouped by common values of
    1290              :    *    {cipher, value, fee, age_mask}.
    1291              :    */
    1292              :   {
    1293              :     json_t *group_obj;
    1294              :     unsigned int group_idx;
    1295              : 
    1296          291 :     json_array_foreach (denominations_by_group,
    1297              :                         group_idx,
    1298              :                         group_obj)
    1299              :     {
    1300              :       /* First, parse { cipher, fees, value, age_mask, hash } of the current
    1301              :          group. */
    1302          249 :       struct TALER_DenominationGroup group = {0};
    1303              :       const json_t *denom_keys_array;
    1304              :       struct GNUNET_JSON_Specification group_spec[] = {
    1305          249 :         TALER_JSON_spec_denomination_group (NULL,
    1306          249 :                                             key_data->currency,
    1307              :                                             &group),
    1308          249 :         GNUNET_JSON_spec_array_const ("denoms",
    1309              :                                       &denom_keys_array),
    1310          249 :         GNUNET_JSON_spec_end ()
    1311              :       };
    1312              :       json_t *denom_key_obj;
    1313              :       unsigned int index;
    1314              : 
    1315          249 :       EXITIF (GNUNET_SYSERR ==
    1316              :               GNUNET_JSON_parse (group_obj,
    1317              :                                  group_spec,
    1318              :                                  NULL,
    1319              :                                  NULL));
    1320              : 
    1321              :       /* Now, parse the individual denominations */
    1322         1170 :       json_array_foreach (denom_keys_array,
    1323              :                           index,
    1324              :                           denom_key_obj)
    1325              :       {
    1326              :         /* Set the common fields from the group for this particular
    1327              :            denomination.  Required to make the validity check inside
    1328              :            parse_json_denomkey_partially pass */
    1329          921 :         struct TALER_EXCHANGE_DenomPublicKey dk = {
    1330              :           .value = group.value,
    1331              :           .fees = group.fees,
    1332              :           .key.age_mask = group.age_mask
    1333              :         };
    1334          921 :         bool found = false;
    1335              : 
    1336          921 :         EXITIF (GNUNET_SYSERR ==
    1337              :                 parse_json_denomkey_partially (&dk,
    1338              :                                                group.cipher,
    1339              :                                                check_sig,
    1340              :                                                denom_key_obj,
    1341              :                                                &key_data->master_pub,
    1342              :                                                group_idx,
    1343              :                                                index,
    1344              :                                                check_sig
    1345              :                                                ? &sig_ctx
    1346              :                                                : NULL));
    1347          921 :         for (unsigned int j = 0;
    1348        17751 :              j<key_data->num_denom_keys;
    1349        16830 :              j++)
    1350              :         {
    1351        16856 :           if (0 == denoms_cmp (&dk,
    1352        16856 :                                &key_data->denom_keys[j]))
    1353              :           {
    1354           26 :             found = true;
    1355           26 :             break;
    1356              :           }
    1357              :         }
    1358              : 
    1359          921 :         if (found)
    1360              :         {
    1361              :           /* 0:0:0 did not support /keys cherry picking */
    1362           26 :           TALER_LOG_DEBUG ("Skipping denomination key: already know it\n");
    1363           26 :           TALER_denom_pub_free (&dk.key);
    1364           26 :           continue;
    1365              :         }
    1366              : 
    1367          895 :         if (key_data->denom_keys_size == key_data->num_denom_keys)
    1368          131 :           GNUNET_array_grow (key_data->denom_keys,
    1369              :                              key_data->denom_keys_size,
    1370              :                              key_data->denom_keys_size * 2 + 2);
    1371          895 :         GNUNET_assert (key_data->denom_keys_size >
    1372              :                        key_data->num_denom_keys);
    1373          895 :         GNUNET_assert (key_data->num_denom_keys < UINT_MAX);
    1374          895 :         key_data->denom_keys[key_data->num_denom_keys++] = dk;
    1375              : 
    1376              :         /* Update "last_denom_issue_date" */
    1377          895 :         TALER_LOG_DEBUG ("Adding denomination key that is valid_until %s\n",
    1378              :                          GNUNET_TIME_timestamp2s (dk.valid_from));
    1379              :         key_data->last_denom_issue_date
    1380          895 :           = GNUNET_TIME_timestamp_max (key_data->last_denom_issue_date,
    1381              :                                        dk.valid_from);
    1382              :       };   /* end of json_array_foreach over denominations */
    1383              :     } /* end of json_array_foreach over groups of denominations */
    1384              :   } /* end of scope for group_ojb/group_idx */
    1385              : 
    1386              :   /* parse the auditor information */
    1387              :   {
    1388              :     json_t *auditor_info;
    1389              :     unsigned int index;
    1390              : 
    1391              :     /* Merge with the existing auditor information we have (/keys cherry picking) */
    1392           54 :     json_array_foreach (auditors_array, index, auditor_info)
    1393              :     {
    1394              :       struct TALER_EXCHANGE_AuditorInformation ai;
    1395           12 :       bool found = false;
    1396              : 
    1397           12 :       memset (&ai,
    1398              :               0,
    1399              :               sizeof (ai));
    1400           12 :       EXITIF (GNUNET_SYSERR ==
    1401              :               parse_json_auditor (&ai,
    1402              :                                   check_sig,
    1403              :                                   auditor_info,
    1404              :                                   key_data));
    1405           12 :       for (unsigned int j = 0; j<key_data->num_auditors; j++)
    1406              :       {
    1407            0 :         struct TALER_EXCHANGE_AuditorInformation *aix = &key_data->auditors[j];
    1408              : 
    1409            0 :         if (0 == GNUNET_memcmp (&ai.auditor_pub,
    1410              :                                 &aix->auditor_pub))
    1411              :         {
    1412            0 :           found = true;
    1413              :           /* Merge denomination key signatures of downloaded /keys into existing
    1414              :              auditor information 'aix'. */
    1415            0 :           TALER_LOG_DEBUG (
    1416              :             "Merging %u new audited keys with %u known audited keys\n",
    1417              :             aix->num_denom_keys,
    1418              :             ai.num_denom_keys);
    1419            0 :           for (unsigned int i = 0; i<ai.num_denom_keys; i++)
    1420              :           {
    1421            0 :             bool kfound = false;
    1422              : 
    1423            0 :             for (unsigned int k = 0; k<aix->num_denom_keys; k++)
    1424              :             {
    1425            0 :               if (aix->denom_keys[k].denom_key_offset ==
    1426            0 :                   ai.denom_keys[i].denom_key_offset)
    1427              :               {
    1428            0 :                 kfound = true;
    1429            0 :                 break;
    1430              :               }
    1431              :             }
    1432            0 :             if (! kfound)
    1433            0 :               GNUNET_array_append (aix->denom_keys,
    1434              :                                    aix->num_denom_keys,
    1435              :                                    ai.denom_keys[i]);
    1436              :           }
    1437            0 :           break;
    1438              :         }
    1439              :       }
    1440           12 :       if (found)
    1441              :       {
    1442            0 :         GNUNET_array_grow (ai.denom_keys,
    1443              :                            ai.num_denom_keys,
    1444              :                            0);
    1445            0 :         GNUNET_free (ai.auditor_url);
    1446            0 :         GNUNET_free (ai.auditor_name);
    1447            0 :         continue; /* we are done */
    1448              :       }
    1449           12 :       if (key_data->auditors_size == key_data->num_auditors)
    1450           12 :         GNUNET_array_grow (key_data->auditors,
    1451              :                            key_data->auditors_size,
    1452              :                            key_data->auditors_size * 2 + 2);
    1453           12 :       GNUNET_assert (key_data->auditors_size >
    1454              :                      key_data->num_auditors);
    1455           12 :       GNUNET_assert (NULL != ai.auditor_url);
    1456           12 :       GNUNET_assert (key_data->num_auditors < UINT_MAX);
    1457           12 :       key_data->auditors[key_data->num_auditors++] = ai;
    1458              :     };
    1459              :   }
    1460              : 
    1461              :   /* parse the revocation/recoup information */
    1462           42 :   if (NULL != recoup_array)
    1463              :   {
    1464              :     json_t *recoup_info;
    1465              :     unsigned int index;
    1466              : 
    1467           42 :     json_array_foreach (recoup_array, index, recoup_info)
    1468              :     {
    1469              :       struct TALER_DenominationHashP h_denom_pub;
    1470              :       struct GNUNET_JSON_Specification spec[] = {
    1471            0 :         GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
    1472              :                                      &h_denom_pub),
    1473            0 :         GNUNET_JSON_spec_end ()
    1474              :       };
    1475              : 
    1476            0 :       EXITIF (GNUNET_OK !=
    1477              :               GNUNET_JSON_parse (recoup_info,
    1478              :                                  spec,
    1479              :                                  NULL, NULL));
    1480            0 :       for (unsigned int j = 0;
    1481            0 :            j<key_data->num_denom_keys;
    1482            0 :            j++)
    1483              :       {
    1484            0 :         if (0 == GNUNET_memcmp (&h_denom_pub,
    1485              :                                 &key_data->denom_keys[j].h_key))
    1486              :         {
    1487            0 :           key_data->denom_keys[j].revoked = true;
    1488            0 :           break;
    1489              :         }
    1490              :       }
    1491              :     }
    1492              :   }
    1493              : 
    1494           42 :   if (check_sig)
    1495              :   {
    1496              :     struct GNUNET_HashContext *hash_context;
    1497              :     struct GNUNET_HashCode hc;
    1498              : 
    1499           34 :     hash_context = GNUNET_CRYPTO_hash_context_start ();
    1500           34 :     qsort (sig_ctx.elements,
    1501           34 :            sig_ctx.elements_pos,
    1502              :            sizeof (struct SignatureElement),
    1503              :            &signature_context_sort_cb);
    1504          850 :     for (unsigned int i = 0; i<sig_ctx.elements_pos; i++)
    1505              :     {
    1506          816 :       struct SignatureElement *element = &sig_ctx.elements[i];
    1507              : 
    1508          816 :       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1509              :                   "Adding %u,%u,%s\n",
    1510              :                   element->group_offset,
    1511              :                   element->offset,
    1512              :                   TALER_B2S (&element->master_sig));
    1513          816 :       GNUNET_CRYPTO_hash_context_read (hash_context,
    1514          816 :                                        &element->master_sig,
    1515              :                                        sizeof (element->master_sig));
    1516              :     }
    1517           34 :     GNUNET_array_grow (sig_ctx.elements,
    1518              :                        sig_ctx.elements_size,
    1519              :                        0);
    1520           34 :     GNUNET_CRYPTO_hash_context_finish (hash_context,
    1521              :                                        &hc);
    1522           34 :     EXITIF (GNUNET_OK !=
    1523              :             TALER_EXCHANGE_test_signing_key (key_data,
    1524              :                                              &exchange_pub));
    1525           34 :     EXITIF (GNUNET_OK !=
    1526              :             TALER_exchange_online_key_set_verify (
    1527              :               key_data->list_issue_date,
    1528              :               &hc,
    1529              :               &exchange_pub,
    1530              :               &exchange_sig));
    1531              :   }
    1532           42 :   return GNUNET_OK;
    1533              : 
    1534            0 : EXITIF_exit:
    1535            0 :   *vc = TALER_EXCHANGE_VC_PROTOCOL_ERROR;
    1536            0 :   return GNUNET_SYSERR;
    1537              : }
    1538              : 
    1539              : 
    1540              : enum GNUNET_GenericReturnValue
    1541          185 : TALER_EXCHANGE_test_signing_key (
    1542              :   const struct TALER_EXCHANGE_Keys *keys,
    1543              :   const struct TALER_ExchangePublicKeyP *pub)
    1544              : {
    1545              :   struct GNUNET_TIME_Absolute now;
    1546              : 
    1547              :   /* we will check using a tolerance of 1h for the time */
    1548          185 :   now = GNUNET_TIME_absolute_get ();
    1549          202 :   for (unsigned int i = 0; i<keys->num_sign_keys; i++)
    1550          202 :     if ( (GNUNET_TIME_absolute_cmp (
    1551              :             keys->sign_keys[i].valid_from.abs_time,
    1552              :             <=,
    1553              :             GNUNET_TIME_absolute_add (now,
    1554          185 :                                       LIFETIME_TOLERANCE))) &&
    1555          185 :          (GNUNET_TIME_absolute_cmp (
    1556              :             keys->sign_keys[i].valid_until.abs_time,
    1557              :             >,
    1558              :             GNUNET_TIME_absolute_subtract (now,
    1559          185 :                                            LIFETIME_TOLERANCE))) &&
    1560          185 :          (0 == GNUNET_memcmp (pub,
    1561              :                               &keys->sign_keys[i].key)) )
    1562          185 :       return GNUNET_OK;
    1563            0 :   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1564              :               "Signing key not valid at time %s\n",
    1565              :               GNUNET_TIME_absolute2s (now));
    1566            0 :   return GNUNET_SYSERR;
    1567              : }
    1568              : 
    1569              : 
    1570              : const struct TALER_EXCHANGE_DenomPublicKey *
    1571           30 : TALER_EXCHANGE_get_denomination_key (
    1572              :   const struct TALER_EXCHANGE_Keys *keys,
    1573              :   const struct TALER_DenominationPublicKey *pk)
    1574              : {
    1575          142 :   for (unsigned int i = 0; i<keys->num_denom_keys; i++)
    1576          142 :     if (0 ==
    1577          142 :         TALER_denom_pub_cmp (pk,
    1578          142 :                              &keys->denom_keys[i].key))
    1579           30 :       return &keys->denom_keys[i];
    1580            0 :   return NULL;
    1581              : }
    1582              : 
    1583              : 
    1584              : const struct TALER_EXCHANGE_GlobalFee *
    1585           13 : TALER_EXCHANGE_get_global_fee (
    1586              :   const struct TALER_EXCHANGE_Keys *keys,
    1587              :   struct GNUNET_TIME_Timestamp ts)
    1588              : {
    1589           13 :   for (unsigned int i = 0; i<keys->num_global_fees; i++)
    1590              :   {
    1591           13 :     const struct TALER_EXCHANGE_GlobalFee *gf = &keys->global_fees[i];
    1592              : 
    1593           13 :     if (GNUNET_TIME_timestamp_cmp (ts,
    1594              :                                    >=,
    1595           13 :                                    gf->start_date) &&
    1596           13 :         GNUNET_TIME_timestamp_cmp (ts,
    1597              :                                    <,
    1598              :                                    gf->end_date))
    1599           13 :       return gf;
    1600              :   }
    1601            0 :   return NULL;
    1602              : }
    1603              : 
    1604              : 
    1605              : struct TALER_EXCHANGE_DenomPublicKey *
    1606           72 : TALER_EXCHANGE_copy_denomination_key (
    1607              :   const struct TALER_EXCHANGE_DenomPublicKey *key)
    1608              : {
    1609              :   struct TALER_EXCHANGE_DenomPublicKey *copy;
    1610              : 
    1611           72 :   copy = GNUNET_new (struct TALER_EXCHANGE_DenomPublicKey);
    1612           72 :   *copy = *key;
    1613           72 :   TALER_denom_pub_copy (&copy->key,
    1614              :                         &key->key);
    1615           72 :   return copy;
    1616              : }
    1617              : 
    1618              : 
    1619              : void
    1620           72 : TALER_EXCHANGE_destroy_denomination_key (
    1621              :   struct TALER_EXCHANGE_DenomPublicKey *key)
    1622              : {
    1623           72 :   TALER_denom_pub_free (&key->key);
    1624           72 :   GNUNET_free (key);
    1625           72 : }
    1626              : 
    1627              : 
    1628              : const struct TALER_EXCHANGE_DenomPublicKey *
    1629          113 : TALER_EXCHANGE_get_denomination_key_by_hash (
    1630              :   const struct TALER_EXCHANGE_Keys *keys,
    1631              :   const struct TALER_DenominationHashP *hc)
    1632              : {
    1633              :   /* FIXME-optimization: should we maybe use a hash map here? */
    1634         2264 :   for (unsigned int i = 0; i<keys->num_denom_keys; i++)
    1635         2264 :     if (0 == GNUNET_memcmp (hc,
    1636              :                             &keys->denom_keys[i].h_key))
    1637          113 :       return &keys->denom_keys[i];
    1638            0 :   return NULL;
    1639              : }
    1640              : 
    1641              : 
    1642              : struct TALER_EXCHANGE_Keys *
    1643          377 : TALER_EXCHANGE_keys_incref (struct TALER_EXCHANGE_Keys *keys)
    1644              : {
    1645          377 :   GNUNET_assert (keys->rc < UINT_MAX);
    1646          377 :   keys->rc++;
    1647          377 :   return keys;
    1648              : }
    1649              : 
    1650              : 
    1651              : void
    1652          473 : TALER_EXCHANGE_keys_decref (struct TALER_EXCHANGE_Keys *keys)
    1653              : {
    1654          473 :   if (NULL == keys)
    1655           54 :     return;
    1656          419 :   GNUNET_assert (0 < keys->rc);
    1657          419 :   keys->rc--;
    1658          419 :   if (0 != keys->rc)
    1659          377 :     return;
    1660           42 :   GNUNET_array_grow (keys->sign_keys,
    1661              :                      keys->num_sign_keys,
    1662              :                      0);
    1663         1042 :   for (unsigned int i = 0; i<keys->num_denom_keys; i++)
    1664         1000 :     TALER_denom_pub_free (&keys->denom_keys[i].key);
    1665           42 :   keys->num_denom_keys = 0;
    1666           42 :   GNUNET_array_grow (keys->denom_keys,
    1667              :                      keys->denom_keys_size,
    1668              :                      0);
    1669           56 :   for (unsigned int i = 0; i<keys->num_auditors; i++)
    1670              :   {
    1671           14 :     GNUNET_array_grow (keys->auditors[i].denom_keys,
    1672              :                        keys->auditors[i].num_denom_keys,
    1673              :                        0);
    1674           14 :     GNUNET_free (keys->auditors[i].auditor_url);
    1675           14 :     GNUNET_free (keys->auditors[i].auditor_name);
    1676              :   }
    1677           42 :   GNUNET_array_grow (keys->auditors,
    1678              :                      keys->auditors_size,
    1679              :                      0);
    1680           42 :   TALER_EXCHANGE_free_accounts (keys->accounts_len,
    1681              :                                 keys->accounts);
    1682           42 :   GNUNET_array_grow (keys->accounts,
    1683              :                      keys->accounts_len,
    1684              :                      0);
    1685           42 :   free_fees (keys->fees,
    1686              :              keys->fees_len);
    1687           42 :   GNUNET_array_grow (keys->hard_limits,
    1688              :                      keys->hard_limits_length,
    1689              :                      0);
    1690           42 :   GNUNET_array_grow (keys->zero_limits,
    1691              :                      keys->zero_limits_length,
    1692              :                      0);
    1693           42 :   json_decref (keys->extensions);
    1694           42 :   GNUNET_free (keys->cspec.name);
    1695           42 :   json_decref (keys->cspec.map_alt_unit_names);
    1696           42 :   GNUNET_array_grow (keys->cspec.common_amounts,
    1697              :                      keys->cspec.num_common_amounts,
    1698              :                      0);
    1699           42 :   GNUNET_free (keys->wallet_balance_limit_without_kyc);
    1700           42 :   GNUNET_free (keys->version);
    1701           42 :   GNUNET_free (keys->currency);
    1702           42 :   GNUNET_free (keys->asset_type);
    1703           42 :   GNUNET_free (keys->shopping_url);
    1704           42 :   GNUNET_free (keys->bank_compliance_language);
    1705           42 :   for (unsigned int i = 0; i < keys->num_wad_partners; i++)
    1706            0 :     GNUNET_free (keys->wad_partners[i].partner_base_url);
    1707           42 :   GNUNET_free (keys->wad_partners);
    1708           42 :   GNUNET_free (keys->global_fees);
    1709           42 :   GNUNET_free (keys->exchange_url);
    1710           42 :   GNUNET_free (keys);
    1711              : }
    1712              : 
    1713              : 
    1714              : struct TALER_EXCHANGE_Keys *
    1715            8 : TALER_EXCHANGE_keys_from_json (const json_t *j)
    1716              : {
    1717              :   const json_t *jkeys;
    1718              :   const char *url;
    1719              :   uint32_t version;
    1720            8 :   struct GNUNET_TIME_Timestamp expire
    1721              :     = GNUNET_TIME_UNIT_ZERO_TS;
    1722              :   struct GNUNET_JSON_Specification spec[] = {
    1723            8 :     GNUNET_JSON_spec_uint32 ("version",
    1724              :                              &version),
    1725            8 :     GNUNET_JSON_spec_object_const ("keys",
    1726              :                                    &jkeys),
    1727            8 :     TALER_JSON_spec_web_url ("exchange_url",
    1728              :                              &url),
    1729            8 :     GNUNET_JSON_spec_mark_optional (
    1730              :       GNUNET_JSON_spec_timestamp ("expire",
    1731              :                                   &expire),
    1732              :       NULL),
    1733            8 :     GNUNET_JSON_spec_end ()
    1734              :   };
    1735              :   struct TALER_EXCHANGE_Keys *keys;
    1736              :   enum TALER_EXCHANGE_VersionCompatibility compat;
    1737              : 
    1738            8 :   if (NULL == j)
    1739            0 :     return NULL;
    1740            8 :   if (GNUNET_OK !=
    1741            8 :       GNUNET_JSON_parse (j,
    1742              :                          spec,
    1743              :                          NULL, NULL))
    1744              :   {
    1745            0 :     GNUNET_break_op (0);
    1746            0 :     return NULL;
    1747              :   }
    1748            8 :   if (0 != version)
    1749              :   {
    1750            0 :     return NULL; /* unsupported version */
    1751              :   }
    1752            8 :   keys = GNUNET_new (struct TALER_EXCHANGE_Keys);
    1753            8 :   if (GNUNET_OK !=
    1754            8 :       TALER_EXCHANGE_decode_keys_json_ (jkeys,
    1755              :                                         false,
    1756              :                                         keys,
    1757              :                                         &compat))
    1758              :   {
    1759            0 :     GNUNET_break (0);
    1760            0 :     return NULL;
    1761              :   }
    1762            8 :   keys->rc = 1;
    1763            8 :   keys->key_data_expiration = expire;
    1764            8 :   keys->exchange_url = GNUNET_strdup (url);
    1765            8 :   return keys;
    1766              : }
    1767              : 
    1768              : 
    1769              : /**
    1770              :  * Data we track per denomination group.
    1771              :  */
    1772              : struct GroupData
    1773              : {
    1774              :   /**
    1775              :    * The json blob with the group meta-data and list of denominations
    1776              :    */
    1777              :   json_t *json;
    1778              : 
    1779              :   /**
    1780              :    * Meta data for this group.
    1781              :    */
    1782              :   struct TALER_DenominationGroup meta;
    1783              : };
    1784              : 
    1785              : 
    1786              : /**
    1787              :  * Add denomination group represented by @a value
    1788              :  * to list of denominations in @a cls. Also frees
    1789              :  * the @a value.
    1790              :  *
    1791              :  * @param[in,out] cls a `json_t *` with an array to build
    1792              :  * @param key unused
    1793              :  * @param value a `struct GroupData *`
    1794              :  * @return #GNUNET_OK (continue to iterate)
    1795              :  */
    1796              : static enum GNUNET_GenericReturnValue
    1797           26 : add_grp (void *cls,
    1798              :          const struct GNUNET_HashCode *key,
    1799              :          void *value)
    1800              : {
    1801           26 :   json_t *denominations_by_group = cls;
    1802           26 :   struct GroupData *gd = value;
    1803              :   const char *cipher;
    1804              :   json_t *ge;
    1805           26 :   bool age_restricted = gd->meta.age_mask.bits != 0;
    1806              : 
    1807              :   (void) key;
    1808           26 :   switch (gd->meta.cipher)
    1809              :   {
    1810           13 :   case GNUNET_CRYPTO_BSA_RSA:
    1811           13 :     cipher = age_restricted ? "RSA+age_restricted" : "RSA";
    1812           13 :     break;
    1813           13 :   case GNUNET_CRYPTO_BSA_CS:
    1814           13 :     cipher = age_restricted ? "CS+age_restricted" : "CS";
    1815           13 :     break;
    1816            0 :   default:
    1817            0 :     GNUNET_assert (false);
    1818              :   }
    1819              : 
    1820           26 :   ge = GNUNET_JSON_PACK (
    1821              :     GNUNET_JSON_pack_string ("cipher",
    1822              :                              cipher),
    1823              :     GNUNET_JSON_pack_array_steal ("denoms",
    1824              :                                   gd->json),
    1825              :     TALER_JSON_PACK_DENOM_FEES ("fee",
    1826              :                                 &gd->meta.fees),
    1827              :     GNUNET_JSON_pack_allow_null (
    1828              :       age_restricted
    1829              :           ? GNUNET_JSON_pack_uint64 ("age_mask",
    1830              :                                      gd->meta.age_mask.bits)
    1831              :           : GNUNET_JSON_pack_string ("dummy",
    1832              :                                      NULL)),
    1833              :     TALER_JSON_pack_amount ("value",
    1834              :                             &gd->meta.value));
    1835           26 :   GNUNET_assert (0 ==
    1836              :                  json_array_append_new (denominations_by_group,
    1837              :                                         ge));
    1838           26 :   GNUNET_free (gd);
    1839           26 :   return GNUNET_OK;
    1840              : }
    1841              : 
    1842              : 
    1843              : /**
    1844              :  * Convert array of account restrictions @a ars to JSON.
    1845              :  *
    1846              :  * @param ar_len length of @a ars
    1847              :  * @param ars account restrictions to convert
    1848              :  * @return JSON representation
    1849              :  */
    1850              : static json_t *
    1851           16 : ar_to_json (unsigned int ar_len,
    1852              :             const struct TALER_EXCHANGE_AccountRestriction ars[static ar_len])
    1853           16 : {
    1854              :   json_t *rval;
    1855              : 
    1856           16 :   rval = json_array ();
    1857           16 :   GNUNET_assert (NULL != rval);
    1858           16 :   for (unsigned int i = 0; i<ar_len; i++)
    1859              :   {
    1860            0 :     const struct TALER_EXCHANGE_AccountRestriction *ar = &ars[i];
    1861              : 
    1862            0 :     switch (ar->type)
    1863              :     {
    1864            0 :     case TALER_EXCHANGE_AR_INVALID:
    1865            0 :       GNUNET_break (0);
    1866            0 :       json_decref (rval);
    1867            0 :       return NULL;
    1868            0 :     case TALER_EXCHANGE_AR_DENY:
    1869            0 :       GNUNET_assert (
    1870              :         0 ==
    1871              :         json_array_append_new (
    1872              :           rval,
    1873              :           GNUNET_JSON_PACK (
    1874              :             GNUNET_JSON_pack_string ("type",
    1875              :                                      "deny"))));
    1876            0 :       break;
    1877            0 :     case TALER_EXCHANGE_AR_REGEX:
    1878            0 :       GNUNET_assert (
    1879              :         0 ==
    1880              :         json_array_append_new (
    1881              :           rval,
    1882              :           GNUNET_JSON_PACK (
    1883              :             GNUNET_JSON_pack_string (
    1884              :               "type",
    1885              :               "regex"),
    1886              :             GNUNET_JSON_pack_string (
    1887              :               "payto_regex",
    1888              :               ar->details.regex.posix_egrep),
    1889              :             GNUNET_JSON_pack_string (
    1890              :               "human_hint",
    1891              :               ar->details.regex.human_hint),
    1892              :             GNUNET_JSON_pack_object_incref (
    1893              :               "human_hint_i18n",
    1894              :               (json_t *) ar->details.regex.human_hint_i18n)
    1895              :             )));
    1896            0 :       break;
    1897              :     }
    1898              :   }
    1899           16 :   return rval;
    1900              : }
    1901              : 
    1902              : 
    1903              : json_t *
    1904            8 : TALER_EXCHANGE_keys_to_json (const struct TALER_EXCHANGE_Keys *kd)
    1905              : {
    1906              :   struct GNUNET_TIME_Timestamp now;
    1907              :   json_t *keys;
    1908              :   json_t *signkeys;
    1909              :   json_t *denominations_by_group;
    1910              :   json_t *auditors;
    1911              :   json_t *recoup;
    1912              :   json_t *wire_fees;
    1913              :   json_t *accounts;
    1914              :   json_t *global_fees;
    1915            8 :   json_t *wblwk = NULL;
    1916              :   json_t *wads_json;
    1917              :   json_t *hard_limits;
    1918              :   json_t *zero_limits;
    1919              : 
    1920            8 :   now = GNUNET_TIME_timestamp_get ();
    1921            8 :   signkeys = json_array ();
    1922            8 :   GNUNET_assert (NULL != signkeys);
    1923           16 :   for (unsigned int i = 0; i<kd->num_sign_keys; i++)
    1924              :   {
    1925            8 :     const struct TALER_EXCHANGE_SigningPublicKey *sk = &kd->sign_keys[i];
    1926              :     json_t *signkey;
    1927              : 
    1928            8 :     if (GNUNET_TIME_timestamp_cmp (now,
    1929              :                                    >,
    1930              :                                    sk->valid_until))
    1931            0 :       continue; /* skip keys that have expired */
    1932            8 :     signkey = GNUNET_JSON_PACK (
    1933              :       GNUNET_JSON_pack_data_auto ("key",
    1934              :                                   &sk->key),
    1935              :       GNUNET_JSON_pack_data_auto ("master_sig",
    1936              :                                   &sk->master_sig),
    1937              :       GNUNET_JSON_pack_timestamp ("stamp_start",
    1938              :                                   sk->valid_from),
    1939              :       GNUNET_JSON_pack_timestamp ("stamp_expire",
    1940              :                                   sk->valid_until),
    1941              :       GNUNET_JSON_pack_timestamp ("stamp_end",
    1942              :                                   sk->valid_legal));
    1943            8 :     GNUNET_assert (NULL != signkey);
    1944            8 :     GNUNET_assert (0 ==
    1945              :                    json_array_append_new (signkeys,
    1946              :                                           signkey));
    1947              :   }
    1948              : 
    1949            8 :   denominations_by_group = json_array ();
    1950            8 :   GNUNET_assert (NULL != denominations_by_group);
    1951              :   {
    1952              :     struct GNUNET_CONTAINER_MultiHashMap *dbg;
    1953              : 
    1954            8 :     dbg = GNUNET_CONTAINER_multihashmap_create (128,
    1955              :                                                 false);
    1956          113 :     for (unsigned int i = 0; i<kd->num_denom_keys; i++)
    1957              :     {
    1958          105 :       const struct TALER_EXCHANGE_DenomPublicKey *dk = &kd->denom_keys[i];
    1959          105 :       struct TALER_DenominationGroup meta = {
    1960          105 :         .cipher = dk->key.bsign_pub_key->cipher,
    1961              :         .value = dk->value,
    1962              :         .fees = dk->fees,
    1963              :         .age_mask = dk->key.age_mask
    1964              :       };
    1965              :       struct GNUNET_HashCode key;
    1966              :       struct GroupData *gd;
    1967              :       json_t *denom;
    1968              :       struct GNUNET_JSON_PackSpec key_spec;
    1969              : 
    1970          105 :       if (GNUNET_TIME_timestamp_cmp (now,
    1971              :                                      >,
    1972              :                                      dk->expire_deposit))
    1973            0 :         continue; /* skip keys that have expired */
    1974          105 :       TALER_denomination_group_get_key (&meta,
    1975              :                                         &key);
    1976          105 :       gd = GNUNET_CONTAINER_multihashmap_get (dbg,
    1977              :                                               &key);
    1978          105 :       if (NULL == gd)
    1979              :       {
    1980           26 :         gd = GNUNET_new (struct GroupData);
    1981           26 :         gd->meta = meta;
    1982           26 :         gd->json = json_array ();
    1983           26 :         GNUNET_assert (NULL != gd->json);
    1984           26 :         GNUNET_assert (
    1985              :           GNUNET_OK ==
    1986              :           GNUNET_CONTAINER_multihashmap_put (dbg,
    1987              :                                              &key,
    1988              :                                              gd,
    1989              :                                              GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    1990              : 
    1991              :       }
    1992          105 :       switch (meta.cipher)
    1993              :       {
    1994           52 :       case GNUNET_CRYPTO_BSA_RSA:
    1995              :         key_spec =
    1996           52 :           GNUNET_JSON_pack_rsa_public_key (
    1997              :             "rsa_pub",
    1998           52 :             dk->key.bsign_pub_key->details.rsa_public_key);
    1999           52 :         break;
    2000           53 :       case GNUNET_CRYPTO_BSA_CS:
    2001              :         key_spec =
    2002           53 :           GNUNET_JSON_pack_data_varsize (
    2003              :             "cs_pub",
    2004           53 :             &dk->key.bsign_pub_key->details.cs_public_key,
    2005              :             sizeof (dk->key.bsign_pub_key->details.cs_public_key));
    2006           53 :         break;
    2007            0 :       default:
    2008            0 :         GNUNET_assert (false);
    2009              :       }
    2010          105 :       denom = GNUNET_JSON_PACK (
    2011              :         GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
    2012              :                                     dk->expire_deposit),
    2013              :         GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
    2014              :                                     dk->withdraw_valid_until),
    2015              :         GNUNET_JSON_pack_timestamp ("stamp_start",
    2016              :                                     dk->valid_from),
    2017              :         GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
    2018              :                                     dk->expire_legal),
    2019              :         GNUNET_JSON_pack_data_auto ("master_sig",
    2020              :                                     &dk->master_sig),
    2021              :         key_spec
    2022              :         );
    2023          105 :       GNUNET_assert (0 ==
    2024              :                      json_array_append_new (gd->json,
    2025              :                                             denom));
    2026              :     }
    2027            8 :     GNUNET_CONTAINER_multihashmap_iterate (dbg,
    2028              :                                            &add_grp,
    2029              :                                            denominations_by_group);
    2030            8 :     GNUNET_CONTAINER_multihashmap_destroy (dbg);
    2031              :   }
    2032              : 
    2033            8 :   auditors = json_array ();
    2034            8 :   GNUNET_assert (NULL != auditors);
    2035           10 :   for (unsigned int i = 0; i<kd->num_auditors; i++)
    2036              :   {
    2037            2 :     const struct TALER_EXCHANGE_AuditorInformation *ai = &kd->auditors[i];
    2038              :     json_t *a;
    2039              :     json_t *adenoms;
    2040              : 
    2041            2 :     adenoms = json_array ();
    2042            2 :     GNUNET_assert (NULL != adenoms);
    2043            2 :     for (unsigned int j = 0; j<ai->num_denom_keys; j++)
    2044              :     {
    2045            0 :       const struct TALER_EXCHANGE_AuditorDenominationInfo *adi =
    2046            0 :         &ai->denom_keys[j];
    2047            0 :       const struct TALER_EXCHANGE_DenomPublicKey *dk =
    2048            0 :         &kd->denom_keys[adi->denom_key_offset];
    2049              :       json_t *k;
    2050              : 
    2051            0 :       GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys);
    2052            0 :       if (GNUNET_TIME_timestamp_cmp (now,
    2053              :                                      >,
    2054              :                                      dk->expire_deposit))
    2055            0 :         continue; /* skip auditor signatures for denomination keys that have expired */
    2056            0 :       GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys);
    2057            0 :       k = GNUNET_JSON_PACK (
    2058              :         GNUNET_JSON_pack_data_auto ("denom_pub_h",
    2059              :                                     &dk->h_key),
    2060              :         GNUNET_JSON_pack_data_auto ("auditor_sig",
    2061              :                                     &adi->auditor_sig));
    2062            0 :       GNUNET_assert (0 ==
    2063              :                      json_array_append_new (adenoms,
    2064              :                                             k));
    2065              :     }
    2066              : 
    2067            2 :     a = GNUNET_JSON_PACK (
    2068              :       GNUNET_JSON_pack_data_auto ("auditor_pub",
    2069              :                                   &ai->auditor_pub),
    2070              :       GNUNET_JSON_pack_string ("auditor_url",
    2071              :                                ai->auditor_url),
    2072              :       GNUNET_JSON_pack_string ("auditor_name",
    2073              :                                ai->auditor_name),
    2074              :       GNUNET_JSON_pack_array_steal ("denomination_keys",
    2075              :                                     adenoms));
    2076            2 :     GNUNET_assert (0 ==
    2077              :                    json_array_append_new (auditors,
    2078              :                                           a));
    2079              :   }
    2080              : 
    2081            8 :   global_fees = json_array ();
    2082            8 :   GNUNET_assert (NULL != global_fees);
    2083           24 :   for (unsigned int i = 0; i<kd->num_global_fees; i++)
    2084              :   {
    2085           16 :     const struct TALER_EXCHANGE_GlobalFee *gf
    2086           16 :       = &kd->global_fees[i];
    2087              : 
    2088           16 :     if (GNUNET_TIME_absolute_is_past (gf->end_date.abs_time))
    2089            0 :       continue;
    2090           16 :     GNUNET_assert (
    2091              :       0 ==
    2092              :       json_array_append_new (
    2093              :         global_fees,
    2094              :         GNUNET_JSON_PACK (
    2095              :           GNUNET_JSON_pack_timestamp ("start_date",
    2096              :                                       gf->start_date),
    2097              :           GNUNET_JSON_pack_timestamp ("end_date",
    2098              :                                       gf->end_date),
    2099              :           TALER_JSON_PACK_GLOBAL_FEES (&gf->fees),
    2100              :           GNUNET_JSON_pack_time_rel ("history_expiration",
    2101              :                                      gf->history_expiration),
    2102              :           GNUNET_JSON_pack_time_rel ("purse_timeout",
    2103              :                                      gf->purse_timeout),
    2104              :           GNUNET_JSON_pack_uint64 ("purse_account_limit",
    2105              :                                    gf->purse_account_limit),
    2106              :           GNUNET_JSON_pack_data_auto ("master_sig",
    2107              :                                       &gf->master_sig))));
    2108              :   }
    2109              : 
    2110            8 :   accounts = json_array ();
    2111            8 :   GNUNET_assert (NULL != accounts);
    2112           16 :   for (unsigned int i = 0; i<kd->accounts_len; i++)
    2113              :   {
    2114            8 :     const struct TALER_EXCHANGE_WireAccount *acc
    2115            8 :       = &kd->accounts[i];
    2116              :     json_t *credit_restrictions;
    2117              :     json_t *debit_restrictions;
    2118              : 
    2119              :     credit_restrictions
    2120            8 :       = ar_to_json (acc->credit_restrictions_length,
    2121            8 :                     acc->credit_restrictions);
    2122            8 :     GNUNET_assert (NULL != credit_restrictions);
    2123              :     debit_restrictions
    2124            8 :       = ar_to_json (acc->debit_restrictions_length,
    2125            8 :                     acc->debit_restrictions);
    2126            8 :     GNUNET_assert (NULL != debit_restrictions);
    2127            8 :     GNUNET_assert (
    2128              :       0 ==
    2129              :       json_array_append_new (
    2130              :         accounts,
    2131              :         GNUNET_JSON_PACK (
    2132              :           TALER_JSON_pack_full_payto ("payto_uri",
    2133              :                                       acc->fpayto_uri),
    2134              :           GNUNET_JSON_pack_allow_null (
    2135              :             GNUNET_JSON_pack_string ("conversion_url",
    2136              :                                      acc->conversion_url)),
    2137              :           GNUNET_JSON_pack_allow_null (
    2138              :             GNUNET_JSON_pack_string ("open_banking_gateway",
    2139              :                                      acc->open_banking_gateway)),
    2140              :           GNUNET_JSON_pack_allow_null (
    2141              :             GNUNET_JSON_pack_string ("wire_transfer_gateway",
    2142              :                                      acc->wire_transfer_gateway)),
    2143              :           GNUNET_JSON_pack_int64 ("priority",
    2144              :                                   acc->priority),
    2145              :           GNUNET_JSON_pack_allow_null (
    2146              :             GNUNET_JSON_pack_string ("bank_label",
    2147              :                                      acc->bank_label)),
    2148              :           GNUNET_JSON_pack_array_steal ("debit_restrictions",
    2149              :                                         debit_restrictions),
    2150              :           GNUNET_JSON_pack_array_steal ("credit_restrictions",
    2151              :                                         credit_restrictions),
    2152              :           GNUNET_JSON_pack_data_auto ("master_sig",
    2153              :                                       &acc->master_sig))));
    2154              :   }
    2155            8 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2156              :               "Serialized %u/%u wire accounts to JSON\n",
    2157              :               (unsigned int) json_array_size (accounts),
    2158              :               kd->accounts_len);
    2159              : 
    2160            8 :   wire_fees = json_object ();
    2161            8 :   GNUNET_assert (NULL != wire_fees);
    2162           16 :   for (unsigned int i = 0; i<kd->fees_len; i++)
    2163              :   {
    2164            8 :     const struct TALER_EXCHANGE_WireFeesByMethod *fbw
    2165            8 :       = &kd->fees[i];
    2166              :     json_t *wf;
    2167              : 
    2168            8 :     wf = json_array ();
    2169            8 :     GNUNET_assert (NULL != wf);
    2170            8 :     for (struct TALER_EXCHANGE_WireAggregateFees *p = fbw->fees_head;
    2171           24 :          NULL != p;
    2172           16 :          p = p->next)
    2173              :     {
    2174           16 :       GNUNET_assert (
    2175              :         0 ==
    2176              :         json_array_append_new (
    2177              :           wf,
    2178              :           GNUNET_JSON_PACK (
    2179              :             TALER_JSON_pack_amount ("wire_fee",
    2180              :                                     &p->fees.wire),
    2181              :             TALER_JSON_pack_amount ("closing_fee",
    2182              :                                     &p->fees.closing),
    2183              :             GNUNET_JSON_pack_timestamp ("start_date",
    2184              :                                         p->start_date),
    2185              :             GNUNET_JSON_pack_timestamp ("end_date",
    2186              :                                         p->end_date),
    2187              :             GNUNET_JSON_pack_data_auto ("sig",
    2188              :                                         &p->master_sig))));
    2189              :     }
    2190            8 :     GNUNET_assert (0 ==
    2191              :                    json_object_set_new (wire_fees,
    2192              :                                         fbw->method,
    2193              :                                         wf));
    2194              :   }
    2195              : 
    2196            8 :   recoup = json_array ();
    2197            8 :   GNUNET_assert (NULL != recoup);
    2198          113 :   for (unsigned int i = 0; i<kd->num_denom_keys; i++)
    2199              :   {
    2200          105 :     const struct TALER_EXCHANGE_DenomPublicKey *dk
    2201          105 :       = &kd->denom_keys[i];
    2202          105 :     if (! dk->revoked)
    2203          105 :       continue;
    2204            0 :     GNUNET_assert (0 ==
    2205              :                    json_array_append_new (
    2206              :                      recoup,
    2207              :                      GNUNET_JSON_PACK (
    2208              :                        GNUNET_JSON_pack_data_auto ("h_denom_pub",
    2209              :                                                    &dk->h_key))));
    2210              :   }
    2211              : 
    2212            8 :   wblwk = json_array ();
    2213            8 :   GNUNET_assert (NULL != wblwk);
    2214            8 :   for (unsigned int i = 0; i<kd->wblwk_length; i++)
    2215              :   {
    2216            0 :     const struct TALER_Amount *a = &kd->wallet_balance_limit_without_kyc[i];
    2217              : 
    2218            0 :     GNUNET_assert (0 ==
    2219              :                    json_array_append_new (
    2220              :                      wblwk,
    2221              :                      TALER_JSON_from_amount (a)));
    2222              :   }
    2223              : 
    2224            8 :   hard_limits = json_array ();
    2225            8 :   for (unsigned int i = 0; i < kd->hard_limits_length; i++)
    2226              :   {
    2227            0 :     const struct TALER_EXCHANGE_AccountLimit *al
    2228            0 :       = &kd->hard_limits[i];
    2229              :     json_t *j;
    2230              : 
    2231            0 :     j = GNUNET_JSON_PACK (
    2232              :       TALER_JSON_pack_amount ("threshold",
    2233              :                               &al->threshold),
    2234              :       GNUNET_JSON_pack_time_rel ("timeframe",
    2235              :                                  al->timeframe),
    2236              :       TALER_JSON_pack_kycte ("operation_type",
    2237              :                              al->operation_type),
    2238              :       GNUNET_JSON_pack_bool ("soft_limit",
    2239              :                              al->soft_limit)
    2240              :       );
    2241            0 :     GNUNET_assert (0 ==
    2242              :                    json_array_append_new (
    2243              :                      hard_limits,
    2244              :                      j));
    2245              :   }
    2246              : 
    2247            8 :   zero_limits = json_array ();
    2248           10 :   for (unsigned int i = 0; i < kd->zero_limits_length; i++)
    2249              :   {
    2250            2 :     const struct TALER_EXCHANGE_ZeroLimitedOperation *zol
    2251            2 :       = &kd->zero_limits[i];
    2252              :     json_t *j;
    2253              : 
    2254            2 :     j = GNUNET_JSON_PACK (
    2255              :       TALER_JSON_pack_kycte ("operation_type",
    2256              :                              zol->operation_type)
    2257              :       );
    2258            2 :     GNUNET_assert (0 ==
    2259              :                    json_array_append_new (
    2260              :                      zero_limits,
    2261              :                      j));
    2262              :   }
    2263              : 
    2264            8 :   wads_json = json_array ();
    2265            8 :   GNUNET_assert (NULL != wads_json);
    2266            8 :   for (unsigned int i = 0; i < kd->num_wad_partners; i++)
    2267              :   {
    2268            0 :     const struct TALER_EXCHANGE_WadPartner *wp
    2269            0 :       = &kd->wad_partners[i];
    2270              : 
    2271            0 :     GNUNET_assert (
    2272              :       0 ==
    2273              :       json_array_append_new (
    2274              :         wads_json,
    2275              :         GNUNET_JSON_PACK (
    2276              :           GNUNET_JSON_pack_string ("partner_base_url",
    2277              :                                    wp->partner_base_url),
    2278              :           GNUNET_JSON_pack_data_auto ("partner_master_pub",
    2279              :                                       &wp->partner_master_pub),
    2280              :           TALER_JSON_pack_amount ("wad_fee",
    2281              :                                   &wp->wad_fee),
    2282              :           GNUNET_JSON_pack_time_rel ("wad_frequency",
    2283              :                                      wp->wad_frequency),
    2284              :           GNUNET_JSON_pack_timestamp ("start_date",
    2285              :                                       wp->start_date),
    2286              :           GNUNET_JSON_pack_timestamp ("end_date",
    2287              :                                       wp->end_date),
    2288              :           GNUNET_JSON_pack_data_auto ("master_sig",
    2289              :                                       &wp->master_sig))));
    2290              :   }
    2291              : 
    2292            8 :   keys = GNUNET_JSON_PACK (
    2293              :     GNUNET_JSON_pack_string ("version",
    2294              :                              kd->version),
    2295              :     GNUNET_JSON_pack_string ("currency",
    2296              :                              kd->currency),
    2297              :     GNUNET_JSON_pack_object_steal ("currency_specification",
    2298              :                                    TALER_JSON_currency_specs_to_json (
    2299              :                                      &kd->cspec)),
    2300              :     TALER_JSON_pack_amount ("stefan_abs",
    2301              :                             &kd->stefan_abs),
    2302              :     TALER_JSON_pack_amount ("stefan_log",
    2303              :                             &kd->stefan_log),
    2304              :     GNUNET_JSON_pack_double ("stefan_lin",
    2305              :                              kd->stefan_lin),
    2306              :     GNUNET_JSON_pack_allow_null (
    2307              :       kd->tiny_amount_available
    2308              :       ? TALER_JSON_pack_amount ("tiny_amount",
    2309              :                                 &kd->tiny_amount)
    2310              :       : GNUNET_JSON_pack_string ("dummy",
    2311              :                                  NULL)),
    2312              :     GNUNET_JSON_pack_string ("asset_type",
    2313              :                              kd->asset_type),
    2314              :     GNUNET_JSON_pack_allow_null (
    2315              :       GNUNET_JSON_pack_string ("shopping_url",
    2316              :                                kd->shopping_url)),
    2317              :     GNUNET_JSON_pack_allow_null (
    2318              :       GNUNET_JSON_pack_string ("bank_compliance_language",
    2319              :                                kd->bank_compliance_language)),
    2320              :     GNUNET_JSON_pack_bool ("disable_direct_deposit",
    2321              :                            kd->disable_direct_deposit),
    2322              :     GNUNET_JSON_pack_data_auto ("master_public_key",
    2323              :                                 &kd->master_pub),
    2324              :     GNUNET_JSON_pack_time_rel ("reserve_closing_delay",
    2325              :                                kd->reserve_closing_delay),
    2326              :     GNUNET_JSON_pack_allow_null (
    2327              :       GNUNET_TIME_relative_is_zero (kd->default_p2p_push_expiration)
    2328              :       ? GNUNET_JSON_pack_string ("dummy",
    2329              :                                  NULL)
    2330              :       : GNUNET_JSON_pack_time_rel ("default_p2p_push_expiration",
    2331              :                                    kd->default_p2p_push_expiration)),
    2332              :     GNUNET_JSON_pack_timestamp ("list_issue_date",
    2333              :                                 kd->list_issue_date),
    2334              :     GNUNET_JSON_pack_array_steal ("global_fees",
    2335              :                                   global_fees),
    2336              :     GNUNET_JSON_pack_array_steal ("signkeys",
    2337              :                                   signkeys),
    2338              :     GNUNET_JSON_pack_object_steal ("wire_fees",
    2339              :                                    wire_fees),
    2340              :     GNUNET_JSON_pack_array_steal ("accounts",
    2341              :                                   accounts),
    2342              :     GNUNET_JSON_pack_array_steal ("wads",
    2343              :                                   wads_json),
    2344              :     GNUNET_JSON_pack_array_steal ("hard_limits",
    2345              :                                   hard_limits),
    2346              :     GNUNET_JSON_pack_array_steal ("zero_limits",
    2347              :                                   zero_limits),
    2348              :     GNUNET_JSON_pack_array_steal ("denominations",
    2349              :                                   denominations_by_group),
    2350              :     GNUNET_JSON_pack_allow_null (
    2351              :       GNUNET_JSON_pack_array_steal ("recoup",
    2352              :                                     recoup)),
    2353              :     GNUNET_JSON_pack_array_steal ("auditors",
    2354              :                                   auditors),
    2355              :     GNUNET_JSON_pack_bool ("kyc_enabled",
    2356              :                            kd->kyc_enabled),
    2357              :     GNUNET_JSON_pack_allow_null (
    2358              :       GNUNET_JSON_pack_object_incref ("extensions",
    2359              :                                       kd->extensions)),
    2360              :     GNUNET_JSON_pack_allow_null (
    2361              :       GNUNET_is_zero (&kd->extensions_sig)
    2362              :       ? GNUNET_JSON_pack_string ("dummy",
    2363              :                                  NULL)
    2364              :       : GNUNET_JSON_pack_data_auto ("extensions_sig",
    2365              :                                     &kd->extensions_sig)),
    2366              :     GNUNET_JSON_pack_allow_null (
    2367              :       GNUNET_JSON_pack_array_steal ("wallet_balance_limit_without_kyc",
    2368              :                                     wblwk))
    2369              : 
    2370              :     );
    2371            8 :   return GNUNET_JSON_PACK (
    2372              :     GNUNET_JSON_pack_uint64 ("version",
    2373              :                              EXCHANGE_SERIALIZATION_FORMAT_VERSION),
    2374              :     GNUNET_JSON_pack_allow_null (
    2375              :       GNUNET_JSON_pack_timestamp ("expire",
    2376              :                                   kd->key_data_expiration)),
    2377              :     GNUNET_JSON_pack_string ("exchange_url",
    2378              :                              kd->exchange_url),
    2379              :     GNUNET_JSON_pack_object_steal ("keys",
    2380              :                                    keys));
    2381              : }
    2382              : 
    2383              : 
    2384              : /* end of exchange_api_handle.c */
        

Generated by: LCOV version 2.0-1