LCOV - code coverage report
Current view: top level - lib - exchange_api_handle.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 73.6 % 863 635
Test Date: 2026-01-04 22:17:00 Functions: 100.0 % 30 30

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2014-2023 Taler Systems SA
       4              : 
       5              :   TALER is free software; you can redistribute it and/or modify it
       6              :   under the terms of the GNU General Public License as published
       7              :   by the Free Software Foundation; either version 3, or (at your
       8              :   option) any later version.
       9              : 
      10              :   TALER is distributed in the hope that it will be useful, but
      11              :   WITHOUT ANY WARRANTY; without even the implied warranty of
      12              :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13              :   GNU General Public License for more details.
      14              : 
      15              :   You should have received a copy of the GNU General Public
      16              :   License along with TALER; see the file COPYING.  If not, see
      17              :   <http://www.gnu.org/licenses/>
      18              : */
      19              : 
      20              : /**
      21              :  * @file lib/exchange_api_handle.c
      22              :  * @brief Implementation of the "handle" component of the exchange's HTTP API
      23              :  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
      24              :  * @author Christian Grothoff
      25              :  */
      26              : #include "taler/platform.h"
      27              : #include <microhttpd.h>
      28              : #include <gnunet/gnunet_curl_lib.h>
      29              : #include "taler/taler_json_lib.h"
      30              : #include "taler/taler_exchange_service.h"
      31              : #include "taler/taler_auditor_service.h"
      32              : #include "taler/taler_signatures.h"
      33              : #include "taler/taler_extensions.h"
      34              : #include "exchange_api_handle.h"
      35              : #include "exchange_api_curl_defaults.h"
      36              : #include "taler/backoff.h"
      37              : #include "taler/taler_curl_lib.h"
      38              : 
      39              : /**
      40              :  * Which version of the Taler protocol is implemented
      41              :  * by this library?  Used to determine compatibility.
      42              :  */
      43              : #define EXCHANGE_PROTOCOL_CURRENT 32
      44              : 
      45              : /**
      46              :  * How many versions are we backwards compatible with?
      47              :  */
      48              : #define EXCHANGE_PROTOCOL_AGE 6
      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        42606 : signature_context_sort_cb (const void *a,
     184              :                            const void *b)
     185              : {
     186        42606 :   const struct SignatureElement *sa = a;
     187        42606 :   const struct SignatureElement *sb = b;
     188              : 
     189        42606 :   if (sa->group_offset < sb->group_offset)
     190        14580 :     return -1;
     191        28026 :   if (sa->group_offset > sb->group_offset)
     192            0 :     return 1;
     193        28026 :   if (sa->offset < sb->offset)
     194        28026 :     return -1;
     195            0 :   if (sa->offset > sb->offset)
     196            0 :     return 1;
     197              :   /* We should never have two disjoint elements
     198              :      with same time and offset */
     199            0 :   GNUNET_assert (sa == sb);
     200            0 :   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         9648 : 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         9648 :   if (sig_ctx->elements_pos == sig_ctx->elements_size)
     223              :   {
     224           34 :     if (0 == sig_ctx->elements_size)
     225           34 :       new_size = 1024;
     226              :     else
     227            0 :       new_size = sig_ctx->elements_size * 2;
     228           34 :     GNUNET_array_grow (sig_ctx->elements,
     229              :                        sig_ctx->elements_size,
     230              :                        new_size);
     231              :   }
     232         9648 :   element = &sig_ctx->elements[sig_ctx->elements_pos++];
     233         9648 :   element->offset = offset;
     234         9648 :   element->group_offset = group_offset;
     235         9648 :   element->master_sig = *master_sig;
     236         9648 : }
     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           42 : free_fees (struct TALER_EXCHANGE_WireFeesByMethod *wfm,
     247              :            unsigned int wfm_len)
     248              : {
     249           84 :   for (unsigned int i = 0; i<wfm_len; i++)
     250              :   {
     251           42 :     struct TALER_EXCHANGE_WireFeesByMethod *wfmi = &wfm[i];
     252              : 
     253          126 :     while (NULL != wfmi->fees_head)
     254              :     {
     255           84 :       struct TALER_EXCHANGE_WireAggregateFees *fe
     256              :         = wfmi->fees_head;
     257              : 
     258           84 :       wfmi->fees_head = fe->next;
     259           84 :       GNUNET_free (fe);
     260              :     }
     261           42 :     GNUNET_free (wfmi->method);
     262              :   }
     263           42 :   GNUNET_free (wfm);
     264           42 : }
     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           42 : 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           42 :   size_t fbml = json_object_size (fees);
     284           42 :   unsigned int i = 0;
     285              :   const char *key;
     286              :   const json_t *fee_array;
     287              : 
     288           42 :   if (UINT_MAX < fbml)
     289              :   {
     290            0 :     GNUNET_break (0);
     291            0 :     return NULL;
     292              :   }
     293           42 :   fbm = GNUNET_new_array (fbml,
     294              :                           struct TALER_EXCHANGE_WireFeesByMethod);
     295           42 :   *fees_len = (unsigned int) fbml;
     296           84 :   json_object_foreach ((json_t *) fees, key, fee_array) {
     297           42 :     struct TALER_EXCHANGE_WireFeesByMethod *fe = &fbm[i++];
     298              :     size_t idx;
     299              :     json_t *fee;
     300              : 
     301           42 :     fe->method = GNUNET_strdup (key);
     302           42 :     fe->fees_head = NULL;
     303          126 :     json_array_foreach (fee_array, idx, fee)
     304              :     {
     305              :       struct TALER_EXCHANGE_WireAggregateFees *wa
     306           84 :         = GNUNET_new (struct TALER_EXCHANGE_WireAggregateFees);
     307              :       struct GNUNET_JSON_Specification spec[] = {
     308           84 :         GNUNET_JSON_spec_fixed_auto ("sig",
     309              :                                      &wa->master_sig),
     310           84 :         TALER_JSON_spec_amount ("wire_fee",
     311              :                                 currency,
     312              :                                 &wa->fees.wire),
     313           84 :         TALER_JSON_spec_amount ("closing_fee",
     314              :                                 currency,
     315              :                                 &wa->fees.closing),
     316           84 :         GNUNET_JSON_spec_timestamp ("start_date",
     317              :                                     &wa->start_date),
     318           84 :         GNUNET_JSON_spec_timestamp ("end_date",
     319              :                                     &wa->end_date),
     320           84 :         GNUNET_JSON_spec_end ()
     321              :       };
     322              : 
     323           84 :       wa->next = fe->fees_head;
     324           84 :       fe->fees_head = wa;
     325           84 :       if (GNUNET_OK !=
     326           84 :           GNUNET_JSON_parse (fee,
     327              :                              spec,
     328              :                              NULL,
     329              :                              NULL))
     330              :       {
     331            0 :         GNUNET_break_op (0);
     332            0 :         free_fees (fbm,
     333              :                    i);
     334            0 :         return NULL;
     335              :       }
     336           84 :       if (GNUNET_OK !=
     337           84 :           TALER_exchange_offline_wire_fee_verify (
     338              :             key,
     339              :             wa->start_date,
     340              :             wa->end_date,
     341           84 :             &wa->fees,
     342              :             master_pub,
     343           84 :             &wa->master_sig))
     344              :       {
     345            0 :         GNUNET_break_op (0);
     346            0 :         free_fees (fbm,
     347              :                    i);
     348            0 :         return NULL;
     349              :       }
     350              :     } /* for all fees over time */
     351              :   } /* for all methods */
     352           42 :   GNUNET_assert (i == fbml);
     353           42 :   return fbm;
     354              : }
     355              : 
     356              : 
     357              : void
     358           84 : TEAH_get_auditors_for_dc (
     359              :   struct TALER_EXCHANGE_Keys *keys,
     360              :   TEAH_AuditorCallback ac,
     361              :   void *ac_cls)
     362              : {
     363           84 :   if (0 == keys->num_auditors)
     364              :   {
     365           52 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     366              :                 "No auditor available. Not submitting deposit confirmations.\n")
     367              :     ;
     368           52 :     return;
     369              :   }
     370           64 :   for (unsigned int i = 0; i<keys->num_auditors; i++)
     371              :   {
     372           32 :     const struct TALER_EXCHANGE_AuditorInformation *auditor
     373           32 :       = &keys->auditors[i];
     374              : 
     375           32 :     ac (ac_cls,
     376           32 :         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          129 : 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          129 :     GNUNET_JSON_spec_fixed_auto ("master_sig",
     406              :                                  &sign_key->master_sig),
     407          129 :     GNUNET_JSON_spec_fixed_auto ("key",
     408              :                                  &sign_key->key),
     409          129 :     GNUNET_JSON_spec_timestamp ("stamp_start",
     410              :                                 &sign_key->valid_from),
     411          129 :     GNUNET_JSON_spec_timestamp ("stamp_expire",
     412              :                                 &sign_key->valid_until),
     413          129 :     GNUNET_JSON_spec_timestamp ("stamp_end",
     414              :                                 &sign_key->valid_legal),
     415          129 :     GNUNET_JSON_spec_end ()
     416              :   };
     417              : 
     418          129 :   if (GNUNET_OK !=
     419          129 :       GNUNET_JSON_parse (sign_key_obj,
     420              :                          spec,
     421              :                          NULL, NULL))
     422              :   {
     423            0 :     GNUNET_break_op (0);
     424            0 :     return GNUNET_SYSERR;
     425              :   }
     426          129 :   if (! check_sigs)
     427           16 :     return GNUNET_OK;
     428          113 :   if (GNUNET_OK !=
     429          113 :       TALER_exchange_offline_signkey_validity_verify (
     430          113 :         &sign_key->key,
     431              :         sign_key->valid_from,
     432              :         sign_key->valid_until,
     433              :         sign_key->valid_legal,
     434              :         master_key,
     435          113 :         &sign_key->master_sig))
     436              :   {
     437            0 :     GNUNET_break_op (0);
     438            0 :     return GNUNET_SYSERR;
     439              :   }
     440          113 :   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        10745 : 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        10745 :     GNUNET_JSON_spec_fixed_auto ("master_sig",
     477              :                                  &denom_key->master_sig),
     478        10745 :     GNUNET_JSON_spec_timestamp ("stamp_expire_deposit",
     479              :                                 &denom_key->expire_deposit),
     480        10745 :     GNUNET_JSON_spec_timestamp ("stamp_expire_withdraw",
     481              :                                 &denom_key->withdraw_valid_until),
     482        10745 :     GNUNET_JSON_spec_timestamp ("stamp_start",
     483              :                                 &denom_key->valid_from),
     484        10745 :     GNUNET_JSON_spec_timestamp ("stamp_expire_legal",
     485              :                                 &denom_key->expire_legal),
     486        10745 :     GNUNET_JSON_spec_mark_optional (
     487              :       GNUNET_JSON_spec_bool ("lost",
     488              :                              &denom_key->lost),
     489              :       NULL),
     490        10745 :     TALER_JSON_spec_denom_pub_cipher (NULL,
     491              :                                       cipher,
     492              :                                       &denom_key->key),
     493        10745 :     GNUNET_JSON_spec_end ()
     494              :   };
     495              : 
     496        10745 :   if (GNUNET_OK !=
     497        10745 :       GNUNET_JSON_parse (denom_key_obj,
     498              :                          spec,
     499              :                          NULL, NULL))
     500              :   {
     501            0 :     GNUNET_break_op (0);
     502            0 :     return GNUNET_SYSERR;
     503              :   }
     504        10745 :   TALER_denom_pub_hash (&denom_key->key,
     505              :                         &denom_key->h_key);
     506        10745 :   if (NULL != sig_ctx)
     507         9648 :     append_signature (sig_ctx,
     508              :                       group_offset,
     509              :                       index,
     510         9648 :                       &denom_key->master_sig);
     511        10745 :   if (! check_sigs)
     512         1097 :     return GNUNET_OK;
     513         9648 :   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         9648 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     525              :               "Learned denomination key %s\n",
     526              :               GNUNET_h2s (&denom_key->h_key.hash));
     527         9648 :   return GNUNET_OK;
     528            0 : EXITIF_exit:
     529            0 :   GNUNET_JSON_parse_free (spec);
     530              :   /* invalidate denom_key, just to be sure */
     531            0 :   memset (denom_key,
     532              :           0,
     533              :           sizeof (*denom_key));
     534            0 :   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           12 : 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           12 :     GNUNET_JSON_spec_fixed_auto ("auditor_pub",
     561              :                                  &auditor->auditor_pub),
     562           12 :     TALER_JSON_spec_web_url ("auditor_url",
     563              :                              &auditor_url),
     564           12 :     GNUNET_JSON_spec_array_const ("denomination_keys",
     565              :                                   &keys),
     566           12 :     GNUNET_JSON_spec_end ()
     567              :   };
     568              : 
     569           12 :   if (GNUNET_OK !=
     570           12 :       GNUNET_JSON_parse (auditor_obj,
     571              :                          spec,
     572              :                          NULL, NULL))
     573              :   {
     574            0 :     GNUNET_break_op (0);
     575              : #if DEBUG
     576              :     json_dumpf (auditor_obj,
     577              :                 stderr,
     578              :                 JSON_INDENT (2));
     579              : #endif
     580            0 :     return GNUNET_SYSERR;
     581              :   }
     582           12 :   auditor->auditor_url = GNUNET_strdup (auditor_url);
     583              :   auditor->denom_keys
     584           12 :     = GNUNET_new_array (json_array_size (keys),
     585              :                         struct TALER_EXCHANGE_AuditorDenominationInfo);
     586           12 :   pos = 0;
     587           12 :   json_array_foreach (keys, off, key) {
     588              :     struct TALER_AuditorSignatureP auditor_sig;
     589              :     struct TALER_DenominationHashP denom_h;
     590            0 :     const struct TALER_EXCHANGE_DenomPublicKey *dk = NULL;
     591            0 :     unsigned int dk_off = UINT_MAX;
     592              :     struct GNUNET_JSON_Specification kspec[] = {
     593            0 :       GNUNET_JSON_spec_fixed_auto ("auditor_sig",
     594              :                                    &auditor_sig),
     595            0 :       GNUNET_JSON_spec_fixed_auto ("denom_pub_h",
     596              :                                    &denom_h),
     597            0 :       GNUNET_JSON_spec_end ()
     598              :     };
     599              : 
     600            0 :     if (GNUNET_OK !=
     601            0 :         GNUNET_JSON_parse (key,
     602              :                            kspec,
     603              :                            NULL, NULL))
     604              :     {
     605            0 :       GNUNET_break_op (0);
     606            0 :       continue;
     607              :     }
     608            0 :     for (unsigned int j = 0; j<key_data->num_denom_keys; j++)
     609              :     {
     610            0 :       if (0 == GNUNET_memcmp (&denom_h,
     611              :                               &key_data->denom_keys[j].h_key))
     612              :       {
     613            0 :         dk = &key_data->denom_keys[j];
     614            0 :         dk_off = j;
     615            0 :         break;
     616              :       }
     617              :     }
     618            0 :     if (NULL == dk)
     619              :     {
     620            0 :       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            0 :       continue;
     624              :     }
     625            0 :     if (check_sigs)
     626              :     {
     627            0 :       if (GNUNET_OK !=
     628            0 :           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            0 :             &auditor->auditor_pub,
     639              :             &auditor_sig))
     640              :       {
     641            0 :         GNUNET_break_op (0);
     642            0 :         return GNUNET_SYSERR;
     643              :       }
     644              :     }
     645            0 :     auditor->denom_keys[pos].denom_key_offset = dk_off;
     646            0 :     auditor->denom_keys[pos].auditor_sig = auditor_sig;
     647            0 :     pos++;
     648              :   }
     649           12 :   if (pos > UINT_MAX)
     650              :   {
     651            0 :     GNUNET_break (0);
     652            0 :     return GNUNET_SYSERR;
     653              :   }
     654           12 :   auditor->num_denom_keys = (unsigned int) pos;
     655           12 :   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           84 : 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           84 :     GNUNET_JSON_spec_timestamp ("start_date",
     677              :                                 &gf->start_date),
     678           84 :     GNUNET_JSON_spec_timestamp ("end_date",
     679              :                                 &gf->end_date),
     680           84 :     GNUNET_JSON_spec_relative_time ("purse_timeout",
     681              :                                     &gf->purse_timeout),
     682           84 :     GNUNET_JSON_spec_relative_time ("history_expiration",
     683              :                                     &gf->history_expiration),
     684           84 :     GNUNET_JSON_spec_uint32 ("purse_account_limit",
     685              :                              &gf->purse_account_limit),
     686           84 :     TALER_JSON_SPEC_GLOBAL_FEES (key_data->currency,
     687              :                                  &gf->fees),
     688           84 :     GNUNET_JSON_spec_fixed_auto ("master_sig",
     689              :                                  &gf->master_sig),
     690           84 :     GNUNET_JSON_spec_end ()
     691              :   };
     692              : 
     693           84 :   if (GNUNET_OK !=
     694           84 :       GNUNET_JSON_parse (fee_obj,
     695              :                          spec,
     696              :                          NULL, NULL))
     697              :   {
     698            0 :     GNUNET_break_op (0);
     699              : #if DEBUG
     700              :     json_dumpf (fee_obj,
     701              :                 stderr,
     702              :                 JSON_INDENT (2));
     703              : #endif
     704            0 :     return GNUNET_SYSERR;
     705              :   }
     706           84 :   if (check_sigs)
     707              :   {
     708           68 :     if (GNUNET_OK !=
     709           68 :         TALER_exchange_offline_global_fee_verify (
     710              :           gf->start_date,
     711              :           gf->end_date,
     712           68 :           &gf->fees,
     713              :           gf->purse_timeout,
     714              :           gf->history_expiration,
     715              :           gf->purse_account_limit,
     716              :           &key_data->master_pub,
     717           68 :           &gf->master_sig))
     718              :     {
     719            0 :       GNUNET_break_op (0);
     720            0 :       GNUNET_JSON_parse_free (spec);
     721            0 :       return GNUNET_SYSERR;
     722              :     }
     723              :   }
     724           84 :   GNUNET_JSON_parse_free (spec);
     725           84 :   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      2809480 : 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      2809480 :   if (0 !=
     745      2809480 :       TALER_denom_pub_cmp (&denom1->key,
     746              :                            &denom2->key))
     747      1407550 :     return 1;
     748      1401930 :   tmp1 = *denom1;
     749      1401930 :   tmp2 = *denom2;
     750      1401930 :   tmp1.revoked = false;
     751      1401930 :   tmp2.revoked = false;
     752      1401930 :   memset (&tmp1.key,
     753              :           0,
     754              :           sizeof (tmp1.key));
     755      1401930 :   memset (&tmp2.key,
     756              :           0,
     757              :           sizeof (tmp2.key));
     758      1401930 :   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           42 : 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           42 :     = (unsigned int) json_array_size (hard_limits);
     781           42 :   if ( ((size_t) key_data->hard_limits_length)
     782           42 :        != json_array_size (hard_limits))
     783              :   {
     784            0 :     GNUNET_break (0);
     785            0 :     return GNUNET_SYSERR;
     786              :   }
     787              :   key_data->hard_limits
     788           42 :     = GNUNET_new_array (key_data->hard_limits_length,
     789              :                         struct TALER_EXCHANGE_AccountLimit);
     790              : 
     791           42 :   json_array_foreach (hard_limits, off, obj)
     792              :   {
     793            0 :     struct TALER_EXCHANGE_AccountLimit *al
     794            0 :       = &key_data->hard_limits[off];
     795              :     struct GNUNET_JSON_Specification spec[] = {
     796            0 :       TALER_JSON_spec_kycte ("operation_type",
     797              :                              &al->operation_type),
     798            0 :       TALER_JSON_spec_amount_any ("threshold",
     799              :                                   &al->threshold),
     800            0 :       GNUNET_JSON_spec_relative_time ("timeframe",
     801              :                                       &al->timeframe),
     802            0 :       GNUNET_JSON_spec_end ()
     803              :     };
     804              : 
     805            0 :     if (GNUNET_OK !=
     806            0 :         GNUNET_JSON_parse (obj,
     807              :                            spec,
     808              :                            NULL, NULL))
     809              :     {
     810            0 :       GNUNET_break_op (0);
     811            0 :       return GNUNET_SYSERR;
     812              :     }
     813              :   }
     814           42 :   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           42 : 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           42 :     = (unsigned int) json_array_size (zero_limits);
     836           42 :   if ( ((size_t) key_data->zero_limits_length)
     837           42 :        != json_array_size (zero_limits))
     838              :   {
     839            0 :     GNUNET_break (0);
     840            0 :     return GNUNET_SYSERR;
     841              :   }
     842              :   key_data->zero_limits
     843           42 :     = GNUNET_new_array (key_data->zero_limits_length,
     844              :                         struct TALER_EXCHANGE_ZeroLimitedOperation);
     845              : 
     846           65 :   json_array_foreach (zero_limits, off, obj)
     847              :   {
     848           23 :     struct TALER_EXCHANGE_ZeroLimitedOperation *zol
     849           23 :       = &key_data->zero_limits[off];
     850              :     struct GNUNET_JSON_Specification spec[] = {
     851           23 :       TALER_JSON_spec_kycte ("operation_type",
     852              :                              &zol->operation_type),
     853           23 :       GNUNET_JSON_spec_end ()
     854              :     };
     855              : 
     856           23 :     if (GNUNET_OK !=
     857           23 :         GNUNET_JSON_parse (obj,
     858              :                            spec,
     859              :                            NULL, NULL))
     860              :     {
     861            0 :       GNUNET_break_op (0);
     862            0 :       return GNUNET_SYSERR;
     863              :     }
     864              :   }
     865           42 :   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           42 : 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           42 :   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           42 :   const json_t *recoup_array = NULL;
     894           42 :   const json_t *manifests = NULL;
     895           42 :   bool no_extensions = false;
     896           42 :   bool no_signature = false;
     897              :   const json_t *accounts;
     898              :   const json_t *fees;
     899              :   const json_t *wads;
     900           42 :   struct SignatureContext sig_ctx = { 0 };
     901              : 
     902           42 :   if (JSON_OBJECT != json_typeof (resp_obj))
     903              :   {
     904            0 :     GNUNET_break_op (0);
     905            0 :     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           42 :       TALER_JSON_spec_version ("version",
     917              :                                &pv),
     918           42 :       GNUNET_JSON_spec_end ()
     919              :     };
     920              : 
     921           42 :     if (GNUNET_OK !=
     922           42 :         GNUNET_JSON_parse (resp_obj,
     923              :                            spec,
     924              :                            NULL, NULL))
     925              :     {
     926            0 :       GNUNET_break_op (0);
     927            0 :       return GNUNET_SYSERR;
     928              :     }
     929           42 :     *vc = TALER_EXCHANGE_VC_MATCH;
     930           42 :     if (EXCHANGE_PROTOCOL_CURRENT < pv.current)
     931              :     {
     932            0 :       *vc |= TALER_EXCHANGE_VC_NEWER;
     933            0 :       if (EXCHANGE_PROTOCOL_CURRENT < pv.current - pv.age)
     934            0 :         *vc |= TALER_EXCHANGE_VC_INCOMPATIBLE;
     935              :     }
     936           42 :     if (EXCHANGE_PROTOCOL_CURRENT > pv.current)
     937              :     {
     938            0 :       *vc |= TALER_EXCHANGE_VC_OLDER;
     939            0 :       if (EXCHANGE_PROTOCOL_CURRENT - EXCHANGE_PROTOCOL_AGE > pv.current)
     940            0 :         *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           42 :       GNUNET_JSON_spec_fixed_auto (
     950              :         "exchange_sig",
     951              :         &exchange_sig),
     952           42 :       GNUNET_JSON_spec_fixed_auto (
     953              :         "exchange_pub",
     954              :         &exchange_pub),
     955           42 :       GNUNET_JSON_spec_fixed_auto (
     956              :         "master_public_key",
     957              :         &key_data->master_pub),
     958           42 :       GNUNET_JSON_spec_array_const ("accounts",
     959              :                                     &accounts),
     960           42 :       GNUNET_JSON_spec_object_const ("wire_fees",
     961              :                                      &fees),
     962           42 :       GNUNET_JSON_spec_array_const ("wads",
     963              :                                     &wads),
     964           42 :       GNUNET_JSON_spec_timestamp (
     965              :         "list_issue_date",
     966              :         &key_data->list_issue_date),
     967           42 :       GNUNET_JSON_spec_relative_time (
     968              :         "reserve_closing_delay",
     969              :         &key_data->reserve_closing_delay),
     970           42 :       GNUNET_JSON_spec_string (
     971              :         "currency",
     972              :         &currency),
     973           42 :       GNUNET_JSON_spec_string (
     974              :         "asset_type",
     975              :         &asset_type),
     976           42 :       GNUNET_JSON_spec_array_const (
     977              :         "global_fees",
     978              :         &global_fees),
     979           42 :       GNUNET_JSON_spec_array_const (
     980              :         "signkeys",
     981              :         &sign_keys_array),
     982           42 :       GNUNET_JSON_spec_array_const (
     983              :         "denominations",
     984              :         &denominations_by_group),
     985           42 :       GNUNET_JSON_spec_mark_optional (
     986              :         GNUNET_JSON_spec_array_const (
     987              :           "recoup",
     988              :           &recoup_array),
     989              :         NULL),
     990           42 :       GNUNET_JSON_spec_array_const (
     991              :         "auditors",
     992              :         &auditors_array),
     993           42 :       GNUNET_JSON_spec_bool (
     994              :         "kyc_enabled",
     995              :         &key_data->kyc_enabled),
     996           42 :       GNUNET_JSON_spec_mark_optional (
     997              :         GNUNET_JSON_spec_object_const ("extensions",
     998              :                                        &manifests),
     999              :         &no_extensions),
    1000           42 :       GNUNET_JSON_spec_mark_optional (
    1001           42 :         GNUNET_JSON_spec_fixed_auto (
    1002              :           "extensions_sig",
    1003              :           &key_data->extensions_sig),
    1004              :         &no_signature),
    1005           42 :       GNUNET_JSON_spec_string ("version",
    1006              :                                &ver),
    1007           42 :       GNUNET_JSON_spec_mark_optional (
    1008              :         GNUNET_JSON_spec_array_const (
    1009              :           "wallet_balance_limit_without_kyc",
    1010              :           &wblwk),
    1011              :         NULL),
    1012           42 :       GNUNET_JSON_spec_end ()
    1013              :     };
    1014              :     const char *emsg;
    1015              :     unsigned int eline;
    1016              : 
    1017           42 :     if (GNUNET_OK !=
    1018           42 :         GNUNET_JSON_parse (resp_obj,
    1019              :                            (check_sig) ? mspec : &mspec[2],
    1020              :                            &emsg,
    1021              :                            &eline))
    1022              :     {
    1023            0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1024              :                   "Parsing /keys failed for `%s' (%u)\n",
    1025              :                   emsg,
    1026              :                   eline);
    1027            0 :       EXITIF (1);
    1028              :     }
    1029              :     {
    1030           42 :       const json_t *hard_limits = NULL;
    1031           42 :       const json_t *zero_limits = NULL;
    1032              :       struct GNUNET_JSON_Specification sspec[] = {
    1033           42 :         TALER_JSON_spec_currency_specification (
    1034              :           "currency_specification",
    1035              :           currency,
    1036              :           &key_data->cspec),
    1037           42 :         TALER_JSON_spec_amount (
    1038              :           "stefan_abs",
    1039              :           currency,
    1040              :           &key_data->stefan_abs),
    1041           42 :         TALER_JSON_spec_amount (
    1042              :           "stefan_log",
    1043              :           currency,
    1044              :           &key_data->stefan_log),
    1045           42 :         GNUNET_JSON_spec_mark_optional (
    1046              :           GNUNET_JSON_spec_array_const (
    1047              :             "hard_limits",
    1048              :             &hard_limits),
    1049              :           NULL),
    1050           42 :         GNUNET_JSON_spec_mark_optional (
    1051              :           GNUNET_JSON_spec_array_const (
    1052              :             "zero_limits",
    1053              :             &zero_limits),
    1054              :           NULL),
    1055           42 :         GNUNET_JSON_spec_double (
    1056              :           "stefan_lin",
    1057              :           &key_data->stefan_lin),
    1058           42 :         GNUNET_JSON_spec_end ()
    1059              :       };
    1060              : 
    1061           42 :       if (GNUNET_OK !=
    1062           42 :           GNUNET_JSON_parse (resp_obj,
    1063              :                              sspec,
    1064              :                              &emsg,
    1065              :                              &eline))
    1066              :       {
    1067            0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1068              :                     "Parsing /keys failed for `%s' (%u)\n",
    1069              :                     emsg,
    1070              :                     eline);
    1071            0 :         EXITIF (1);
    1072              :       }
    1073           84 :       if ( (NULL != hard_limits) &&
    1074              :            (GNUNET_OK !=
    1075           42 :             parse_hard_limits (hard_limits,
    1076              :                                key_data)) )
    1077              :       {
    1078            0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1079              :                     "Parsing hard limits of /keys failed\n");
    1080            0 :         EXITIF (1);
    1081              :       }
    1082           84 :       if ( (NULL != zero_limits) &&
    1083              :            (GNUNET_OK !=
    1084           42 :             parse_zero_limits (zero_limits,
    1085              :                                key_data)) )
    1086              :       {
    1087            0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1088              :                     "Parsing hard limits of /keys failed\n");
    1089            0 :         EXITIF (1);
    1090              :       }
    1091              :     }
    1092              : 
    1093           42 :     key_data->currency = GNUNET_strdup (currency);
    1094           42 :     key_data->version = GNUNET_strdup (ver);
    1095           42 :     key_data->asset_type = GNUNET_strdup (asset_type);
    1096           42 :     if (! no_extensions)
    1097           23 :       key_data->extensions = json_incref ((json_t *) manifests);
    1098              :   }
    1099              : 
    1100              :   /* parse the global fees */
    1101           42 :   EXITIF (json_array_size (global_fees) > UINT_MAX);
    1102              :   key_data->num_global_fees
    1103           42 :     = (unsigned int) json_array_size (global_fees);
    1104           42 :   if (0 != key_data->num_global_fees)
    1105              :   {
    1106              :     json_t *global_fee;
    1107              :     size_t index;
    1108              : 
    1109              :     key_data->global_fees
    1110           42 :       = GNUNET_new_array (key_data->num_global_fees,
    1111              :                           struct TALER_EXCHANGE_GlobalFee);
    1112          126 :     json_array_foreach (global_fees, index, global_fee)
    1113              :     {
    1114           84 :       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           42 :   EXITIF (json_array_size (sign_keys_array) > UINT_MAX);
    1124              :   key_data->num_sign_keys
    1125           42 :     = (unsigned int) json_array_size (sign_keys_array);
    1126           42 :   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           42 :       = GNUNET_new_array (key_data->num_sign_keys,
    1133              :                           struct TALER_EXCHANGE_SigningPublicKey);
    1134          171 :     json_array_foreach (sign_keys_array, index, sign_key_obj) {
    1135          129 :       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           42 :   if (NULL != wblwk)
    1145              :   {
    1146           42 :     EXITIF (json_array_size (wblwk) > UINT_MAX);
    1147              :     key_data->wblwk_length
    1148           42 :       = (unsigned int) json_array_size (wblwk);
    1149              :     key_data->wallet_balance_limit_without_kyc
    1150           42 :       = GNUNET_new_array (key_data->wblwk_length,
    1151              :                           struct TALER_Amount);
    1152           43 :     for (unsigned int i = 0; i<key_data->wblwk_length; i++)
    1153              :     {
    1154            1 :       struct TALER_Amount *a = &key_data->wallet_balance_limit_without_kyc[i];
    1155            1 :       const json_t *aj = json_array_get (wblwk,
    1156              :                                          i);
    1157              :       struct GNUNET_JSON_Specification spec[] = {
    1158            1 :         TALER_JSON_spec_amount (NULL,
    1159            1 :                                 key_data->currency,
    1160              :                                 a),
    1161            1 :         GNUNET_JSON_spec_end ()
    1162              :       };
    1163              : 
    1164            1 :       EXITIF (GNUNET_OK !=
    1165              :               GNUNET_JSON_parse (aj,
    1166              :                                  spec,
    1167              :                                  NULL, NULL));
    1168              :     }
    1169              :   }
    1170              : 
    1171              :   /* Parse wire accounts */
    1172           84 :   key_data->fees = parse_fees (&key_data->master_pub,
    1173           42 :                                key_data->currency,
    1174              :                                fees,
    1175              :                                &key_data->fees_len);
    1176           42 :   EXITIF (NULL == key_data->fees);
    1177              :   /* parse accounts */
    1178           42 :   EXITIF (json_array_size (accounts) > UINT_MAX);
    1179           42 :   GNUNET_array_grow (key_data->accounts,
    1180              :                      key_data->accounts_len,
    1181              :                      json_array_size (accounts));
    1182           42 :   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           42 :   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           42 :   if (! no_extensions)
    1196              :   {
    1197           23 :     if (no_signature)
    1198              :     {
    1199           23 :       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            0 :       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            0 :       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           23 :     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          291 :     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          249 :       struct TALER_DenominationGroup group = {0};
    1238              :       const json_t *denom_keys_array;
    1239              :       struct GNUNET_JSON_Specification group_spec[] = {
    1240          249 :         TALER_JSON_spec_denomination_group (NULL,
    1241          249 :                                             key_data->currency,
    1242              :                                             &group),
    1243          249 :         GNUNET_JSON_spec_array_const ("denoms",
    1244              :                                       &denom_keys_array),
    1245          249 :         GNUNET_JSON_spec_end ()
    1246              :       };
    1247              :       json_t *denom_key_obj;
    1248              :       unsigned int index;
    1249              : 
    1250          249 :       EXITIF (GNUNET_SYSERR ==
    1251              :               GNUNET_JSON_parse (group_obj,
    1252              :                                  group_spec,
    1253              :                                  NULL,
    1254              :                                  NULL));
    1255              : 
    1256              :       /* Now, parse the individual denominations */
    1257        10994 :       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        10745 :         struct TALER_EXCHANGE_DenomPublicKey dk = {
    1265              :           .value = group.value,
    1266              :           .fees = group.fees,
    1267              :           .key.age_mask = group.age_mask
    1268              :         };
    1269        10745 :         bool found = false;
    1270              : 
    1271        10745 :         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        10745 :         for (unsigned int j = 0;
    1283      2820199 :              j<key_data->num_denom_keys;
    1284      2809454 :              j++)
    1285              :         {
    1286      2809480 :           if (0 == denoms_cmp (&dk,
    1287      2809480 :                                &key_data->denom_keys[j]))
    1288              :           {
    1289           26 :             found = true;
    1290           26 :             break;
    1291              :           }
    1292              :         }
    1293              : 
    1294        10745 :         if (found)
    1295              :         {
    1296              :           /* 0:0:0 did not support /keys cherry picking */
    1297           26 :           TALER_LOG_DEBUG ("Skipping denomination key: already know it\n");
    1298           26 :           TALER_denom_pub_free (&dk.key);
    1299           26 :           continue;
    1300              :         }
    1301              : 
    1302        10719 :         if (key_data->denom_keys_size == key_data->num_denom_keys)
    1303          214 :           GNUNET_array_grow (key_data->denom_keys,
    1304              :                              key_data->denom_keys_size,
    1305              :                              key_data->denom_keys_size * 2 + 2);
    1306        10719 :         GNUNET_assert (key_data->denom_keys_size >
    1307              :                        key_data->num_denom_keys);
    1308        10719 :         GNUNET_assert (key_data->num_denom_keys < UINT_MAX);
    1309        10719 :         key_data->denom_keys[key_data->num_denom_keys++] = dk;
    1310              : 
    1311              :         /* Update "last_denom_issue_date" */
    1312        10719 :         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        10719 :           = 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           54 :     json_array_foreach (auditors_array, index, auditor_info)
    1328              :     {
    1329              :       struct TALER_EXCHANGE_AuditorInformation ai;
    1330           12 :       bool found = false;
    1331              : 
    1332           12 :       memset (&ai,
    1333              :               0,
    1334              :               sizeof (ai));
    1335           12 :       EXITIF (GNUNET_SYSERR ==
    1336              :               parse_json_auditor (&ai,
    1337              :                                   check_sig,
    1338              :                                   auditor_info,
    1339              :                                   key_data));
    1340           12 :       for (unsigned int j = 0; j<key_data->num_auditors; j++)
    1341              :       {
    1342            0 :         struct TALER_EXCHANGE_AuditorInformation *aix = &key_data->auditors[j];
    1343              : 
    1344            0 :         if (0 == GNUNET_memcmp (&ai.auditor_pub,
    1345              :                                 &aix->auditor_pub))
    1346              :         {
    1347            0 :           found = true;
    1348              :           /* Merge denomination key signatures of downloaded /keys into existing
    1349              :              auditor information 'aix'. */
    1350            0 :           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            0 :           for (unsigned int i = 0; i<ai.num_denom_keys; i++)
    1355              :           {
    1356            0 :             bool kfound = false;
    1357              : 
    1358            0 :             for (unsigned int k = 0; k<aix->num_denom_keys; k++)
    1359              :             {
    1360            0 :               if (aix->denom_keys[k].denom_key_offset ==
    1361            0 :                   ai.denom_keys[i].denom_key_offset)
    1362              :               {
    1363            0 :                 kfound = true;
    1364            0 :                 break;
    1365              :               }
    1366              :             }
    1367            0 :             if (! kfound)
    1368            0 :               GNUNET_array_append (aix->denom_keys,
    1369              :                                    aix->num_denom_keys,
    1370              :                                    ai.denom_keys[i]);
    1371              :           }
    1372            0 :           break;
    1373              :         }
    1374              :       }
    1375           12 :       if (found)
    1376              :       {
    1377            0 :         GNUNET_array_grow (ai.denom_keys,
    1378              :                            ai.num_denom_keys,
    1379              :                            0);
    1380            0 :         GNUNET_free (ai.auditor_url);
    1381            0 :         continue; /* we are done */
    1382              :       }
    1383           12 :       if (key_data->auditors_size == key_data->num_auditors)
    1384           12 :         GNUNET_array_grow (key_data->auditors,
    1385              :                            key_data->auditors_size,
    1386              :                            key_data->auditors_size * 2 + 2);
    1387           12 :       GNUNET_assert (key_data->auditors_size >
    1388              :                      key_data->num_auditors);
    1389           12 :       GNUNET_assert (NULL != ai.auditor_url);
    1390           12 :       GNUNET_assert (key_data->num_auditors < UINT_MAX);
    1391           12 :       key_data->auditors[key_data->num_auditors++] = ai;
    1392              :     };
    1393              :   }
    1394              : 
    1395              :   /* parse the revocation/recoup information */
    1396           42 :   if (NULL != recoup_array)
    1397              :   {
    1398              :     json_t *recoup_info;
    1399              :     unsigned int index;
    1400              : 
    1401           42 :     json_array_foreach (recoup_array, index, recoup_info)
    1402              :     {
    1403              :       struct TALER_DenominationHashP h_denom_pub;
    1404              :       struct GNUNET_JSON_Specification spec[] = {
    1405            0 :         GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
    1406              :                                      &h_denom_pub),
    1407            0 :         GNUNET_JSON_spec_end ()
    1408              :       };
    1409              : 
    1410            0 :       EXITIF (GNUNET_OK !=
    1411              :               GNUNET_JSON_parse (recoup_info,
    1412              :                                  spec,
    1413              :                                  NULL, NULL));
    1414            0 :       for (unsigned int j = 0;
    1415            0 :            j<key_data->num_denom_keys;
    1416            0 :            j++)
    1417              :       {
    1418            0 :         if (0 == GNUNET_memcmp (&h_denom_pub,
    1419              :                                 &key_data->denom_keys[j].h_key))
    1420              :         {
    1421            0 :           key_data->denom_keys[j].revoked = true;
    1422            0 :           break;
    1423              :         }
    1424              :       }
    1425              :     }
    1426              :   }
    1427              : 
    1428           42 :   if (check_sig)
    1429              :   {
    1430              :     struct GNUNET_HashContext *hash_context;
    1431              :     struct GNUNET_HashCode hc;
    1432              : 
    1433           34 :     hash_context = GNUNET_CRYPTO_hash_context_start ();
    1434           34 :     qsort (sig_ctx.elements,
    1435           34 :            sig_ctx.elements_pos,
    1436              :            sizeof (struct SignatureElement),
    1437              :            &signature_context_sort_cb);
    1438         9682 :     for (unsigned int i = 0; i<sig_ctx.elements_pos; i++)
    1439              :     {
    1440         9648 :       struct SignatureElement *element = &sig_ctx.elements[i];
    1441              : 
    1442         9648 :       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         9648 :       GNUNET_CRYPTO_hash_context_read (hash_context,
    1448         9648 :                                        &element->master_sig,
    1449              :                                        sizeof (element->master_sig));
    1450              :     }
    1451           34 :     GNUNET_array_grow (sig_ctx.elements,
    1452              :                        sig_ctx.elements_size,
    1453              :                        0);
    1454           34 :     GNUNET_CRYPTO_hash_context_finish (hash_context,
    1455              :                                        &hc);
    1456           34 :     EXITIF (GNUNET_OK !=
    1457              :             TALER_EXCHANGE_test_signing_key (key_data,
    1458              :                                              &exchange_pub));
    1459           34 :     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           42 :   return GNUNET_OK;
    1467              : 
    1468            0 : EXITIF_exit:
    1469            0 :   *vc = TALER_EXCHANGE_VC_PROTOCOL_ERROR;
    1470            0 :   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           34 : keys_completed_cb (void *cls,
    1484              :                    long response_code,
    1485              :                    const void *resp_obj)
    1486              : {
    1487           34 :   struct TALER_EXCHANGE_GetKeysHandle *gkh = cls;
    1488           34 :   const json_t *j = resp_obj;
    1489           34 :   struct TALER_EXCHANGE_Keys *kd = NULL;
    1490           34 :   struct TALER_EXCHANGE_KeysResponse kresp = {
    1491              :     .hr.reply = j,
    1492           34 :     .hr.http_status = (unsigned int) response_code,
    1493              :     .details.ok.compat = TALER_EXCHANGE_VC_PROTOCOL_ERROR,
    1494              :   };
    1495              : 
    1496           34 :   gkh->job = NULL;
    1497           34 :   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           34 :   if (GNUNET_TIME_absolute_is_past (gkh->expire.abs_time))
    1503              :   {
    1504            0 :     if (MHD_HTTP_OK == response_code)
    1505            0 :       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            0 :       = GNUNET_TIME_absolute_to_timestamp (
    1511              :           GNUNET_TIME_relative_to_absolute (DEFAULT_EXPIRATION));
    1512              :   }
    1513           34 :   switch (response_code)
    1514              :   {
    1515            0 :   case 0:
    1516            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1517              :                 "Failed to receive /keys response from exchange %s\n",
    1518              :                 gkh->exchange_url);
    1519            0 :     break;
    1520           34 :   case MHD_HTTP_OK:
    1521           34 :     if (NULL == j)
    1522              :     {
    1523            0 :       GNUNET_break (0);
    1524            0 :       response_code = 0;
    1525            0 :       break;
    1526              :     }
    1527           34 :     kd = GNUNET_new (struct TALER_EXCHANGE_Keys);
    1528           34 :     kd->exchange_url = GNUNET_strdup (gkh->exchange_url);
    1529           34 :     if (NULL != gkh->prev_keys)
    1530              :     {
    1531            8 :       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            8 :         = kd_old->num_denom_keys;
    1537              :       kd->last_denom_issue_date
    1538            8 :         = kd_old->last_denom_issue_date;
    1539            8 :       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            8 :       GNUNET_memcpy (kd->denom_keys,
    1544              :                      kd_old->denom_keys,
    1545              :                      kd_old->num_denom_keys
    1546              :                      * sizeof (struct TALER_EXCHANGE_DenomPublicKey));
    1547         1105 :       for (unsigned int i = 0; i<kd_old->num_denom_keys; i++)
    1548         1097 :         TALER_denom_pub_copy (&kd->denom_keys[i].key,
    1549         1097 :                               &kd_old->denom_keys[i].key);
    1550            8 :       kd->num_auditors = kd_old->num_auditors;
    1551              :       kd->auditors
    1552            8 :         = GNUNET_new_array (kd->num_auditors,
    1553              :                             struct TALER_EXCHANGE_AuditorInformation);
    1554              :       /* Now the necessary deep copy... */
    1555           10 :       for (unsigned int i = 0; i<kd_old->num_auditors; i++)
    1556              :       {
    1557            2 :         const struct TALER_EXCHANGE_AuditorInformation *aold =
    1558            2 :           &kd_old->auditors[i];
    1559            2 :         struct TALER_EXCHANGE_AuditorInformation *anew = &kd->auditors[i];
    1560              : 
    1561            2 :         anew->auditor_pub = aold->auditor_pub;
    1562            2 :         anew->auditor_url = GNUNET_strdup (aold->auditor_url);
    1563            2 :         GNUNET_array_grow (anew->denom_keys,
    1564              :                            anew->num_denom_keys,
    1565              :                            aold->num_denom_keys);
    1566            2 :         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           34 :     if (GNUNET_OK !=
    1575           34 :         decode_keys_json (j,
    1576              :                           true,
    1577              :                           kd,
    1578              :                           &kresp.details.ok.compat))
    1579              :     {
    1580            0 :       TALER_LOG_ERROR ("Could not decode /keys response\n");
    1581            0 :       kd->rc = 1;
    1582            0 :       TALER_EXCHANGE_keys_decref (kd);
    1583            0 :       kd = NULL;
    1584            0 :       kresp.hr.http_status = 0;
    1585            0 :       kresp.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
    1586            0 :       break;
    1587              :     }
    1588           34 :     kd->rc = 1;
    1589           34 :     kd->key_data_expiration = gkh->expire;
    1590           34 :     if (GNUNET_TIME_relative_cmp (
    1591              :           GNUNET_TIME_absolute_get_remaining (gkh->expire.abs_time),
    1592              :           <,
    1593              :           MINIMUM_EXPIRATION))
    1594              :     {
    1595            0 :       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            0 :         = GNUNET_TIME_relative_to_timestamp (MINIMUM_EXPIRATION);
    1601              :     }
    1602              : 
    1603           34 :     kresp.details.ok.keys = kd;
    1604           34 :     break;
    1605            0 :   case MHD_HTTP_BAD_REQUEST:
    1606              :   case MHD_HTTP_UNAUTHORIZED:
    1607              :   case MHD_HTTP_FORBIDDEN:
    1608              :   case MHD_HTTP_NOT_FOUND:
    1609            0 :     if (NULL == j)
    1610              :     {
    1611            0 :       kresp.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    1612            0 :       kresp.hr.hint = TALER_ErrorCode_get_hint (kresp.hr.ec);
    1613              :     }
    1614              :     else
    1615              :     {
    1616            0 :       kresp.hr.ec = TALER_JSON_get_error_code (j);
    1617            0 :       kresp.hr.hint = TALER_JSON_get_error_hint (j);
    1618              :     }
    1619            0 :     break;
    1620            0 :   default:
    1621            0 :     if (NULL == j)
    1622              :     {
    1623            0 :       kresp.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    1624            0 :       kresp.hr.hint = TALER_ErrorCode_get_hint (kresp.hr.ec);
    1625              :     }
    1626              :     else
    1627              :     {
    1628            0 :       kresp.hr.ec = TALER_JSON_get_error_code (j);
    1629            0 :       kresp.hr.hint = TALER_JSON_get_error_hint (j);
    1630              :     }
    1631            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1632              :                 "Unexpected response code %u/%d\n",
    1633              :                 (unsigned int) response_code,
    1634              :                 (int) kresp.hr.ec);
    1635            0 :     break;
    1636              :   }
    1637           34 :   gkh->cert_cb (gkh->cert_cb_cls,
    1638              :                 &kresp,
    1639              :                 kd);
    1640           34 :   TALER_EXCHANGE_get_keys_cancel (gkh);
    1641           34 : }
    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           34 : 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           34 :   if (strlen (dateline) > MAX_DATE_LINE_LEN)
    1683              :   {
    1684            0 :     GNUNET_break_op (0);
    1685            0 :     return GNUNET_SYSERR;
    1686              :   }
    1687           34 :   while (*dateline == ' ')
    1688            0 :     ++dateline;
    1689          170 :   while (*dateline && *dateline != ' ')
    1690          136 :     ++dateline;
    1691           68 :   while (*dateline == ' ')
    1692           34 :     ++dateline;
    1693              :   /* We just skipped over the day of the week. Now we have:*/
    1694           34 :   if ( (sscanf (dateline,
    1695              :                 "%d %3s %d %d:%d:%d",
    1696            0 :                 &day, month, &year, &hour, &min, &sec) != 6) &&
    1697            0 :        (sscanf (dateline,
    1698              :                 "%d-%3s-%d %d:%d:%d",
    1699            0 :                 &day, month, &year, &hour, &min, &sec) != 6) &&
    1700            0 :        (sscanf (dateline,
    1701              :                 "%3s %d %d:%d:%d %d",
    1702              :                 month, &day, &hour, &min, &sec, &year) != 6) )
    1703              :   {
    1704            0 :     GNUNET_break (0);
    1705            0 :     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           34 :   if (year < 100)
    1710            0 :     year += 1900;
    1711              : 
    1712           34 :   for (mon = 0; ; mon++)
    1713              :   {
    1714           34 :     if (! MONTHS[mon])
    1715              :     {
    1716            0 :       GNUNET_break_op (0);
    1717            0 :       return GNUNET_SYSERR;
    1718              :     }
    1719           34 :     if (0 == strcasecmp (month,
    1720              :                          MONTHS[mon]))
    1721           34 :       break;
    1722              :   }
    1723              : 
    1724           34 :   memset (&tm, 0, sizeof(tm));
    1725           34 :   tm.tm_year = year - 1900;
    1726           34 :   tm.tm_mon = mon;
    1727           34 :   tm.tm_mday = day;
    1728           34 :   tm.tm_hour = hour;
    1729           34 :   tm.tm_min = min;
    1730           34 :   tm.tm_sec = sec;
    1731              : 
    1732           34 :   t = mktime (&tm);
    1733           34 :   if (((time_t) -1) == t)
    1734              :   {
    1735            0 :     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
    1736              :                          "mktime");
    1737            0 :     return GNUNET_SYSERR;
    1738              :   }
    1739           34 :   if (t < 0)
    1740            0 :     t = 0; /* can happen due to timezone issues if date was 1.1.1970 */
    1741           34 :   *at = GNUNET_TIME_timestamp_from_s (t);
    1742           34 :   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          442 : header_cb (char *buffer,
    1759              :            size_t size,
    1760              :            size_t nitems,
    1761              :            void *userdata)
    1762              : {
    1763          442 :   struct TALER_EXCHANGE_GetKeysHandle *kr = userdata;
    1764          442 :   size_t total = size * nitems;
    1765              :   char *val;
    1766              : 
    1767          442 :   if (total < strlen (MHD_HTTP_HEADER_EXPIRES ": "))
    1768           34 :     return total;
    1769          408 :   if (0 != strncasecmp (MHD_HTTP_HEADER_EXPIRES ": ",
    1770              :                         buffer,
    1771              :                         strlen (MHD_HTTP_HEADER_EXPIRES ": ")))
    1772          374 :     return total;
    1773           34 :   val = GNUNET_strndup (&buffer[strlen (MHD_HTTP_HEADER_EXPIRES ": ")],
    1774              :                         total - strlen (MHD_HTTP_HEADER_EXPIRES ": "));
    1775           34 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1776              :               "Found %s header `%s'\n",
    1777              :               MHD_HTTP_HEADER_EXPIRES,
    1778              :               val);
    1779           34 :   if (GNUNET_OK !=
    1780           34 :       parse_date_string (val,
    1781              :                          &kr->expire))
    1782              :   {
    1783            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1784              :                 "Failed to parse %s-header `%s'\n",
    1785              :                 MHD_HTTP_HEADER_EXPIRES,
    1786              :                 val);
    1787            0 :     kr->expire = GNUNET_TIME_UNIT_ZERO_TS;
    1788              :   }
    1789           34 :   GNUNET_free (val);
    1790           34 :   return total;
    1791              : }
    1792              : 
    1793              : 
    1794              : struct TALER_EXCHANGE_GetKeysHandle *
    1795           34 : 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           34 :   char last_date[80] = { 0 };
    1805              : 
    1806           34 :   TALER_LOG_DEBUG ("Connecting to the exchange (%s)\n",
    1807              :                    url);
    1808           34 :   gkh = GNUNET_new (struct TALER_EXCHANGE_GetKeysHandle);
    1809           34 :   gkh->exchange_url = GNUNET_strdup (url);
    1810           34 :   gkh->cert_cb = cert_cb;
    1811           34 :   gkh->cert_cb_cls = cert_cb_cls;
    1812           34 :   if (NULL != last_keys)
    1813              :   {
    1814            8 :     gkh->prev_keys = TALER_EXCHANGE_keys_incref (last_keys);
    1815            8 :     TALER_LOG_DEBUG ("Last DK issue date (before GETting /keys): %s\n",
    1816              :                      GNUNET_TIME_timestamp2s (
    1817              :                        last_keys->last_denom_issue_date));
    1818            8 :     GNUNET_snprintf (last_date,
    1819              :                      sizeof (last_date),
    1820              :                      "%llu",
    1821              :                      (unsigned long long)
    1822            8 :                      last_keys->last_denom_issue_date.abs_time.abs_value_us
    1823              :                      / 1000000LLU);
    1824              :   }
    1825           34 :   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           34 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1835              :               "Requesting keys with URL `%s'.\n",
    1836              :               gkh->url);
    1837           34 :   eh = TALER_EXCHANGE_curl_easy_get_ (gkh->url);
    1838           34 :   if (NULL == eh)
    1839              :   {
    1840            0 :     GNUNET_break (0);
    1841            0 :     GNUNET_free (gkh->exchange_url);
    1842            0 :     GNUNET_free (gkh->url);
    1843            0 :     GNUNET_free (gkh);
    1844            0 :     return NULL;
    1845              :   }
    1846           34 :   GNUNET_break (CURLE_OK ==
    1847              :                 curl_easy_setopt (eh,
    1848              :                                   CURLOPT_VERBOSE,
    1849              :                                   0));
    1850           34 :   GNUNET_break (CURLE_OK ==
    1851              :                 curl_easy_setopt (eh,
    1852              :                                   CURLOPT_TIMEOUT,
    1853              :                                   120 /* seconds */));
    1854           34 :   GNUNET_assert (CURLE_OK ==
    1855              :                  curl_easy_setopt (eh,
    1856              :                                    CURLOPT_HEADERFUNCTION,
    1857              :                                    &header_cb));
    1858           34 :   GNUNET_assert (CURLE_OK ==
    1859              :                  curl_easy_setopt (eh,
    1860              :                                    CURLOPT_HEADERDATA,
    1861              :                                    gkh));
    1862           34 :   gkh->job = GNUNET_CURL_job_add_with_ct_json (ctx,
    1863              :                                                eh,
    1864              :                                                &keys_completed_cb,
    1865              :                                                gkh);
    1866           34 :   return gkh;
    1867              : }
    1868              : 
    1869              : 
    1870              : void
    1871           34 : TALER_EXCHANGE_get_keys_cancel (
    1872              :   struct TALER_EXCHANGE_GetKeysHandle *gkh)
    1873              : {
    1874           34 :   if (NULL != gkh->job)
    1875              :   {
    1876            0 :     GNUNET_CURL_job_cancel (gkh->job);
    1877            0 :     gkh->job = NULL;
    1878              :   }
    1879           34 :   TALER_EXCHANGE_keys_decref (gkh->prev_keys);
    1880           34 :   GNUNET_free (gkh->exchange_url);
    1881           34 :   GNUNET_free (gkh->url);
    1882           34 :   GNUNET_free (gkh);
    1883           34 : }
    1884              : 
    1885              : 
    1886              : enum GNUNET_GenericReturnValue
    1887          185 : 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          185 :   now = GNUNET_TIME_absolute_get ();
    1895          329 :   for (unsigned int i = 0; i<keys->num_sign_keys; i++)
    1896          329 :     if ( (GNUNET_TIME_absolute_cmp (
    1897              :             keys->sign_keys[i].valid_from.abs_time,
    1898              :             <=,
    1899              :             GNUNET_TIME_absolute_add (now,
    1900          185 :                                       LIFETIME_TOLERANCE))) &&
    1901          185 :          (GNUNET_TIME_absolute_cmp (
    1902              :             keys->sign_keys[i].valid_until.abs_time,
    1903              :             >,
    1904              :             GNUNET_TIME_absolute_subtract (now,
    1905          185 :                                            LIFETIME_TOLERANCE))) &&
    1906          185 :          (0 == GNUNET_memcmp (pub,
    1907              :                               &keys->sign_keys[i].key)) )
    1908          185 :       return GNUNET_OK;
    1909            0 :   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1910              :               "Signing key not valid at time %s\n",
    1911              :               GNUNET_TIME_absolute2s (now));
    1912            0 :   return GNUNET_SYSERR;
    1913              : }
    1914              : 
    1915              : 
    1916              : const struct TALER_EXCHANGE_DenomPublicKey *
    1917           30 : TALER_EXCHANGE_get_denomination_key (
    1918              :   const struct TALER_EXCHANGE_Keys *keys,
    1919              :   const struct TALER_DenominationPublicKey *pk)
    1920              : {
    1921         1037 :   for (unsigned int i = 0; i<keys->num_denom_keys; i++)
    1922         1037 :     if (0 ==
    1923         1037 :         TALER_denom_pub_cmp (pk,
    1924         1037 :                              &keys->denom_keys[i].key))
    1925           30 :       return &keys->denom_keys[i];
    1926            0 :   return NULL;
    1927              : }
    1928              : 
    1929              : 
    1930              : const struct TALER_EXCHANGE_GlobalFee *
    1931           13 : TALER_EXCHANGE_get_global_fee (
    1932              :   const struct TALER_EXCHANGE_Keys *keys,
    1933              :   struct GNUNET_TIME_Timestamp ts)
    1934              : {
    1935           13 :   for (unsigned int i = 0; i<keys->num_global_fees; i++)
    1936              :   {
    1937           13 :     const struct TALER_EXCHANGE_GlobalFee *gf = &keys->global_fees[i];
    1938              : 
    1939           13 :     if (GNUNET_TIME_timestamp_cmp (ts,
    1940              :                                    >=,
    1941           13 :                                    gf->start_date) &&
    1942           13 :         GNUNET_TIME_timestamp_cmp (ts,
    1943              :                                    <,
    1944              :                                    gf->end_date))
    1945           13 :       return gf;
    1946              :   }
    1947            0 :   return NULL;
    1948              : }
    1949              : 
    1950              : 
    1951              : struct TALER_EXCHANGE_DenomPublicKey *
    1952           72 : TALER_EXCHANGE_copy_denomination_key (
    1953              :   const struct TALER_EXCHANGE_DenomPublicKey *key)
    1954              : {
    1955              :   struct TALER_EXCHANGE_DenomPublicKey *copy;
    1956              : 
    1957           72 :   copy = GNUNET_new (struct TALER_EXCHANGE_DenomPublicKey);
    1958           72 :   *copy = *key;
    1959           72 :   TALER_denom_pub_copy (&copy->key,
    1960              :                         &key->key);
    1961           72 :   return copy;
    1962              : }
    1963              : 
    1964              : 
    1965              : void
    1966           72 : TALER_EXCHANGE_destroy_denomination_key (
    1967              :   struct TALER_EXCHANGE_DenomPublicKey *key)
    1968              : {
    1969           72 :   TALER_denom_pub_free (&key->key);
    1970           72 :   GNUNET_free (key);
    1971           72 : }
    1972              : 
    1973              : 
    1974              : const struct TALER_EXCHANGE_DenomPublicKey *
    1975          113 : 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        27286 :   for (unsigned int i = 0; i<keys->num_denom_keys; i++)
    1981        27286 :     if (0 == GNUNET_memcmp (hc,
    1982              :                             &keys->denom_keys[i].h_key))
    1983          113 :       return &keys->denom_keys[i];
    1984            0 :   return NULL;
    1985              : }
    1986              : 
    1987              : 
    1988              : struct TALER_EXCHANGE_Keys *
    1989          377 : TALER_EXCHANGE_keys_incref (struct TALER_EXCHANGE_Keys *keys)
    1990              : {
    1991          377 :   GNUNET_assert (keys->rc < UINT_MAX);
    1992          377 :   keys->rc++;
    1993          377 :   return keys;
    1994              : }
    1995              : 
    1996              : 
    1997              : void
    1998          465 : TALER_EXCHANGE_keys_decref (struct TALER_EXCHANGE_Keys *keys)
    1999              : {
    2000          465 :   if (NULL == keys)
    2001           46 :     return;
    2002          419 :   GNUNET_assert (0 < keys->rc);
    2003          419 :   keys->rc--;
    2004          419 :   if (0 != keys->rc)
    2005          377 :     return;
    2006           42 :   GNUNET_array_grow (keys->sign_keys,
    2007              :                      keys->num_sign_keys,
    2008              :                      0);
    2009        11858 :   for (unsigned int i = 0; i<keys->num_denom_keys; i++)
    2010        11816 :     TALER_denom_pub_free (&keys->denom_keys[i].key);
    2011           42 :   keys->num_denom_keys = 0;
    2012           42 :   GNUNET_array_grow (keys->denom_keys,
    2013              :                      keys->denom_keys_size,
    2014              :                      0);
    2015           56 :   for (unsigned int i = 0; i<keys->num_auditors; i++)
    2016              :   {
    2017           14 :     GNUNET_array_grow (keys->auditors[i].denom_keys,
    2018              :                        keys->auditors[i].num_denom_keys,
    2019              :                        0);
    2020           14 :     GNUNET_free (keys->auditors[i].auditor_url);
    2021              :   }
    2022           42 :   GNUNET_array_grow (keys->auditors,
    2023              :                      keys->auditors_size,
    2024              :                      0);
    2025           42 :   TALER_EXCHANGE_free_accounts (keys->accounts_len,
    2026              :                                 keys->accounts);
    2027           42 :   GNUNET_array_grow (keys->accounts,
    2028              :                      keys->accounts_len,
    2029              :                      0);
    2030           42 :   free_fees (keys->fees,
    2031              :              keys->fees_len);
    2032           42 :   GNUNET_array_grow (keys->hard_limits,
    2033              :                      keys->hard_limits_length,
    2034              :                      0);
    2035           42 :   GNUNET_array_grow (keys->zero_limits,
    2036              :                      keys->zero_limits_length,
    2037              :                      0);
    2038           42 :   json_decref (keys->extensions);
    2039           42 :   GNUNET_free (keys->cspec.name);
    2040           42 :   json_decref (keys->cspec.map_alt_unit_names);
    2041           42 :   GNUNET_array_grow (keys->cspec.common_amounts,
    2042              :                      keys->cspec.num_common_amounts,
    2043              :                      0);
    2044           42 :   GNUNET_free (keys->wallet_balance_limit_without_kyc);
    2045           42 :   GNUNET_free (keys->version);
    2046           42 :   GNUNET_free (keys->currency);
    2047           42 :   GNUNET_free (keys->asset_type);
    2048           42 :   GNUNET_free (keys->global_fees);
    2049           42 :   GNUNET_free (keys->exchange_url);
    2050           42 :   GNUNET_free (keys);
    2051              : }
    2052              : 
    2053              : 
    2054              : struct TALER_EXCHANGE_Keys *
    2055            8 : TALER_EXCHANGE_keys_from_json (const json_t *j)
    2056              : {
    2057              :   const json_t *jkeys;
    2058              :   const char *url;
    2059              :   uint32_t version;
    2060            8 :   struct GNUNET_TIME_Timestamp expire
    2061              :     = GNUNET_TIME_UNIT_ZERO_TS;
    2062              :   struct GNUNET_JSON_Specification spec[] = {
    2063            8 :     GNUNET_JSON_spec_uint32 ("version",
    2064              :                              &version),
    2065            8 :     GNUNET_JSON_spec_object_const ("keys",
    2066              :                                    &jkeys),
    2067            8 :     TALER_JSON_spec_web_url ("exchange_url",
    2068              :                              &url),
    2069            8 :     GNUNET_JSON_spec_mark_optional (
    2070              :       GNUNET_JSON_spec_timestamp ("expire",
    2071              :                                   &expire),
    2072              :       NULL),
    2073            8 :     GNUNET_JSON_spec_end ()
    2074              :   };
    2075              :   struct TALER_EXCHANGE_Keys *keys;
    2076              :   enum TALER_EXCHANGE_VersionCompatibility compat;
    2077              : 
    2078            8 :   if (NULL == j)
    2079            0 :     return NULL;
    2080            8 :   if (GNUNET_OK !=
    2081            8 :       GNUNET_JSON_parse (j,
    2082              :                          spec,
    2083              :                          NULL, NULL))
    2084              :   {
    2085            0 :     GNUNET_break_op (0);
    2086            0 :     return NULL;
    2087              :   }
    2088            8 :   if (0 != version)
    2089              :   {
    2090            0 :     return NULL; /* unsupported version */
    2091              :   }
    2092            8 :   keys = GNUNET_new (struct TALER_EXCHANGE_Keys);
    2093            8 :   if (GNUNET_OK !=
    2094            8 :       decode_keys_json (jkeys,
    2095              :                         false,
    2096              :                         keys,
    2097              :                         &compat))
    2098              :   {
    2099            0 :     GNUNET_break (0);
    2100            0 :     return NULL;
    2101              :   }
    2102            8 :   keys->rc = 1;
    2103            8 :   keys->key_data_expiration = expire;
    2104            8 :   keys->exchange_url = GNUNET_strdup (url);
    2105            8 :   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           26 : add_grp (void *cls,
    2138              :          const struct GNUNET_HashCode *key,
    2139              :          void *value)
    2140              : {
    2141           26 :   json_t *denominations_by_group = cls;
    2142           26 :   struct GroupData *gd = value;
    2143              :   const char *cipher;
    2144              :   json_t *ge;
    2145           26 :   bool age_restricted = gd->meta.age_mask.bits != 0;
    2146              : 
    2147              :   (void) key;
    2148           26 :   switch (gd->meta.cipher)
    2149              :   {
    2150           13 :   case GNUNET_CRYPTO_BSA_RSA:
    2151           13 :     cipher = age_restricted ? "RSA+age_restricted" : "RSA";
    2152           13 :     break;
    2153           13 :   case GNUNET_CRYPTO_BSA_CS:
    2154           13 :     cipher = age_restricted ? "CS+age_restricted" : "CS";
    2155           13 :     break;
    2156            0 :   default:
    2157            0 :     GNUNET_assert (false);
    2158              :   }
    2159              : 
    2160           26 :   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           26 :   GNUNET_assert (0 ==
    2176              :                  json_array_append_new (denominations_by_group,
    2177              :                                         ge));
    2178           26 :   GNUNET_free (gd);
    2179           26 :   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           16 : ar_to_json (unsigned int ar_len,
    2192              :             const struct TALER_EXCHANGE_AccountRestriction ars[static ar_len])
    2193           16 : {
    2194              :   json_t *rval;
    2195              : 
    2196           16 :   rval = json_array ();
    2197           16 :   GNUNET_assert (NULL != rval);
    2198           16 :   for (unsigned int i = 0; i<ar_len; i++)
    2199              :   {
    2200            0 :     const struct TALER_EXCHANGE_AccountRestriction *ar = &ars[i];
    2201              : 
    2202            0 :     switch (ar->type)
    2203              :     {
    2204            0 :     case TALER_EXCHANGE_AR_INVALID:
    2205            0 :       GNUNET_break (0);
    2206            0 :       json_decref (rval);
    2207            0 :       return NULL;
    2208            0 :     case TALER_EXCHANGE_AR_DENY:
    2209            0 :       GNUNET_assert (
    2210              :         0 ==
    2211              :         json_array_append_new (
    2212              :           rval,
    2213              :           GNUNET_JSON_PACK (
    2214              :             GNUNET_JSON_pack_string ("type",
    2215              :                                      "deny"))));
    2216            0 :       break;
    2217            0 :     case TALER_EXCHANGE_AR_REGEX:
    2218            0 :       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            0 :       break;
    2237              :     }
    2238              :   }
    2239           16 :   return rval;
    2240              : }
    2241              : 
    2242              : 
    2243              : json_t *
    2244            8 : 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            8 :   json_t *wblwk = NULL;
    2256              :   json_t *hard_limits;
    2257              :   json_t *zero_limits;
    2258              : 
    2259            8 :   now = GNUNET_TIME_timestamp_get ();
    2260            8 :   signkeys = json_array ();
    2261            8 :   GNUNET_assert (NULL != signkeys);
    2262           24 :   for (unsigned int i = 0; i<kd->num_sign_keys; i++)
    2263              :   {
    2264           16 :     const struct TALER_EXCHANGE_SigningPublicKey *sk = &kd->sign_keys[i];
    2265              :     json_t *signkey;
    2266              : 
    2267           16 :     if (GNUNET_TIME_timestamp_cmp (now,
    2268              :                                    >,
    2269              :                                    sk->valid_until))
    2270            0 :       continue; /* skip keys that have expired */
    2271           16 :     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           16 :     GNUNET_assert (NULL != signkey);
    2283           16 :     GNUNET_assert (0 ==
    2284              :                    json_array_append_new (signkeys,
    2285              :                                           signkey));
    2286              :   }
    2287              : 
    2288            8 :   denominations_by_group = json_array ();
    2289            8 :   GNUNET_assert (NULL != denominations_by_group);
    2290              :   {
    2291              :     struct GNUNET_CONTAINER_MultiHashMap *dbg;
    2292              : 
    2293            8 :     dbg = GNUNET_CONTAINER_multihashmap_create (128,
    2294              :                                                 false);
    2295         1105 :     for (unsigned int i = 0; i<kd->num_denom_keys; i++)
    2296              :     {
    2297         1097 :       const struct TALER_EXCHANGE_DenomPublicKey *dk = &kd->denom_keys[i];
    2298         1097 :       struct TALER_DenominationGroup meta = {
    2299         1097 :         .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         1097 :       if (GNUNET_TIME_timestamp_cmp (now,
    2310              :                                      >,
    2311              :                                      dk->expire_deposit))
    2312            0 :         continue; /* skip keys that have expired */
    2313         1097 :       TALER_denomination_group_get_key (&meta,
    2314              :                                         &key);
    2315         1097 :       gd = GNUNET_CONTAINER_multihashmap_get (dbg,
    2316              :                                               &key);
    2317         1097 :       if (NULL == gd)
    2318              :       {
    2319           26 :         gd = GNUNET_new (struct GroupData);
    2320           26 :         gd->meta = meta;
    2321           26 :         gd->json = json_array ();
    2322           26 :         GNUNET_assert (NULL != gd->json);
    2323           26 :         GNUNET_assert (
    2324              :           GNUNET_OK ==
    2325              :           GNUNET_CONTAINER_multihashmap_put (dbg,
    2326              :                                              &key,
    2327              :                                              gd,
    2328              :                                              GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    2329              : 
    2330              :       }
    2331         1097 :       switch (meta.cipher)
    2332              :       {
    2333          548 :       case GNUNET_CRYPTO_BSA_RSA:
    2334              :         key_spec =
    2335          548 :           GNUNET_JSON_pack_rsa_public_key (
    2336              :             "rsa_pub",
    2337          548 :             dk->key.bsign_pub_key->details.rsa_public_key);
    2338          548 :         break;
    2339          549 :       case GNUNET_CRYPTO_BSA_CS:
    2340              :         key_spec =
    2341          549 :           GNUNET_JSON_pack_data_varsize (
    2342              :             "cs_pub",
    2343          549 :             &dk->key.bsign_pub_key->details.cs_public_key,
    2344              :             sizeof (dk->key.bsign_pub_key->details.cs_public_key));
    2345          549 :         break;
    2346            0 :       default:
    2347            0 :         GNUNET_assert (false);
    2348              :       }
    2349         1097 :       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         1097 :       GNUNET_assert (0 ==
    2363              :                      json_array_append_new (gd->json,
    2364              :                                             denom));
    2365              :     }
    2366            8 :     GNUNET_CONTAINER_multihashmap_iterate (dbg,
    2367              :                                            &add_grp,
    2368              :                                            denominations_by_group);
    2369            8 :     GNUNET_CONTAINER_multihashmap_destroy (dbg);
    2370              :   }
    2371              : 
    2372            8 :   auditors = json_array ();
    2373            8 :   GNUNET_assert (NULL != auditors);
    2374           10 :   for (unsigned int i = 0; i<kd->num_auditors; i++)
    2375              :   {
    2376            2 :     const struct TALER_EXCHANGE_AuditorInformation *ai = &kd->auditors[i];
    2377              :     json_t *a;
    2378              :     json_t *adenoms;
    2379              : 
    2380            2 :     adenoms = json_array ();
    2381            2 :     GNUNET_assert (NULL != adenoms);
    2382            2 :     for (unsigned int j = 0; j<ai->num_denom_keys; j++)
    2383              :     {
    2384            0 :       const struct TALER_EXCHANGE_AuditorDenominationInfo *adi =
    2385            0 :         &ai->denom_keys[j];
    2386            0 :       const struct TALER_EXCHANGE_DenomPublicKey *dk =
    2387            0 :         &kd->denom_keys[adi->denom_key_offset];
    2388              :       json_t *k;
    2389              : 
    2390            0 :       GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys);
    2391            0 :       if (GNUNET_TIME_timestamp_cmp (now,
    2392              :                                      >,
    2393              :                                      dk->expire_deposit))
    2394            0 :         continue; /* skip auditor signatures for denomination keys that have expired */
    2395            0 :       GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys);
    2396            0 :       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            0 :       GNUNET_assert (0 ==
    2402              :                      json_array_append_new (adenoms,
    2403              :                                             k));
    2404              :     }
    2405              : 
    2406            2 :     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            2 :     GNUNET_assert (0 ==
    2414              :                    json_array_append_new (auditors,
    2415              :                                           a));
    2416              :   }
    2417              : 
    2418            8 :   global_fees = json_array ();
    2419            8 :   GNUNET_assert (NULL != global_fees);
    2420           24 :   for (unsigned int i = 0; i<kd->num_global_fees; i++)
    2421              :   {
    2422           16 :     const struct TALER_EXCHANGE_GlobalFee *gf
    2423           16 :       = &kd->global_fees[i];
    2424              : 
    2425           16 :     if (GNUNET_TIME_absolute_is_past (gf->end_date.abs_time))
    2426            0 :       continue;
    2427           16 :     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            8 :   accounts = json_array ();
    2448            8 :   GNUNET_assert (NULL != accounts);
    2449           16 :   for (unsigned int i = 0; i<kd->accounts_len; i++)
    2450              :   {
    2451            8 :     const struct TALER_EXCHANGE_WireAccount *acc
    2452            8 :       = &kd->accounts[i];
    2453              :     json_t *credit_restrictions;
    2454              :     json_t *debit_restrictions;
    2455              : 
    2456              :     credit_restrictions
    2457            8 :       = ar_to_json (acc->credit_restrictions_length,
    2458            8 :                     acc->credit_restrictions);
    2459            8 :     GNUNET_assert (NULL != credit_restrictions);
    2460              :     debit_restrictions
    2461            8 :       = ar_to_json (acc->debit_restrictions_length,
    2462            8 :                     acc->debit_restrictions);
    2463            8 :     GNUNET_assert (NULL != debit_restrictions);
    2464            8 :     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            8 :   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            8 :   wire_fees = json_object ();
    2492            8 :   GNUNET_assert (NULL != wire_fees);
    2493           16 :   for (unsigned int i = 0; i<kd->fees_len; i++)
    2494              :   {
    2495            8 :     const struct TALER_EXCHANGE_WireFeesByMethod *fbw
    2496            8 :       = &kd->fees[i];
    2497              :     json_t *wf;
    2498              : 
    2499            8 :     wf = json_array ();
    2500            8 :     GNUNET_assert (NULL != wf);
    2501            8 :     for (struct TALER_EXCHANGE_WireAggregateFees *p = fbw->fees_head;
    2502           24 :          NULL != p;
    2503           16 :          p = p->next)
    2504              :     {
    2505           16 :       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            8 :     GNUNET_assert (0 ==
    2522              :                    json_object_set_new (wire_fees,
    2523              :                                         fbw->method,
    2524              :                                         wf));
    2525              :   }
    2526              : 
    2527            8 :   recoup = json_array ();
    2528            8 :   GNUNET_assert (NULL != recoup);
    2529         1105 :   for (unsigned int i = 0; i<kd->num_denom_keys; i++)
    2530              :   {
    2531         1097 :     const struct TALER_EXCHANGE_DenomPublicKey *dk
    2532         1097 :       = &kd->denom_keys[i];
    2533         1097 :     if (! dk->revoked)
    2534         1097 :       continue;
    2535            0 :     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            8 :   wblwk = json_array ();
    2544            8 :   GNUNET_assert (NULL != wblwk);
    2545            8 :   for (unsigned int i = 0; i<kd->wblwk_length; i++)
    2546              :   {
    2547            0 :     const struct TALER_Amount *a = &kd->wallet_balance_limit_without_kyc[i];
    2548              : 
    2549            0 :     GNUNET_assert (0 ==
    2550              :                    json_array_append_new (
    2551              :                      wblwk,
    2552              :                      TALER_JSON_from_amount (a)));
    2553              :   }
    2554              : 
    2555            8 :   hard_limits = json_array ();
    2556            8 :   for (unsigned int i = 0; i < kd->hard_limits_length; i++)
    2557              :   {
    2558            0 :     const struct TALER_EXCHANGE_AccountLimit *al
    2559            0 :       = &kd->hard_limits[i];
    2560              :     json_t *j;
    2561              : 
    2562            0 :     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            0 :     GNUNET_assert (0 ==
    2571              :                    json_array_append_new (
    2572              :                      hard_limits,
    2573              :                      j));
    2574              :   }
    2575              : 
    2576            8 :   zero_limits = json_array ();
    2577           10 :   for (unsigned int i = 0; i < kd->zero_limits_length; i++)
    2578              :   {
    2579            2 :     const struct TALER_EXCHANGE_ZeroLimitedOperation *zol
    2580            2 :       = &kd->zero_limits[i];
    2581              :     json_t *j;
    2582              : 
    2583            2 :     j = GNUNET_JSON_PACK (
    2584              :       TALER_JSON_pack_kycte ("operation_type",
    2585              :                              zol->operation_type)
    2586              :       );
    2587            2 :     GNUNET_assert (0 ==
    2588              :                    json_array_append_new (
    2589              :                      zero_limits,
    2590              :                      j));
    2591              :   }
    2592              : 
    2593            8 :   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            8 :   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 */
        

Generated by: LCOV version 2.0-1