exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

exchange_api_handle.c (82848B)


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