LCOV - code coverage report
Current view: top level - lib - exchange_api_handle.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 652 861 75.7 %
Date: 2025-06-05 21:03:14 Functions: 30 30 100.0 %

          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 "platform.h"
      27             : #include <microhttpd.h>
      28             : #include <gnunet/gnunet_curl_lib.h>
      29             : #include "taler_json_lib.h"
      30             : #include "taler_exchange_service.h"
      31             : #include "taler_auditor_service.h"
      32             : #include "taler_signatures.h"
      33             : #include "taler_extensions.h"
      34             : #include "exchange_api_handle.h"
      35             : #include "exchange_api_curl_defaults.h"
      36             : #include "backoff.h"
      37             : #include "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 26
      44             : 
      45             : /**
      46             :  * How many versions are we backwards compatible with?
      47             :  */
      48             : #define EXCHANGE_PROTOCOL_AGE 0
      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       60192 : signature_context_sort_cb (const void *a,
     184             :                            const void *b)
     185             : {
     186       60192 :   const struct SignatureElement *sa = a;
     187       60192 :   const struct SignatureElement *sb = b;
     188             : 
     189       60192 :   if (sa->group_offset < sb->group_offset)
     190       21290 :     return -1;
     191       38902 :   if (sa->group_offset > sb->group_offset)
     192           0 :     return 1;
     193       38902 :   if (sa->offset < sb->offset)
     194       38902 :     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       13524 : 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       13524 :   if (sig_ctx->elements_pos == sig_ctx->elements_size)
     223             :   {
     224          42 :     if (0 == sig_ctx->elements_size)
     225          42 :       new_size = 1024;
     226             :     else
     227           0 :       new_size = sig_ctx->elements_size * 2;
     228          42 :     GNUNET_array_grow (sig_ctx->elements,
     229             :                        sig_ctx->elements_size,
     230             :                        new_size);
     231             :   }
     232       13524 :   element = &sig_ctx->elements[sig_ctx->elements_pos++];
     233       13524 :   element->offset = offset;
     234       13524 :   element->group_offset = group_offset;
     235       13524 :   element->master_sig = *master_sig;
     236       13524 : }
     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          62 : free_fees (struct TALER_EXCHANGE_WireFeesByMethod *wfm,
     247             :            unsigned int wfm_len)
     248             : {
     249         124 :   for (unsigned int i = 0; i<wfm_len; i++)
     250             :   {
     251          62 :     struct TALER_EXCHANGE_WireFeesByMethod *wfmi = &wfm[i];
     252             : 
     253         130 :     while (NULL != wfmi->fees_head)
     254             :     {
     255          68 :       struct TALER_EXCHANGE_WireAggregateFees *fe
     256             :         = wfmi->fees_head;
     257             : 
     258          68 :       wfmi->fees_head = fe->next;
     259          68 :       GNUNET_free (fe);
     260             :     }
     261          62 :     GNUNET_free (wfmi->method);
     262             :   }
     263          62 :   GNUNET_free (wfm);
     264          62 : }
     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          62 : 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          62 :   size_t fbml = json_object_size (fees);
     284          62 :   unsigned int i = 0;
     285             :   const char *key;
     286             :   const json_t *fee_array;
     287             : 
     288          62 :   if (UINT_MAX < fbml)
     289             :   {
     290           0 :     GNUNET_break (0);
     291           0 :     return NULL;
     292             :   }
     293          62 :   fbm = GNUNET_new_array (fbml,
     294             :                           struct TALER_EXCHANGE_WireFeesByMethod);
     295          62 :   *fees_len = (unsigned int) fbml;
     296         124 :   json_object_foreach ((json_t *) fees, key, fee_array) {
     297          62 :     struct TALER_EXCHANGE_WireFeesByMethod *fe = &fbm[i++];
     298             :     size_t idx;
     299             :     json_t *fee;
     300             : 
     301          62 :     fe->method = GNUNET_strdup (key);
     302          62 :     fe->fees_head = NULL;
     303         130 :     json_array_foreach (fee_array, idx, fee)
     304             :     {
     305             :       struct TALER_EXCHANGE_WireAggregateFees *wa
     306          68 :         = GNUNET_new (struct TALER_EXCHANGE_WireAggregateFees);
     307             :       struct GNUNET_JSON_Specification spec[] = {
     308          68 :         GNUNET_JSON_spec_fixed_auto ("sig",
     309             :                                      &wa->master_sig),
     310          68 :         TALER_JSON_spec_amount ("wire_fee",
     311             :                                 currency,
     312             :                                 &wa->fees.wire),
     313          68 :         TALER_JSON_spec_amount ("closing_fee",
     314             :                                 currency,
     315             :                                 &wa->fees.closing),
     316          68 :         GNUNET_JSON_spec_timestamp ("start_date",
     317             :                                     &wa->start_date),
     318          68 :         GNUNET_JSON_spec_timestamp ("end_date",
     319             :                                     &wa->end_date),
     320          68 :         GNUNET_JSON_spec_end ()
     321             :       };
     322             : 
     323          68 :       wa->next = fe->fees_head;
     324          68 :       fe->fees_head = wa;
     325          68 :       if (GNUNET_OK !=
     326          68 :           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          68 :       if (GNUNET_OK !=
     337          68 :           TALER_exchange_offline_wire_fee_verify (
     338             :             key,
     339             :             wa->start_date,
     340             :             wa->end_date,
     341          68 :             &wa->fees,
     342             :             master_pub,
     343          68 :             &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          62 :   GNUNET_assert (i == fbml);
     353          62 :   return fbm;
     354             : }
     355             : 
     356             : 
     357             : void
     358          90 : TEAH_get_auditors_for_dc (
     359             :   struct TALER_EXCHANGE_Keys *keys,
     360             :   TEAH_AuditorCallback ac,
     361             :   void *ac_cls)
     362             : {
     363          90 :   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          76 :   for (unsigned int i = 0; i<keys->num_auditors; i++)
     371             :   {
     372          38 :     const struct TALER_EXCHANGE_AuditorInformation *auditor
     373          38 :       = &keys->auditors[i];
     374             : 
     375          38 :     ac (ac_cls,
     376          38 :         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         205 : 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         205 :     GNUNET_JSON_spec_fixed_auto ("master_sig",
     406             :                                  &sign_key->master_sig),
     407         205 :     GNUNET_JSON_spec_fixed_auto ("key",
     408             :                                  &sign_key->key),
     409         205 :     GNUNET_JSON_spec_timestamp ("stamp_start",
     410             :                                 &sign_key->valid_from),
     411         205 :     GNUNET_JSON_spec_timestamp ("stamp_expire",
     412             :                                 &sign_key->valid_until),
     413         205 :     GNUNET_JSON_spec_timestamp ("stamp_end",
     414             :                                 &sign_key->valid_legal),
     415         205 :     GNUNET_JSON_spec_end ()
     416             :   };
     417             : 
     418         205 :   if (GNUNET_OK !=
     419         205 :       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         205 :   if (! check_sigs)
     427          60 :     return GNUNET_OK;
     428         145 :   if (GNUNET_OK !=
     429         145 :       TALER_exchange_offline_signkey_validity_verify (
     430         145 :         &sign_key->key,
     431             :         sign_key->valid_from,
     432             :         sign_key->valid_until,
     433             :         sign_key->valid_legal,
     434             :         master_key,
     435         145 :         &sign_key->master_sig))
     436             :   {
     437           0 :     GNUNET_break_op (0);
     438           0 :     return GNUNET_SYSERR;
     439             :   }
     440         145 :   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       20680 : 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       20680 :     GNUNET_JSON_spec_fixed_auto ("master_sig",
     477             :                                  &denom_key->master_sig),
     478       20680 :     GNUNET_JSON_spec_timestamp ("stamp_expire_deposit",
     479             :                                 &denom_key->expire_deposit),
     480       20680 :     GNUNET_JSON_spec_timestamp ("stamp_expire_withdraw",
     481             :                                 &denom_key->withdraw_valid_until),
     482       20680 :     GNUNET_JSON_spec_timestamp ("stamp_start",
     483             :                                 &denom_key->valid_from),
     484       20680 :     GNUNET_JSON_spec_timestamp ("stamp_expire_legal",
     485             :                                 &denom_key->expire_legal),
     486       20680 :     GNUNET_JSON_spec_mark_optional (
     487             :       GNUNET_JSON_spec_bool ("lost",
     488             :                              &denom_key->lost),
     489             :       NULL),
     490       20680 :     TALER_JSON_spec_denom_pub_cipher (NULL,
     491             :                                       cipher,
     492             :                                       &denom_key->key),
     493       20680 :     GNUNET_JSON_spec_end ()
     494             :   };
     495             : 
     496       20680 :   if (GNUNET_OK !=
     497       20680 :       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       20680 :   TALER_denom_pub_hash (&denom_key->key,
     505             :                         &denom_key->h_key);
     506       20680 :   if (NULL != sig_ctx)
     507       13524 :     append_signature (sig_ctx,
     508             :                       group_offset,
     509             :                       index,
     510       13524 :                       &denom_key->master_sig);
     511       20680 :   if (! check_sigs)
     512        7156 :     return GNUNET_OK;
     513       13524 :   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       13524 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     525             :               "Learned denomination key %s\n",
     526             :               GNUNET_h2s (&denom_key->h_key.hash));
     527       13524 :   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          20 : 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          20 :     GNUNET_JSON_spec_fixed_auto ("auditor_pub",
     561             :                                  &auditor->auditor_pub),
     562          20 :     TALER_JSON_spec_web_url ("auditor_url",
     563             :                              &auditor_url),
     564          20 :     GNUNET_JSON_spec_array_const ("denomination_keys",
     565             :                                   &keys),
     566          20 :     GNUNET_JSON_spec_end ()
     567             :   };
     568             : 
     569          20 :   if (GNUNET_OK !=
     570          20 :       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          20 :   auditor->auditor_url = GNUNET_strdup (auditor_url);
     583             :   auditor->denom_keys
     584          20 :     = GNUNET_new_array (json_array_size (keys),
     585             :                         struct TALER_EXCHANGE_AuditorDenominationInfo);
     586          20 :   pos = 0;
     587          20 :   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          20 :   if (pos > UINT_MAX)
     650             :   {
     651           0 :     GNUNET_break (0);
     652           0 :     return GNUNET_SYSERR;
     653             :   }
     654          20 :   auditor->num_denom_keys = (unsigned int) pos;
     655          20 :   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          68 : 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          68 :     GNUNET_JSON_spec_timestamp ("start_date",
     677             :                                 &gf->start_date),
     678          68 :     GNUNET_JSON_spec_timestamp ("end_date",
     679             :                                 &gf->end_date),
     680          68 :     GNUNET_JSON_spec_relative_time ("purse_timeout",
     681             :                                     &gf->purse_timeout),
     682          68 :     GNUNET_JSON_spec_relative_time ("history_expiration",
     683             :                                     &gf->history_expiration),
     684          68 :     GNUNET_JSON_spec_uint32 ("purse_account_limit",
     685             :                              &gf->purse_account_limit),
     686          68 :     TALER_JSON_SPEC_GLOBAL_FEES (key_data->currency,
     687             :                                  &gf->fees),
     688          68 :     GNUNET_JSON_spec_fixed_auto ("master_sig",
     689             :                                  &gf->master_sig),
     690          68 :     GNUNET_JSON_spec_end ()
     691             :   };
     692             : 
     693          68 :   if (GNUNET_OK !=
     694          68 :       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          68 :   if (check_sigs)
     707             :   {
     708          44 :     if (GNUNET_OK !=
     709          44 :         TALER_exchange_offline_global_fee_verify (
     710             :           gf->start_date,
     711             :           gf->end_date,
     712          44 :           &gf->fees,
     713             :           gf->purse_timeout,
     714             :           gf->history_expiration,
     715             :           gf->purse_account_limit,
     716             :           &key_data->master_pub,
     717          44 :           &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          68 :   GNUNET_JSON_parse_free (spec);
     725          68 :   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     6586912 : 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     6586912 :   if (0 !=
     745     6586912 :       TALER_denom_pub_cmp (&denom1->key,
     746             :                            &denom2->key))
     747     1407550 :     return 1;
     748     5179362 :   tmp1 = *denom1;
     749     5179362 :   tmp2 = *denom2;
     750     5179362 :   tmp1.revoked = false;
     751     5179362 :   tmp2.revoked = false;
     752     5179362 :   memset (&tmp1.key,
     753             :           0,
     754             :           sizeof (tmp1.key));
     755     5179362 :   memset (&tmp2.key,
     756             :           0,
     757             :           sizeof (tmp2.key));
     758     5179362 :   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          62 : 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          62 :     = (unsigned int) json_array_size (hard_limits);
     781          62 :   if ( ((size_t) key_data->hard_limits_length)
     782          62 :        != json_array_size (hard_limits))
     783             :   {
     784           0 :     GNUNET_break (0);
     785           0 :     return GNUNET_SYSERR;
     786             :   }
     787             :   key_data->hard_limits
     788          62 :     = GNUNET_new_array (key_data->hard_limits_length,
     789             :                         struct TALER_EXCHANGE_AccountLimit);
     790             : 
     791          92 :   json_array_foreach (hard_limits, off, obj)
     792             :   {
     793          30 :     struct TALER_EXCHANGE_AccountLimit *al
     794          30 :       = &key_data->hard_limits[off];
     795             :     struct GNUNET_JSON_Specification spec[] = {
     796          30 :       TALER_JSON_spec_kycte ("operation_type",
     797             :                              &al->operation_type),
     798          30 :       TALER_JSON_spec_amount_any ("threshold",
     799             :                                   &al->threshold),
     800          30 :       GNUNET_JSON_spec_relative_time ("timeframe",
     801             :                                       &al->timeframe),
     802          30 :       GNUNET_JSON_spec_end ()
     803             :     };
     804             : 
     805          30 :     if (GNUNET_OK !=
     806          30 :         GNUNET_JSON_parse (obj,
     807             :                            spec,
     808             :                            NULL, NULL))
     809             :     {
     810           0 :       GNUNET_break_op (0);
     811           0 :       return GNUNET_SYSERR;
     812             :     }
     813             :   }
     814          62 :   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          62 : 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          62 :     = (unsigned int) json_array_size (zero_limits);
     836          62 :   if ( ((size_t) key_data->zero_limits_length)
     837          62 :        != json_array_size (zero_limits))
     838             :   {
     839           0 :     GNUNET_break (0);
     840           0 :     return GNUNET_SYSERR;
     841             :   }
     842             :   key_data->zero_limits
     843          62 :     = GNUNET_new_array (key_data->zero_limits_length,
     844             :                         struct TALER_EXCHANGE_ZeroLimitedOperation);
     845             : 
     846          97 :   json_array_foreach (zero_limits, off, obj)
     847             :   {
     848          35 :     struct TALER_EXCHANGE_ZeroLimitedOperation *zol
     849          35 :       = &key_data->zero_limits[off];
     850             :     struct GNUNET_JSON_Specification spec[] = {
     851          35 :       TALER_JSON_spec_kycte ("operation_type",
     852             :                              &zol->operation_type),
     853          35 :       GNUNET_JSON_spec_end ()
     854             :     };
     855             : 
     856          35 :     if (GNUNET_OK !=
     857          35 :         GNUNET_JSON_parse (obj,
     858             :                            spec,
     859             :                            NULL, NULL))
     860             :     {
     861           0 :       GNUNET_break_op (0);
     862           0 :       return GNUNET_SYSERR;
     863             :     }
     864             :   }
     865          62 :   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          62 : 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          62 :   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          62 :   const json_t *recoup_array = NULL;
     894          62 :   const json_t *manifests = NULL;
     895          62 :   bool no_extensions = false;
     896          62 :   bool no_signature = false;
     897             :   const json_t *accounts;
     898             :   const json_t *fees;
     899             :   const json_t *wads;
     900          62 :   struct SignatureContext sig_ctx = { 0 };
     901             : 
     902          62 :   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          62 :       TALER_JSON_spec_version ("version",
     917             :                                &pv),
     918          62 :       GNUNET_JSON_spec_end ()
     919             :     };
     920             : 
     921          62 :     if (GNUNET_OK !=
     922          62 :         GNUNET_JSON_parse (resp_obj,
     923             :                            spec,
     924             :                            NULL, NULL))
     925             :     {
     926           0 :       GNUNET_break_op (0);
     927           0 :       return GNUNET_SYSERR;
     928             :     }
     929          62 :     *vc = TALER_EXCHANGE_VC_MATCH;
     930          62 :     if (EXCHANGE_PROTOCOL_CURRENT < pv.current)
     931             :     {
     932          62 :       *vc |= TALER_EXCHANGE_VC_NEWER;
     933          62 :       if (EXCHANGE_PROTOCOL_CURRENT < pv.current - pv.age)
     934           0 :         *vc |= TALER_EXCHANGE_VC_INCOMPATIBLE;
     935             :     }
     936          62 :     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          62 :       GNUNET_JSON_spec_fixed_auto (
     950             :         "exchange_sig",
     951             :         &exchange_sig),
     952          62 :       GNUNET_JSON_spec_fixed_auto (
     953             :         "exchange_pub",
     954             :         &exchange_pub),
     955          62 :       GNUNET_JSON_spec_fixed_auto (
     956             :         "master_public_key",
     957             :         &key_data->master_pub),
     958          62 :       GNUNET_JSON_spec_array_const ("accounts",
     959             :                                     &accounts),
     960          62 :       GNUNET_JSON_spec_object_const ("wire_fees",
     961             :                                      &fees),
     962          62 :       GNUNET_JSON_spec_array_const ("wads",
     963             :                                     &wads),
     964          62 :       GNUNET_JSON_spec_timestamp (
     965             :         "list_issue_date",
     966             :         &key_data->list_issue_date),
     967          62 :       GNUNET_JSON_spec_relative_time (
     968             :         "reserve_closing_delay",
     969             :         &key_data->reserve_closing_delay),
     970          62 :       GNUNET_JSON_spec_string (
     971             :         "currency",
     972             :         &currency),
     973          62 :       GNUNET_JSON_spec_string (
     974             :         "asset_type",
     975             :         &asset_type),
     976          62 :       GNUNET_JSON_spec_array_const (
     977             :         "global_fees",
     978             :         &global_fees),
     979          62 :       GNUNET_JSON_spec_array_const (
     980             :         "signkeys",
     981             :         &sign_keys_array),
     982          62 :       GNUNET_JSON_spec_array_const (
     983             :         "denominations",
     984             :         &denominations_by_group),
     985          62 :       GNUNET_JSON_spec_mark_optional (
     986             :         GNUNET_JSON_spec_array_const (
     987             :           "recoup",
     988             :           &recoup_array),
     989             :         NULL),
     990          62 :       GNUNET_JSON_spec_array_const (
     991             :         "auditors",
     992             :         &auditors_array),
     993          62 :       GNUNET_JSON_spec_bool (
     994             :         "kyc_enabled",
     995             :         &key_data->kyc_enabled),
     996          62 :       GNUNET_JSON_spec_mark_optional (
     997             :         GNUNET_JSON_spec_object_const ("extensions",
     998             :                                        &manifests),
     999             :         &no_extensions),
    1000          62 :       GNUNET_JSON_spec_mark_optional (
    1001          62 :         GNUNET_JSON_spec_fixed_auto (
    1002             :           "extensions_sig",
    1003             :           &key_data->extensions_sig),
    1004             :         &no_signature),
    1005          62 :       GNUNET_JSON_spec_string ("version",
    1006             :                                &ver),
    1007          62 :       GNUNET_JSON_spec_mark_optional (
    1008             :         GNUNET_JSON_spec_array_const (
    1009             :           "wallet_balance_limit_without_kyc",
    1010             :           &wblwk),
    1011             :         NULL),
    1012          62 :       GNUNET_JSON_spec_end ()
    1013             :     };
    1014             :     const char *emsg;
    1015             :     unsigned int eline;
    1016             : 
    1017          62 :     if (GNUNET_OK !=
    1018          62 :         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          62 :       const json_t *hard_limits = NULL;
    1031          62 :       const json_t *zero_limits = NULL;
    1032             :       struct GNUNET_JSON_Specification sspec[] = {
    1033          62 :         TALER_JSON_spec_currency_specification (
    1034             :           "currency_specification",
    1035             :           currency,
    1036             :           &key_data->cspec),
    1037          62 :         TALER_JSON_spec_amount (
    1038             :           "stefan_abs",
    1039             :           currency,
    1040             :           &key_data->stefan_abs),
    1041          62 :         TALER_JSON_spec_amount (
    1042             :           "stefan_log",
    1043             :           currency,
    1044             :           &key_data->stefan_log),
    1045          62 :         GNUNET_JSON_spec_mark_optional (
    1046             :           GNUNET_JSON_spec_array_const (
    1047             :             "hard_limits",
    1048             :             &hard_limits),
    1049             :           NULL),
    1050          62 :         GNUNET_JSON_spec_mark_optional (
    1051             :           GNUNET_JSON_spec_array_const (
    1052             :             "zero_limits",
    1053             :             &zero_limits),
    1054             :           NULL),
    1055          62 :         GNUNET_JSON_spec_double (
    1056             :           "stefan_lin",
    1057             :           &key_data->stefan_lin),
    1058          62 :         GNUNET_JSON_spec_end ()
    1059             :       };
    1060             : 
    1061          62 :       if (GNUNET_OK !=
    1062          62 :           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         124 :       if ( (NULL != hard_limits) &&
    1074             :            (GNUNET_OK !=
    1075          62 :             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         124 :       if ( (NULL != zero_limits) &&
    1083             :            (GNUNET_OK !=
    1084          62 :             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          62 :     key_data->currency = GNUNET_strdup (currency);
    1094          62 :     key_data->version = GNUNET_strdup (ver);
    1095          62 :     key_data->asset_type = GNUNET_strdup (asset_type);
    1096          62 :     if (! no_extensions)
    1097          23 :       key_data->extensions = json_incref ((json_t *) manifests);
    1098             :   }
    1099             : 
    1100             :   /* parse the global fees */
    1101          62 :   EXITIF (json_array_size (global_fees) > UINT_MAX);
    1102             :   key_data->num_global_fees
    1103          62 :     = (unsigned int) json_array_size (global_fees);
    1104          62 :   if (0 != key_data->num_global_fees)
    1105             :   {
    1106             :     json_t *global_fee;
    1107             :     size_t index;
    1108             : 
    1109             :     key_data->global_fees
    1110          62 :       = GNUNET_new_array (key_data->num_global_fees,
    1111             :                           struct TALER_EXCHANGE_GlobalFee);
    1112         130 :     json_array_foreach (global_fees, index, global_fee)
    1113             :     {
    1114          68 :       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          62 :   EXITIF (json_array_size (sign_keys_array) > UINT_MAX);
    1124             :   key_data->num_sign_keys
    1125          62 :     = (unsigned int) json_array_size (sign_keys_array);
    1126          62 :   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          62 :       = GNUNET_new_array (key_data->num_sign_keys,
    1133             :                           struct TALER_EXCHANGE_SigningPublicKey);
    1134         267 :     json_array_foreach (sign_keys_array, index, sign_key_obj) {
    1135         205 :       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          62 :   if (NULL != wblwk)
    1145             :   {
    1146          62 :     EXITIF (json_array_size (wblwk) > UINT_MAX);
    1147             :     key_data->wblwk_length
    1148          62 :       = (unsigned int) json_array_size (wblwk);
    1149             :     key_data->wallet_balance_limit_without_kyc
    1150          62 :       = GNUNET_new_array (key_data->wblwk_length,
    1151             :                           struct TALER_Amount);
    1152          63 :     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         124 :   key_data->fees = parse_fees (&key_data->master_pub,
    1173          62 :                                key_data->currency,
    1174             :                                fees,
    1175             :                                &key_data->fees_len);
    1176          62 :   EXITIF (NULL == key_data->fees);
    1177             :   /* parse accounts */
    1178          62 :   EXITIF (json_array_size (accounts) > UINT_MAX);
    1179          62 :   GNUNET_array_grow (key_data->accounts,
    1180             :                      key_data->accounts_len,
    1181             :                      json_array_size (accounts));
    1182          62 :   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          62 :   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          62 :   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         573 :     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         511 :       struct TALER_DenominationGroup group = {0};
    1238             :       const json_t *denom_keys_array;
    1239             :       struct GNUNET_JSON_Specification group_spec[] = {
    1240         511 :         TALER_JSON_spec_denomination_group (NULL,
    1241         511 :                                             key_data->currency,
    1242             :                                             &group),
    1243         511 :         GNUNET_JSON_spec_array_const ("denoms",
    1244             :                                       &denom_keys_array),
    1245         511 :         GNUNET_JSON_spec_end ()
    1246             :       };
    1247             :       json_t *denom_key_obj;
    1248             :       unsigned int index;
    1249             : 
    1250         511 :       EXITIF (GNUNET_SYSERR ==
    1251             :               GNUNET_JSON_parse (group_obj,
    1252             :                                  group_spec,
    1253             :                                  NULL,
    1254             :                                  NULL));
    1255             : 
    1256             :       /* Now, parse the individual denominations */
    1257       21191 :       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       20680 :         struct TALER_EXCHANGE_DenomPublicKey dk = {
    1265             :           .value = group.value,
    1266             :           .fees = group.fees,
    1267             :           .key.age_mask = group.age_mask
    1268             :         };
    1269       20680 :         bool found = false;
    1270             : 
    1271       20680 :         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       20680 :         for (unsigned int j = 0;
    1283     6607566 :              j<key_data->num_denom_keys;
    1284     6586886 :              j++)
    1285             :         {
    1286     6586912 :           if (0 == denoms_cmp (&dk,
    1287     6586912 :                                &key_data->denom_keys[j]))
    1288             :           {
    1289          26 :             found = true;
    1290          26 :             break;
    1291             :           }
    1292             :         }
    1293             : 
    1294       20680 :         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       20654 :         if (key_data->denom_keys_size == key_data->num_denom_keys)
    1303         365 :           GNUNET_array_grow (key_data->denom_keys,
    1304             :                              key_data->denom_keys_size,
    1305             :                              key_data->denom_keys_size * 2 + 2);
    1306       20654 :         GNUNET_assert (key_data->denom_keys_size >
    1307             :                        key_data->num_denom_keys);
    1308       20654 :         GNUNET_assert (key_data->num_denom_keys < UINT_MAX);
    1309       20654 :         key_data->denom_keys[key_data->num_denom_keys++] = dk;
    1310             : 
    1311             :         /* Update "last_denom_issue_date" */
    1312       20654 :         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       20654 :           = 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          82 :     json_array_foreach (auditors_array, index, auditor_info)
    1328             :     {
    1329             :       struct TALER_EXCHANGE_AuditorInformation ai;
    1330          20 :       bool found = false;
    1331             : 
    1332          20 :       memset (&ai,
    1333             :               0,
    1334             :               sizeof (ai));
    1335          20 :       EXITIF (GNUNET_SYSERR ==
    1336             :               parse_json_auditor (&ai,
    1337             :                                   check_sig,
    1338             :                                   auditor_info,
    1339             :                                   key_data));
    1340          20 :       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          20 :       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          20 :       if (key_data->auditors_size == key_data->num_auditors)
    1384          20 :         GNUNET_array_grow (key_data->auditors,
    1385             :                            key_data->auditors_size,
    1386             :                            key_data->auditors_size * 2 + 2);
    1387          20 :       GNUNET_assert (key_data->auditors_size >
    1388             :                      key_data->num_auditors);
    1389          20 :       GNUNET_assert (NULL != ai.auditor_url);
    1390          20 :       GNUNET_assert (key_data->num_auditors < UINT_MAX);
    1391          20 :       key_data->auditors[key_data->num_auditors++] = ai;
    1392             :     };
    1393             :   }
    1394             : 
    1395             :   /* parse the revocation/recoup information */
    1396          62 :   if (NULL != recoup_array)
    1397             :   {
    1398             :     json_t *recoup_info;
    1399             :     unsigned int index;
    1400             : 
    1401          62 :     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          62 :   if (check_sig)
    1429             :   {
    1430             :     struct GNUNET_HashContext *hash_context;
    1431             :     struct GNUNET_HashCode hc;
    1432             : 
    1433          42 :     hash_context = GNUNET_CRYPTO_hash_context_start ();
    1434          42 :     qsort (sig_ctx.elements,
    1435          42 :            sig_ctx.elements_pos,
    1436             :            sizeof (struct SignatureElement),
    1437             :            &signature_context_sort_cb);
    1438       13566 :     for (unsigned int i = 0; i<sig_ctx.elements_pos; i++)
    1439             :     {
    1440       13524 :       struct SignatureElement *element = &sig_ctx.elements[i];
    1441             : 
    1442       13524 :       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       13524 :       GNUNET_CRYPTO_hash_context_read (hash_context,
    1448       13524 :                                        &element->master_sig,
    1449             :                                        sizeof (element->master_sig));
    1450             :     }
    1451          42 :     GNUNET_array_grow (sig_ctx.elements,
    1452             :                        sig_ctx.elements_size,
    1453             :                        0);
    1454          42 :     GNUNET_CRYPTO_hash_context_finish (hash_context,
    1455             :                                        &hc);
    1456          42 :     EXITIF (GNUNET_OK !=
    1457             :             TALER_EXCHANGE_test_signing_key (key_data,
    1458             :                                              &exchange_pub));
    1459          42 :     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          62 :   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          42 : keys_completed_cb (void *cls,
    1484             :                    long response_code,
    1485             :                    const void *resp_obj)
    1486             : {
    1487          42 :   struct TALER_EXCHANGE_GetKeysHandle *gkh = cls;
    1488          42 :   const json_t *j = resp_obj;
    1489          42 :   struct TALER_EXCHANGE_Keys *kd = NULL;
    1490          42 :   struct TALER_EXCHANGE_KeysResponse kresp = {
    1491             :     .hr.reply = j,
    1492          42 :     .hr.http_status = (unsigned int) response_code,
    1493             :     .details.ok.compat = TALER_EXCHANGE_VC_PROTOCOL_ERROR,
    1494             :   };
    1495             : 
    1496          42 :   gkh->job = NULL;
    1497          42 :   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          42 :   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          42 :   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          42 :   case MHD_HTTP_OK:
    1521          42 :     if (NULL == j)
    1522             :     {
    1523           0 :       GNUNET_break (0);
    1524           0 :       response_code = 0;
    1525           0 :       break;
    1526             :     }
    1527          42 :     kd = GNUNET_new (struct TALER_EXCHANGE_Keys);
    1528          42 :     kd->exchange_url = GNUNET_strdup (gkh->exchange_url);
    1529          42 :     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        1104 :       for (unsigned int i = 0; i<kd_old->num_denom_keys; i++)
    1548        1096 :         TALER_denom_pub_copy (&kd->denom_keys[i].key,
    1549        1096 :                               &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          42 :     if (GNUNET_OK !=
    1575          42 :         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          42 :     kd->rc = 1;
    1589          42 :     kd->key_data_expiration = gkh->expire;
    1590          42 :     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          42 :     kresp.details.ok.keys = kd;
    1604          42 :     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          42 :   gkh->cert_cb (gkh->cert_cb_cls,
    1638             :                 &kresp,
    1639             :                 kd);
    1640          42 :   TALER_EXCHANGE_get_keys_cancel (gkh);
    1641          42 : }
    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          42 : 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          42 :   if (strlen (dateline) > MAX_DATE_LINE_LEN)
    1683             :   {
    1684           0 :     GNUNET_break_op (0);
    1685           0 :     return GNUNET_SYSERR;
    1686             :   }
    1687          42 :   while (*dateline == ' ')
    1688           0 :     ++dateline;
    1689         210 :   while (*dateline && *dateline != ' ')
    1690         168 :     ++dateline;
    1691          84 :   while (*dateline == ' ')
    1692          42 :     ++dateline;
    1693             :   /* We just skipped over the day of the week. Now we have:*/
    1694          42 :   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          42 :   if (year < 100)
    1710           0 :     year += 1900;
    1711             : 
    1712         252 :   for (mon = 0; ; mon++)
    1713             :   {
    1714         252 :     if (! MONTHS[mon])
    1715             :     {
    1716           0 :       GNUNET_break_op (0);
    1717           0 :       return GNUNET_SYSERR;
    1718             :     }
    1719         252 :     if (0 == strcasecmp (month,
    1720             :                          MONTHS[mon]))
    1721          42 :       break;
    1722             :   }
    1723             : 
    1724          42 :   memset (&tm, 0, sizeof(tm));
    1725          42 :   tm.tm_year = year - 1900;
    1726          42 :   tm.tm_mon = mon;
    1727          42 :   tm.tm_mday = day;
    1728          42 :   tm.tm_hour = hour;
    1729          42 :   tm.tm_min = min;
    1730          42 :   tm.tm_sec = sec;
    1731             : 
    1732          42 :   t = mktime (&tm);
    1733          42 :   if (((time_t) -1) == t)
    1734             :   {
    1735           0 :     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
    1736             :                          "mktime");
    1737           0 :     return GNUNET_SYSERR;
    1738             :   }
    1739          42 :   if (t < 0)
    1740           0 :     t = 0; /* can happen due to timezone issues if date was 1.1.1970 */
    1741          42 :   *at = GNUNET_TIME_timestamp_from_s (t);
    1742          42 :   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         554 : header_cb (char *buffer,
    1759             :            size_t size,
    1760             :            size_t nitems,
    1761             :            void *userdata)
    1762             : {
    1763         554 :   struct TALER_EXCHANGE_GetKeysHandle *kr = userdata;
    1764         554 :   size_t total = size * nitems;
    1765             :   char *val;
    1766             : 
    1767         554 :   if (total < strlen (MHD_HTTP_HEADER_EXPIRES ": "))
    1768          42 :     return total;
    1769         512 :   if (0 != strncasecmp (MHD_HTTP_HEADER_EXPIRES ": ",
    1770             :                         buffer,
    1771             :                         strlen (MHD_HTTP_HEADER_EXPIRES ": ")))
    1772         470 :     return total;
    1773          42 :   val = GNUNET_strndup (&buffer[strlen (MHD_HTTP_HEADER_EXPIRES ": ")],
    1774             :                         total - strlen (MHD_HTTP_HEADER_EXPIRES ": "));
    1775          42 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1776             :               "Found %s header `%s'\n",
    1777             :               MHD_HTTP_HEADER_EXPIRES,
    1778             :               val);
    1779          42 :   if (GNUNET_OK !=
    1780          42 :       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          42 :   GNUNET_free (val);
    1790          42 :   return total;
    1791             : }
    1792             : 
    1793             : 
    1794             : struct TALER_EXCHANGE_GetKeysHandle *
    1795          42 : 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          42 :   char last_date[80] = { 0 };
    1805             : 
    1806          42 :   TALER_LOG_DEBUG ("Connecting to the exchange (%s)\n",
    1807             :                    url);
    1808          42 :   gkh = GNUNET_new (struct TALER_EXCHANGE_GetKeysHandle);
    1809          42 :   gkh->exchange_url = GNUNET_strdup (url);
    1810          42 :   gkh->cert_cb = cert_cb;
    1811          42 :   gkh->cert_cb_cls = cert_cb_cls;
    1812          42 :   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          42 :   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          42 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1835             :               "Requesting keys with URL `%s'.\n",
    1836             :               gkh->url);
    1837          42 :   eh = TALER_EXCHANGE_curl_easy_get_ (gkh->url);
    1838          42 :   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          42 :   GNUNET_break (CURLE_OK ==
    1847             :                 curl_easy_setopt (eh,
    1848             :                                   CURLOPT_VERBOSE,
    1849             :                                   0));
    1850          42 :   GNUNET_break (CURLE_OK ==
    1851             :                 curl_easy_setopt (eh,
    1852             :                                   CURLOPT_TIMEOUT,
    1853             :                                   120 /* seconds */));
    1854          42 :   GNUNET_assert (CURLE_OK ==
    1855             :                  curl_easy_setopt (eh,
    1856             :                                    CURLOPT_HEADERFUNCTION,
    1857             :                                    &header_cb));
    1858          42 :   GNUNET_assert (CURLE_OK ==
    1859             :                  curl_easy_setopt (eh,
    1860             :                                    CURLOPT_HEADERDATA,
    1861             :                                    gkh));
    1862          42 :   gkh->job = GNUNET_CURL_job_add_with_ct_json (ctx,
    1863             :                                                eh,
    1864             :                                                &keys_completed_cb,
    1865             :                                                gkh);
    1866          42 :   return gkh;
    1867             : }
    1868             : 
    1869             : 
    1870             : void
    1871          42 : TALER_EXCHANGE_get_keys_cancel (
    1872             :   struct TALER_EXCHANGE_GetKeysHandle *gkh)
    1873             : {
    1874          42 :   if (NULL != gkh->job)
    1875             :   {
    1876           0 :     GNUNET_CURL_job_cancel (gkh->job);
    1877           0 :     gkh->job = NULL;
    1878             :   }
    1879          42 :   TALER_EXCHANGE_keys_decref (gkh->prev_keys);
    1880          42 :   GNUNET_free (gkh->exchange_url);
    1881          42 :   GNUNET_free (gkh->url);
    1882          42 :   GNUNET_free (gkh);
    1883          42 : }
    1884             : 
    1885             : 
    1886             : enum GNUNET_GenericReturnValue
    1887         201 : 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         201 :   now = GNUNET_TIME_absolute_get ();
    1895         802 :   for (unsigned int i = 0; i<keys->num_sign_keys; i++)
    1896         802 :     if ( (GNUNET_TIME_absolute_cmp (
    1897             :             keys->sign_keys[i].valid_from.abs_time,
    1898             :             <=,
    1899             :             GNUNET_TIME_absolute_add (now,
    1900         201 :                                       LIFETIME_TOLERANCE))) &&
    1901         201 :          (GNUNET_TIME_absolute_cmp (
    1902             :             keys->sign_keys[i].valid_until.abs_time,
    1903             :             >,
    1904             :             GNUNET_TIME_absolute_subtract (now,
    1905         201 :                                            LIFETIME_TOLERANCE))) &&
    1906         201 :          (0 == GNUNET_memcmp (pub,
    1907             :                               &keys->sign_keys[i].key)) )
    1908         201 :       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        1530 :   for (unsigned int i = 0; i<keys->num_denom_keys; i++)
    1922        1530 :     if (0 ==
    1923        1530 :         TALER_denom_pub_cmp (pk,
    1924        1530 :                              &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         125 : 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       44501 :   for (unsigned int i = 0; i<keys->num_denom_keys; i++)
    1981       44501 :     if (0 == GNUNET_memcmp (hc,
    1982             :                             &keys->denom_keys[i].h_key))
    1983         125 :       return &keys->denom_keys[i];
    1984           0 :   return NULL;
    1985             : }
    1986             : 
    1987             : 
    1988             : struct TALER_EXCHANGE_Keys *
    1989         385 : TALER_EXCHANGE_keys_incref (struct TALER_EXCHANGE_Keys *keys)
    1990             : {
    1991         385 :   GNUNET_assert (keys->rc < UINT_MAX);
    1992         385 :   keys->rc++;
    1993         385 :   return keys;
    1994             : }
    1995             : 
    1996             : 
    1997             : void
    1998         513 : TALER_EXCHANGE_keys_decref (struct TALER_EXCHANGE_Keys *keys)
    1999             : {
    2000         513 :   if (NULL == keys)
    2001          66 :     return;
    2002         447 :   GNUNET_assert (0 < keys->rc);
    2003         447 :   keys->rc--;
    2004         447 :   if (0 != keys->rc)
    2005         385 :     return;
    2006          62 :   GNUNET_array_grow (keys->sign_keys,
    2007             :                      keys->num_sign_keys,
    2008             :                      0);
    2009       21812 :   for (unsigned int i = 0; i<keys->num_denom_keys; i++)
    2010       21750 :     TALER_denom_pub_free (&keys->denom_keys[i].key);
    2011             : 
    2012          62 :   GNUNET_array_grow (keys->denom_keys,
    2013             :                      keys->denom_keys_size,
    2014             :                      0);
    2015          84 :   for (unsigned int i = 0; i<keys->num_auditors; i++)
    2016             :   {
    2017          22 :     GNUNET_array_grow (keys->auditors[i].denom_keys,
    2018             :                        keys->auditors[i].num_denom_keys,
    2019             :                        0);
    2020          22 :     GNUNET_free (keys->auditors[i].auditor_url);
    2021             :   }
    2022          62 :   GNUNET_array_grow (keys->auditors,
    2023             :                      keys->auditors_size,
    2024             :                      0);
    2025          62 :   TALER_EXCHANGE_free_accounts (keys->accounts_len,
    2026             :                                 keys->accounts);
    2027          62 :   GNUNET_array_grow (keys->accounts,
    2028             :                      keys->accounts_len,
    2029             :                      0);
    2030          62 :   free_fees (keys->fees,
    2031             :              keys->fees_len);
    2032          62 :   GNUNET_array_grow (keys->hard_limits,
    2033             :                      keys->hard_limits_length,
    2034             :                      0);
    2035          62 :   GNUNET_array_grow (keys->zero_limits,
    2036             :                      keys->zero_limits_length,
    2037             :                      0);
    2038          62 :   json_decref (keys->extensions);
    2039          62 :   GNUNET_free (keys->cspec.name);
    2040          62 :   json_decref (keys->cspec.map_alt_unit_names);
    2041          62 :   GNUNET_free (keys->wallet_balance_limit_without_kyc);
    2042          62 :   GNUNET_free (keys->version);
    2043          62 :   GNUNET_free (keys->currency);
    2044          62 :   GNUNET_free (keys->asset_type);
    2045          62 :   GNUNET_free (keys->global_fees);
    2046          62 :   GNUNET_free (keys->exchange_url);
    2047          62 :   GNUNET_free (keys);
    2048             : }
    2049             : 
    2050             : 
    2051             : struct TALER_EXCHANGE_Keys *
    2052          20 : TALER_EXCHANGE_keys_from_json (const json_t *j)
    2053             : {
    2054             :   const json_t *jkeys;
    2055             :   const char *url;
    2056             :   uint32_t version;
    2057          20 :   struct GNUNET_TIME_Timestamp expire
    2058             :     = GNUNET_TIME_UNIT_ZERO_TS;
    2059             :   struct GNUNET_JSON_Specification spec[] = {
    2060          20 :     GNUNET_JSON_spec_uint32 ("version",
    2061             :                              &version),
    2062          20 :     GNUNET_JSON_spec_object_const ("keys",
    2063             :                                    &jkeys),
    2064          20 :     TALER_JSON_spec_web_url ("exchange_url",
    2065             :                              &url),
    2066          20 :     GNUNET_JSON_spec_mark_optional (
    2067             :       GNUNET_JSON_spec_timestamp ("expire",
    2068             :                                   &expire),
    2069             :       NULL),
    2070          20 :     GNUNET_JSON_spec_end ()
    2071             :   };
    2072             :   struct TALER_EXCHANGE_Keys *keys;
    2073             :   enum TALER_EXCHANGE_VersionCompatibility compat;
    2074             : 
    2075          20 :   if (NULL == j)
    2076           0 :     return NULL;
    2077          20 :   if (GNUNET_OK !=
    2078          20 :       GNUNET_JSON_parse (j,
    2079             :                          spec,
    2080             :                          NULL, NULL))
    2081             :   {
    2082           0 :     GNUNET_break_op (0);
    2083           0 :     return NULL;
    2084             :   }
    2085          20 :   if (0 != version)
    2086             :   {
    2087           0 :     return NULL; /* unsupported version */
    2088             :   }
    2089          20 :   keys = GNUNET_new (struct TALER_EXCHANGE_Keys);
    2090          20 :   if (GNUNET_OK !=
    2091          20 :       decode_keys_json (jkeys,
    2092             :                         false,
    2093             :                         keys,
    2094             :                         &compat))
    2095             :   {
    2096           0 :     GNUNET_break (0);
    2097           0 :     return NULL;
    2098             :   }
    2099          20 :   keys->rc = 1;
    2100          20 :   keys->key_data_expiration = expire;
    2101          20 :   keys->exchange_url = GNUNET_strdup (url);
    2102          20 :   return keys;
    2103             : }
    2104             : 
    2105             : 
    2106             : /**
    2107             :  * Data we track per denomination group.
    2108             :  */
    2109             : struct GroupData
    2110             : {
    2111             :   /**
    2112             :    * The json blob with the group meta-data and list of denominations
    2113             :    */
    2114             :   json_t *json;
    2115             : 
    2116             :   /**
    2117             :    * Meta data for this group.
    2118             :    */
    2119             :   struct TALER_DenominationGroup meta;
    2120             : };
    2121             : 
    2122             : 
    2123             : /**
    2124             :  * Add denomination group represented by @a value
    2125             :  * to list of denominations in @a cls. Also frees
    2126             :  * the @a value.
    2127             :  *
    2128             :  * @param[in,out] cls a `json_t *` with an array to build
    2129             :  * @param key unused
    2130             :  * @param value a `struct GroupData *`
    2131             :  * @return #GNUNET_OK (continue to iterate)
    2132             :  */
    2133             : static enum GNUNET_GenericReturnValue
    2134         108 : add_grp (void *cls,
    2135             :          const struct GNUNET_HashCode *key,
    2136             :          void *value)
    2137             : {
    2138         108 :   json_t *denominations_by_group = cls;
    2139         108 :   struct GroupData *gd = value;
    2140             :   const char *cipher;
    2141             :   json_t *ge;
    2142         108 :   bool age_restricted = gd->meta.age_mask.bits != 0;
    2143             : 
    2144             :   (void) key;
    2145         108 :   switch (gd->meta.cipher)
    2146             :   {
    2147          95 :   case GNUNET_CRYPTO_BSA_RSA:
    2148          95 :     cipher = age_restricted ? "RSA+age_restricted" : "RSA";
    2149          95 :     break;
    2150          13 :   case GNUNET_CRYPTO_BSA_CS:
    2151          13 :     cipher = age_restricted ? "CS+age_restricted" : "CS";
    2152          13 :     break;
    2153           0 :   default:
    2154           0 :     GNUNET_assert (false);
    2155             :   }
    2156             : 
    2157         108 :   ge = GNUNET_JSON_PACK (
    2158             :     GNUNET_JSON_pack_string ("cipher",
    2159             :                              cipher),
    2160             :     GNUNET_JSON_pack_array_steal ("denoms",
    2161             :                                   gd->json),
    2162             :     TALER_JSON_PACK_DENOM_FEES ("fee",
    2163             :                                 &gd->meta.fees),
    2164             :     GNUNET_JSON_pack_allow_null (
    2165             :       age_restricted
    2166             :           ? GNUNET_JSON_pack_uint64 ("age_mask",
    2167             :                                      gd->meta.age_mask.bits)
    2168             :           : GNUNET_JSON_pack_string ("dummy",
    2169             :                                      NULL)),
    2170             :     TALER_JSON_pack_amount ("value",
    2171             :                             &gd->meta.value));
    2172         108 :   GNUNET_assert (0 ==
    2173             :                  json_array_append_new (denominations_by_group,
    2174             :                                         ge));
    2175         108 :   GNUNET_free (gd);
    2176         108 :   return GNUNET_OK;
    2177             : }
    2178             : 
    2179             : 
    2180             : /**
    2181             :  * Convert array of account restrictions @a ars to JSON.
    2182             :  *
    2183             :  * @param ar_len length of @a ars
    2184             :  * @param ars account restrictions to convert
    2185             :  * @return JSON representation
    2186             :  */
    2187             : static json_t *
    2188          28 : ar_to_json (unsigned int ar_len,
    2189             :             const struct TALER_EXCHANGE_AccountRestriction ars[static ar_len])
    2190          28 : {
    2191             :   json_t *rval;
    2192             : 
    2193          28 :   rval = json_array ();
    2194          28 :   GNUNET_assert (NULL != rval);
    2195          32 :   for (unsigned int i = 0; i<ar_len; i++)
    2196             :   {
    2197           4 :     const struct TALER_EXCHANGE_AccountRestriction *ar = &ars[i];
    2198             : 
    2199           4 :     switch (ar->type)
    2200             :     {
    2201           0 :     case TALER_EXCHANGE_AR_INVALID:
    2202           0 :       GNUNET_break (0);
    2203           0 :       json_decref (rval);
    2204           0 :       return NULL;
    2205           0 :     case TALER_EXCHANGE_AR_DENY:
    2206           0 :       GNUNET_assert (
    2207             :         0 ==
    2208             :         json_array_append_new (
    2209             :           rval,
    2210             :           GNUNET_JSON_PACK (
    2211             :             GNUNET_JSON_pack_string ("type",
    2212             :                                      "deny"))));
    2213           0 :       break;
    2214           4 :     case TALER_EXCHANGE_AR_REGEX:
    2215           4 :       GNUNET_assert (
    2216             :         0 ==
    2217             :         json_array_append_new (
    2218             :           rval,
    2219             :           GNUNET_JSON_PACK (
    2220             :             GNUNET_JSON_pack_string (
    2221             :               "type",
    2222             :               "regex"),
    2223             :             GNUNET_JSON_pack_string (
    2224             :               "payto_regex",
    2225             :               ar->details.regex.posix_egrep),
    2226             :             GNUNET_JSON_pack_string (
    2227             :               "human_hint",
    2228             :               ar->details.regex.human_hint),
    2229             :             GNUNET_JSON_pack_object_incref (
    2230             :               "human_hint_i18n",
    2231             :               (json_t *) ar->details.regex.human_hint_i18n)
    2232             :             )));
    2233           4 :       break;
    2234             :     }
    2235             :   }
    2236          28 :   return rval;
    2237             : }
    2238             : 
    2239             : 
    2240             : json_t *
    2241          14 : TALER_EXCHANGE_keys_to_json (const struct TALER_EXCHANGE_Keys *kd)
    2242             : {
    2243             :   struct GNUNET_TIME_Timestamp now;
    2244             :   json_t *keys;
    2245             :   json_t *signkeys;
    2246             :   json_t *denominations_by_group;
    2247             :   json_t *auditors;
    2248             :   json_t *recoup;
    2249             :   json_t *wire_fees;
    2250             :   json_t *accounts;
    2251             :   json_t *global_fees;
    2252          14 :   json_t *wblwk = NULL;
    2253             :   json_t *hard_limits;
    2254             :   json_t *zero_limits;
    2255             : 
    2256          14 :   now = GNUNET_TIME_timestamp_get ();
    2257          14 :   signkeys = json_array ();
    2258          14 :   GNUNET_assert (NULL != signkeys);
    2259          52 :   for (unsigned int i = 0; i<kd->num_sign_keys; i++)
    2260             :   {
    2261          38 :     const struct TALER_EXCHANGE_SigningPublicKey *sk = &kd->sign_keys[i];
    2262             :     json_t *signkey;
    2263             : 
    2264          38 :     if (GNUNET_TIME_timestamp_cmp (now,
    2265             :                                    >,
    2266             :                                    sk->valid_until))
    2267           0 :       continue; /* skip keys that have expired */
    2268          38 :     signkey = GNUNET_JSON_PACK (
    2269             :       GNUNET_JSON_pack_data_auto ("key",
    2270             :                                   &sk->key),
    2271             :       GNUNET_JSON_pack_data_auto ("master_sig",
    2272             :                                   &sk->master_sig),
    2273             :       GNUNET_JSON_pack_timestamp ("stamp_start",
    2274             :                                   sk->valid_from),
    2275             :       GNUNET_JSON_pack_timestamp ("stamp_expire",
    2276             :                                   sk->valid_until),
    2277             :       GNUNET_JSON_pack_timestamp ("stamp_end",
    2278             :                                   sk->valid_legal));
    2279          38 :     GNUNET_assert (NULL != signkey);
    2280          38 :     GNUNET_assert (0 ==
    2281             :                    json_array_append_new (signkeys,
    2282             :                                           signkey));
    2283             :   }
    2284             : 
    2285          14 :   denominations_by_group = json_array ();
    2286          14 :   GNUNET_assert (NULL != denominations_by_group);
    2287             :   {
    2288             :     struct GNUNET_CONTAINER_MultiHashMap *dbg;
    2289             : 
    2290          14 :     dbg = GNUNET_CONTAINER_multihashmap_create (128,
    2291             :                                                 false);
    2292        4140 :     for (unsigned int i = 0; i<kd->num_denom_keys; i++)
    2293             :     {
    2294        4126 :       const struct TALER_EXCHANGE_DenomPublicKey *dk = &kd->denom_keys[i];
    2295        4126 :       struct TALER_DenominationGroup meta = {
    2296        4126 :         .cipher = dk->key.bsign_pub_key->cipher,
    2297             :         .value = dk->value,
    2298             :         .fees = dk->fees,
    2299             :         .age_mask = dk->key.age_mask
    2300             :       };
    2301             :       struct GNUNET_HashCode key;
    2302             :       struct GroupData *gd;
    2303             :       json_t *denom;
    2304             :       struct GNUNET_JSON_PackSpec key_spec;
    2305             : 
    2306        4126 :       if (GNUNET_TIME_timestamp_cmp (now,
    2307             :                                      >,
    2308             :                                      dk->expire_deposit))
    2309           0 :         continue; /* skip keys that have expired */
    2310        4126 :       TALER_denomination_group_get_key (&meta,
    2311             :                                         &key);
    2312        4126 :       gd = GNUNET_CONTAINER_multihashmap_get (dbg,
    2313             :                                               &key);
    2314        4126 :       if (NULL == gd)
    2315             :       {
    2316         108 :         gd = GNUNET_new (struct GroupData);
    2317         108 :         gd->meta = meta;
    2318         108 :         gd->json = json_array ();
    2319         108 :         GNUNET_assert (NULL != gd->json);
    2320         108 :         GNUNET_assert (
    2321             :           GNUNET_OK ==
    2322             :           GNUNET_CONTAINER_multihashmap_put (dbg,
    2323             :                                              &key,
    2324             :                                              gd,
    2325             :                                              GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    2326             : 
    2327             :       }
    2328        4126 :       switch (meta.cipher)
    2329             :       {
    2330        3578 :       case GNUNET_CRYPTO_BSA_RSA:
    2331             :         key_spec =
    2332        3578 :           GNUNET_JSON_pack_rsa_public_key (
    2333             :             "rsa_pub",
    2334        3578 :             dk->key.bsign_pub_key->details.rsa_public_key);
    2335        3578 :         break;
    2336         548 :       case GNUNET_CRYPTO_BSA_CS:
    2337             :         key_spec =
    2338         548 :           GNUNET_JSON_pack_data_varsize (
    2339             :             "cs_pub",
    2340         548 :             &dk->key.bsign_pub_key->details.cs_public_key,
    2341             :             sizeof (dk->key.bsign_pub_key->details.cs_public_key));
    2342         548 :         break;
    2343           0 :       default:
    2344           0 :         GNUNET_assert (false);
    2345             :       }
    2346        4126 :       denom = GNUNET_JSON_PACK (
    2347             :         GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
    2348             :                                     dk->expire_deposit),
    2349             :         GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
    2350             :                                     dk->withdraw_valid_until),
    2351             :         GNUNET_JSON_pack_timestamp ("stamp_start",
    2352             :                                     dk->valid_from),
    2353             :         GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
    2354             :                                     dk->expire_legal),
    2355             :         GNUNET_JSON_pack_data_auto ("master_sig",
    2356             :                                     &dk->master_sig),
    2357             :         key_spec
    2358             :         );
    2359        4126 :       GNUNET_assert (0 ==
    2360             :                      json_array_append_new (gd->json,
    2361             :                                             denom));
    2362             :     }
    2363          14 :     GNUNET_CONTAINER_multihashmap_iterate (dbg,
    2364             :                                            &add_grp,
    2365             :                                            denominations_by_group);
    2366          14 :     GNUNET_CONTAINER_multihashmap_destroy (dbg);
    2367             :   }
    2368             : 
    2369          14 :   auditors = json_array ();
    2370          14 :   GNUNET_assert (NULL != auditors);
    2371          18 :   for (unsigned int i = 0; i<kd->num_auditors; i++)
    2372             :   {
    2373           4 :     const struct TALER_EXCHANGE_AuditorInformation *ai = &kd->auditors[i];
    2374             :     json_t *a;
    2375             :     json_t *adenoms;
    2376             : 
    2377           4 :     adenoms = json_array ();
    2378           4 :     GNUNET_assert (NULL != adenoms);
    2379           4 :     for (unsigned int j = 0; j<ai->num_denom_keys; j++)
    2380             :     {
    2381           0 :       const struct TALER_EXCHANGE_AuditorDenominationInfo *adi =
    2382           0 :         &ai->denom_keys[j];
    2383           0 :       const struct TALER_EXCHANGE_DenomPublicKey *dk =
    2384           0 :         &kd->denom_keys[adi->denom_key_offset];
    2385             :       json_t *k;
    2386             : 
    2387           0 :       GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys);
    2388           0 :       if (GNUNET_TIME_timestamp_cmp (now,
    2389             :                                      >,
    2390             :                                      dk->expire_deposit))
    2391           0 :         continue; /* skip auditor signatures for denomination keys that have expired */
    2392           0 :       GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys);
    2393           0 :       k = GNUNET_JSON_PACK (
    2394             :         GNUNET_JSON_pack_data_auto ("denom_pub_h",
    2395             :                                     &dk->h_key),
    2396             :         GNUNET_JSON_pack_data_auto ("auditor_sig",
    2397             :                                     &adi->auditor_sig));
    2398           0 :       GNUNET_assert (0 ==
    2399             :                      json_array_append_new (adenoms,
    2400             :                                             k));
    2401             :     }
    2402             : 
    2403           4 :     a = GNUNET_JSON_PACK (
    2404             :       GNUNET_JSON_pack_data_auto ("auditor_pub",
    2405             :                                   &ai->auditor_pub),
    2406             :       GNUNET_JSON_pack_string ("auditor_url",
    2407             :                                ai->auditor_url),
    2408             :       GNUNET_JSON_pack_array_steal ("denomination_keys",
    2409             :                                     adenoms));
    2410           4 :     GNUNET_assert (0 ==
    2411             :                    json_array_append_new (auditors,
    2412             :                                           a));
    2413             :   }
    2414             : 
    2415          14 :   global_fees = json_array ();
    2416          14 :   GNUNET_assert (NULL != global_fees);
    2417          30 :   for (unsigned int i = 0; i<kd->num_global_fees; i++)
    2418             :   {
    2419          16 :     const struct TALER_EXCHANGE_GlobalFee *gf
    2420          16 :       = &kd->global_fees[i];
    2421             : 
    2422          16 :     if (GNUNET_TIME_absolute_is_past (gf->end_date.abs_time))
    2423           0 :       continue;
    2424          16 :     GNUNET_assert (
    2425             :       0 ==
    2426             :       json_array_append_new (
    2427             :         global_fees,
    2428             :         GNUNET_JSON_PACK (
    2429             :           GNUNET_JSON_pack_timestamp ("start_date",
    2430             :                                       gf->start_date),
    2431             :           GNUNET_JSON_pack_timestamp ("end_date",
    2432             :                                       gf->end_date),
    2433             :           TALER_JSON_PACK_GLOBAL_FEES (&gf->fees),
    2434             :           GNUNET_JSON_pack_time_rel ("history_expiration",
    2435             :                                      gf->history_expiration),
    2436             :           GNUNET_JSON_pack_time_rel ("purse_timeout",
    2437             :                                      gf->purse_timeout),
    2438             :           GNUNET_JSON_pack_uint64 ("purse_account_limit",
    2439             :                                    gf->purse_account_limit),
    2440             :           GNUNET_JSON_pack_data_auto ("master_sig",
    2441             :                                       &gf->master_sig))));
    2442             :   }
    2443             : 
    2444          14 :   accounts = json_array ();
    2445          14 :   GNUNET_assert (NULL != accounts);
    2446          28 :   for (unsigned int i = 0; i<kd->accounts_len; i++)
    2447             :   {
    2448          14 :     const struct TALER_EXCHANGE_WireAccount *acc
    2449          14 :       = &kd->accounts[i];
    2450             :     json_t *credit_restrictions;
    2451             :     json_t *debit_restrictions;
    2452             : 
    2453             :     credit_restrictions
    2454          14 :       = ar_to_json (acc->credit_restrictions_length,
    2455          14 :                     acc->credit_restrictions);
    2456          14 :     GNUNET_assert (NULL != credit_restrictions);
    2457             :     debit_restrictions
    2458          14 :       = ar_to_json (acc->debit_restrictions_length,
    2459          14 :                     acc->debit_restrictions);
    2460          14 :     GNUNET_assert (NULL != debit_restrictions);
    2461          14 :     GNUNET_assert (
    2462             :       0 ==
    2463             :       json_array_append_new (
    2464             :         accounts,
    2465             :         GNUNET_JSON_PACK (
    2466             :           TALER_JSON_pack_full_payto ("payto_uri",
    2467             :                                       acc->fpayto_uri),
    2468             :           GNUNET_JSON_pack_allow_null (
    2469             :             GNUNET_JSON_pack_string ("conversion_url",
    2470             :                                      acc->conversion_url)),
    2471             :           GNUNET_JSON_pack_int64 ("priority",
    2472             :                                   acc->priority),
    2473             :           GNUNET_JSON_pack_allow_null (
    2474             :             GNUNET_JSON_pack_string ("bank_label",
    2475             :                                      acc->bank_label)),
    2476             :           GNUNET_JSON_pack_array_steal ("debit_restrictions",
    2477             :                                         debit_restrictions),
    2478             :           GNUNET_JSON_pack_array_steal ("credit_restrictions",
    2479             :                                         credit_restrictions),
    2480             :           GNUNET_JSON_pack_data_auto ("master_sig",
    2481             :                                       &acc->master_sig))));
    2482             :   }
    2483          14 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2484             :               "Serialized %u/%u wire accounts to JSON\n",
    2485             :               (unsigned int) json_array_size (accounts),
    2486             :               kd->accounts_len);
    2487             : 
    2488          14 :   wire_fees = json_object ();
    2489          14 :   GNUNET_assert (NULL != wire_fees);
    2490          28 :   for (unsigned int i = 0; i<kd->fees_len; i++)
    2491             :   {
    2492          14 :     const struct TALER_EXCHANGE_WireFeesByMethod *fbw
    2493          14 :       = &kd->fees[i];
    2494             :     json_t *wf;
    2495             : 
    2496          14 :     wf = json_array ();
    2497          14 :     GNUNET_assert (NULL != wf);
    2498          14 :     for (struct TALER_EXCHANGE_WireAggregateFees *p = fbw->fees_head;
    2499          30 :          NULL != p;
    2500          16 :          p = p->next)
    2501             :     {
    2502          16 :       GNUNET_assert (
    2503             :         0 ==
    2504             :         json_array_append_new (
    2505             :           wf,
    2506             :           GNUNET_JSON_PACK (
    2507             :             TALER_JSON_pack_amount ("wire_fee",
    2508             :                                     &p->fees.wire),
    2509             :             TALER_JSON_pack_amount ("closing_fee",
    2510             :                                     &p->fees.closing),
    2511             :             GNUNET_JSON_pack_timestamp ("start_date",
    2512             :                                         p->start_date),
    2513             :             GNUNET_JSON_pack_timestamp ("end_date",
    2514             :                                         p->end_date),
    2515             :             GNUNET_JSON_pack_data_auto ("sig",
    2516             :                                         &p->master_sig))));
    2517             :     }
    2518          14 :     GNUNET_assert (0 ==
    2519             :                    json_object_set_new (wire_fees,
    2520             :                                         fbw->method,
    2521             :                                         wf));
    2522             :   }
    2523             : 
    2524          14 :   recoup = json_array ();
    2525          14 :   GNUNET_assert (NULL != recoup);
    2526        4140 :   for (unsigned int i = 0; i<kd->num_denom_keys; i++)
    2527             :   {
    2528        4126 :     const struct TALER_EXCHANGE_DenomPublicKey *dk
    2529        4126 :       = &kd->denom_keys[i];
    2530        4126 :     if (! dk->revoked)
    2531        4126 :       continue;
    2532           0 :     GNUNET_assert (0 ==
    2533             :                    json_array_append_new (
    2534             :                      recoup,
    2535             :                      GNUNET_JSON_PACK (
    2536             :                        GNUNET_JSON_pack_data_auto ("h_denom_pub",
    2537             :                                                    &dk->h_key))));
    2538             :   }
    2539             : 
    2540          14 :   wblwk = json_array ();
    2541          14 :   GNUNET_assert (NULL != wblwk);
    2542          14 :   for (unsigned int i = 0; i<kd->wblwk_length; i++)
    2543             :   {
    2544           0 :     const struct TALER_Amount *a = &kd->wallet_balance_limit_without_kyc[i];
    2545             : 
    2546           0 :     GNUNET_assert (0 ==
    2547             :                    json_array_append_new (
    2548             :                      wblwk,
    2549             :                      TALER_JSON_from_amount (a)));
    2550             :   }
    2551             : 
    2552          14 :   hard_limits = json_array ();
    2553          24 :   for (unsigned int i = 0; i < kd->hard_limits_length; i++)
    2554             :   {
    2555          10 :     const struct TALER_EXCHANGE_AccountLimit *al
    2556          10 :       = &kd->hard_limits[i];
    2557             :     json_t *j;
    2558             : 
    2559          10 :     j = GNUNET_JSON_PACK (
    2560             :       TALER_JSON_pack_amount ("threshold",
    2561             :                               &al->threshold),
    2562             :       GNUNET_JSON_pack_time_rel ("timeframe",
    2563             :                                  al->timeframe),
    2564             :       TALER_JSON_pack_kycte ("operation_type",
    2565             :                              al->operation_type)
    2566             :       );
    2567          10 :     GNUNET_assert (0 ==
    2568             :                    json_array_append_new (
    2569             :                      hard_limits,
    2570             :                      j));
    2571             :   }
    2572             : 
    2573          14 :   zero_limits = json_array ();
    2574          20 :   for (unsigned int i = 0; i < kd->zero_limits_length; i++)
    2575             :   {
    2576           6 :     const struct TALER_EXCHANGE_ZeroLimitedOperation *zol
    2577           6 :       = &kd->zero_limits[i];
    2578             :     json_t *j;
    2579             : 
    2580           6 :     j = GNUNET_JSON_PACK (
    2581             :       TALER_JSON_pack_kycte ("operation_type",
    2582             :                              zol->operation_type)
    2583             :       );
    2584           6 :     GNUNET_assert (0 ==
    2585             :                    json_array_append_new (
    2586             :                      zero_limits,
    2587             :                      j));
    2588             :   }
    2589             : 
    2590          14 :   keys = GNUNET_JSON_PACK (
    2591             :     GNUNET_JSON_pack_string ("version",
    2592             :                              kd->version),
    2593             :     GNUNET_JSON_pack_string ("currency",
    2594             :                              kd->currency),
    2595             :     GNUNET_JSON_pack_object_steal ("currency_specification",
    2596             :                                    TALER_CONFIG_currency_specs_to_json (
    2597             :                                      &kd->cspec)),
    2598             :     TALER_JSON_pack_amount ("stefan_abs",
    2599             :                             &kd->stefan_abs),
    2600             :     TALER_JSON_pack_amount ("stefan_log",
    2601             :                             &kd->stefan_log),
    2602             :     GNUNET_JSON_pack_double ("stefan_lin",
    2603             :                              kd->stefan_lin),
    2604             :     GNUNET_JSON_pack_string ("asset_type",
    2605             :                              kd->asset_type),
    2606             :     GNUNET_JSON_pack_data_auto ("master_public_key",
    2607             :                                 &kd->master_pub),
    2608             :     GNUNET_JSON_pack_time_rel ("reserve_closing_delay",
    2609             :                                kd->reserve_closing_delay),
    2610             :     GNUNET_JSON_pack_timestamp ("list_issue_date",
    2611             :                                 kd->list_issue_date),
    2612             :     GNUNET_JSON_pack_array_steal ("global_fees",
    2613             :                                   global_fees),
    2614             :     GNUNET_JSON_pack_array_steal ("signkeys",
    2615             :                                   signkeys),
    2616             :     GNUNET_JSON_pack_object_steal ("wire_fees",
    2617             :                                    wire_fees),
    2618             :     GNUNET_JSON_pack_array_steal ("accounts",
    2619             :                                   accounts),
    2620             :     GNUNET_JSON_pack_array_steal ("wads",
    2621             :                                   json_array ()),
    2622             :     GNUNET_JSON_pack_array_steal ("hard_limits",
    2623             :                                   hard_limits),
    2624             :     GNUNET_JSON_pack_array_steal ("zero_limits",
    2625             :                                   zero_limits),
    2626             :     GNUNET_JSON_pack_array_steal ("denominations",
    2627             :                                   denominations_by_group),
    2628             :     GNUNET_JSON_pack_allow_null (
    2629             :       GNUNET_JSON_pack_array_steal ("recoup",
    2630             :                                     recoup)),
    2631             :     GNUNET_JSON_pack_array_steal ("auditors",
    2632             :                                   auditors),
    2633             :     GNUNET_JSON_pack_bool ("kyc_enabled",
    2634             :                            kd->kyc_enabled),
    2635             :     GNUNET_JSON_pack_allow_null (
    2636             :       GNUNET_JSON_pack_object_incref ("extensions",
    2637             :                                       kd->extensions)),
    2638             :     GNUNET_JSON_pack_allow_null (
    2639             :       GNUNET_is_zero (&kd->extensions_sig)
    2640             :       ? GNUNET_JSON_pack_string ("dummy",
    2641             :                                  NULL)
    2642             :       : GNUNET_JSON_pack_data_auto ("extensions_sig",
    2643             :                                     &kd->extensions_sig)),
    2644             :     GNUNET_JSON_pack_allow_null (
    2645             :       GNUNET_JSON_pack_array_steal ("wallet_balance_limit_without_kyc",
    2646             :                                     wblwk))
    2647             : 
    2648             :     );
    2649          14 :   return GNUNET_JSON_PACK (
    2650             :     GNUNET_JSON_pack_uint64 ("version",
    2651             :                              EXCHANGE_SERIALIZATION_FORMAT_VERSION),
    2652             :     GNUNET_JSON_pack_allow_null (
    2653             :       GNUNET_JSON_pack_timestamp ("expire",
    2654             :                                   kd->key_data_expiration)),
    2655             :     GNUNET_JSON_pack_string ("exchange_url",
    2656             :                              kd->exchange_url),
    2657             :     GNUNET_JSON_pack_object_steal ("keys",
    2658             :                                    keys));
    2659             : }
    2660             : 
    2661             : 
    2662             : /* end of exchange_api_handle.c */

Generated by: LCOV version 1.16