LCOV - code coverage report
Current view: top level - lib - exchange_api_handle.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 0 771 0.0 %
Date: 2022-08-25 06:15:09 Functions: 0 35 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014-2022 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 14
      44             : 
      45             : /**
      46             :  * How many versions are we backwards compatible with?
      47             :  */
      48             : #define EXCHANGE_PROTOCOL_AGE 0
      49             : 
      50             : /**
      51             :  * Current version for (local) JSON serialization of persisted
      52             :  * /keys data.
      53             :  */
      54             : #define EXCHANGE_SERIALIZATION_FORMAT_VERSION 0
      55             : 
      56             : /**
      57             :  * How far off do we allow key liftimes to be?
      58             :  */
      59             : #define LIFETIME_TOLERANCE GNUNET_TIME_UNIT_HOURS
      60             : 
      61             : /**
      62             :  * If the "Expire" cache control header is missing, for
      63             :  * how long do we assume the reply to be valid at least?
      64             :  */
      65             : #define DEFAULT_EXPIRATION GNUNET_TIME_UNIT_HOURS
      66             : 
      67             : /**
      68             :  * Set to 1 for extra debug logging.
      69             :  */
      70             : #define DEBUG 0
      71             : 
      72             : /**
      73             :  * Log error related to CURL operations.
      74             :  *
      75             :  * @param type log level
      76             :  * @param function which function failed to run
      77             :  * @param code what was the curl error code
      78             :  */
      79             : #define CURL_STRERROR(type, function, code)      \
      80             :   GNUNET_log (type, "Curl function `%s' has failed at `%s:%d' with error: %s", \
      81             :               function, __FILE__, __LINE__, curl_easy_strerror (code));
      82             : 
      83             : 
      84             : /**
      85             :  * Data for the request to get the /keys of a exchange.
      86             :  */
      87             : struct KeysRequest;
      88             : 
      89             : 
      90             : /**
      91             :  * Entry in DLL of auditors used by an exchange.
      92             :  */
      93             : struct TEAH_AuditorListEntry
      94             : {
      95             :   /**
      96             :    * Next pointer of DLL.
      97             :    */
      98             :   struct TEAH_AuditorListEntry *next;
      99             : 
     100             :   /**
     101             :    * Prev pointer of DLL.
     102             :    */
     103             :   struct TEAH_AuditorListEntry *prev;
     104             : 
     105             :   /**
     106             :    * Base URL of the auditor.
     107             :    */
     108             :   char *auditor_url;
     109             : 
     110             :   /**
     111             :    * Handle to the auditor.
     112             :    */
     113             :   struct TALER_AUDITOR_Handle *ah;
     114             : 
     115             :   /**
     116             :    * Head of DLL of interactions with this auditor.
     117             :    */
     118             :   struct TEAH_AuditorInteractionEntry *ai_head;
     119             : 
     120             :   /**
     121             :    * Tail of DLL of interactions with this auditor.
     122             :    */
     123             :   struct TEAH_AuditorInteractionEntry *ai_tail;
     124             : 
     125             :   /**
     126             :    * Public key of the auditor.
     127             :    */
     128             :   struct TALER_AuditorPublicKeyP auditor_pub;
     129             : 
     130             :   /**
     131             :    * Flag indicating that the auditor is available and that protocol
     132             :    * version compatibility is given.
     133             :    */
     134             :   bool is_up;
     135             : 
     136             : };
     137             : 
     138             : 
     139             : /* ***************** Internal /keys fetching ************* */
     140             : 
     141             : /**
     142             :  * Data for the request to get the /keys of a exchange.
     143             :  */
     144             : struct KeysRequest
     145             : {
     146             :   /**
     147             :    * The connection to exchange this request handle will use
     148             :    */
     149             :   struct TALER_EXCHANGE_Handle *exchange;
     150             : 
     151             :   /**
     152             :    * The url for this handle
     153             :    */
     154             :   char *url;
     155             : 
     156             :   /**
     157             :    * Entry for this request with the `struct GNUNET_CURL_Context`.
     158             :    */
     159             :   struct GNUNET_CURL_Job *job;
     160             : 
     161             :   /**
     162             :    * Expiration time according to "Expire:" header.
     163             :    * 0 if not provided by the server.
     164             :    */
     165             :   struct GNUNET_TIME_Timestamp expire;
     166             : 
     167             : };
     168             : 
     169             : 
     170             : void
     171           0 : TEAH_acc_confirmation_cb (void *cls,
     172             :                           const struct TALER_AUDITOR_HttpResponse *hr)
     173             : {
     174           0 :   struct TEAH_AuditorInteractionEntry *aie = cls;
     175           0 :   struct TEAH_AuditorListEntry *ale = aie->ale;
     176             : 
     177           0 :   if (MHD_HTTP_OK != hr->http_status)
     178             :   {
     179           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     180             :                 "Failed to submit deposit confirmation to auditor `%s' with HTTP status %d (EC: %d). This is acceptable if it does not happen often.\n",
     181             :                 ale->auditor_url,
     182             :                 hr->http_status,
     183             :                 hr->ec);
     184             :   }
     185           0 :   GNUNET_CONTAINER_DLL_remove (ale->ai_head,
     186             :                                ale->ai_tail,
     187             :                                aie);
     188           0 :   GNUNET_free (aie);
     189           0 : }
     190             : 
     191             : 
     192             : void
     193           0 : TEAH_get_auditors_for_dc (struct TALER_EXCHANGE_Handle *h,
     194             :                           TEAH_AuditorCallback ac,
     195             :                           void *ac_cls)
     196             : {
     197           0 :   if (NULL == h->auditors_head)
     198             :   {
     199           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     200             :                 "No auditor available for exchange `%s'. Not submitting deposit confirmations.\n",
     201             :                 h->url);
     202           0 :     return;
     203             :   }
     204           0 :   for (struct TEAH_AuditorListEntry *ale = h->auditors_head;
     205             :        NULL != ale;
     206           0 :        ale = ale->next)
     207             :   {
     208             :     struct TEAH_AuditorInteractionEntry *aie;
     209             : 
     210           0 :     if (! ale->is_up)
     211           0 :       continue;
     212           0 :     aie = ac (ac_cls,
     213             :               ale->ah,
     214           0 :               &ale->auditor_pub);
     215           0 :     if (NULL != aie)
     216             :     {
     217           0 :       aie->ale = ale;
     218           0 :       GNUNET_CONTAINER_DLL_insert (ale->ai_head,
     219             :                                    ale->ai_tail,
     220             :                                    aie);
     221             :     }
     222             :   }
     223             : }
     224             : 
     225             : 
     226             : /**
     227             :  * Release memory occupied by a keys request.  Note that this does not
     228             :  * cancel the request itself.
     229             :  *
     230             :  * @param kr request to free
     231             :  */
     232             : static void
     233           0 : free_keys_request (struct KeysRequest *kr)
     234             : {
     235           0 :   GNUNET_free (kr->url);
     236           0 :   GNUNET_free (kr);
     237           0 : }
     238             : 
     239             : 
     240             : #define EXITIF(cond)                                              \
     241             :   do {                                                            \
     242             :     if (cond) { GNUNET_break (0); goto EXITIF_exit; }             \
     243             :   } while (0)
     244             : 
     245             : 
     246             : /**
     247             :  * Parse a exchange's signing key encoded in JSON.
     248             :  *
     249             :  * @param[out] sign_key where to return the result
     250             :  * @param check_sigs should we check signatures?
     251             :  * @param[in] sign_key_obj json to parse
     252             :  * @param master_key master key to use to verify signature
     253             :  * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
     254             :  *        invalid or the json malformed.
     255             :  */
     256             : static enum GNUNET_GenericReturnValue
     257           0 : parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key,
     258             :                     bool check_sigs,
     259             :                     json_t *sign_key_obj,
     260             :                     const struct TALER_MasterPublicKeyP *master_key)
     261             : {
     262             :   struct TALER_MasterSignatureP sign_key_issue_sig;
     263             :   struct GNUNET_JSON_Specification spec[] = {
     264           0 :     GNUNET_JSON_spec_fixed_auto ("master_sig",
     265             :                                  &sign_key_issue_sig),
     266           0 :     GNUNET_JSON_spec_fixed_auto ("key",
     267             :                                  &sign_key->key),
     268           0 :     GNUNET_JSON_spec_timestamp ("stamp_start",
     269             :                                 &sign_key->valid_from),
     270           0 :     GNUNET_JSON_spec_timestamp ("stamp_expire",
     271             :                                 &sign_key->valid_until),
     272           0 :     GNUNET_JSON_spec_timestamp ("stamp_end",
     273             :                                 &sign_key->valid_legal),
     274           0 :     GNUNET_JSON_spec_end ()
     275             :   };
     276             : 
     277           0 :   if (GNUNET_OK !=
     278           0 :       GNUNET_JSON_parse (sign_key_obj,
     279             :                          spec,
     280             :                          NULL, NULL))
     281             :   {
     282           0 :     GNUNET_break_op (0);
     283           0 :     return GNUNET_SYSERR;
     284             :   }
     285             : 
     286           0 :   if (! check_sigs)
     287           0 :     return GNUNET_OK;
     288           0 :   if (GNUNET_OK !=
     289           0 :       TALER_exchange_offline_signkey_validity_verify (
     290           0 :         &sign_key->key,
     291             :         sign_key->valid_from,
     292             :         sign_key->valid_until,
     293             :         sign_key->valid_legal,
     294             :         master_key,
     295             :         &sign_key_issue_sig))
     296             :   {
     297           0 :     GNUNET_break_op (0);
     298           0 :     return GNUNET_SYSERR;
     299             :   }
     300           0 :   sign_key->master_sig = sign_key_issue_sig;
     301           0 :   return GNUNET_OK;
     302             : }
     303             : 
     304             : 
     305             : /**
     306             :  * Parse a exchange's denomination key encoded in JSON partially.
     307             :  *
     308             :  * Only the values for master_sig, timestamps and the cipher-specific public
     309             :  * key are parsed.  All other fields (fees, age_mask, value) MUST have been set
     310             :  * prior to calling this function, otherwise the signature verification
     311             :  * performed within this function will fail.
     312             :  *
     313             :  * @param[out] denom_key where to return the result
     314             :  * @param cipher cipher type to parse
     315             :  * @param check_sigs should we check signatures?
     316             :  * @param[in] denom_key_obj json to parse
     317             :  * @param master_key master key to use to verify signature
     318             :  * @param hash_xor where to accumulate data for signature verification via XOR
     319             :  * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
     320             :  *        invalid or the json malformed.
     321             :  */
     322             : static enum GNUNET_GenericReturnValue
     323           0 : parse_json_denomkey_partially (
     324             :   struct TALER_EXCHANGE_DenomPublicKey *denom_key,
     325             :   enum TALER_DenominationCipher cipher,
     326             :   bool check_sigs,
     327             :   json_t *denom_key_obj,
     328             :   struct TALER_MasterPublicKeyP *master_key,
     329             :   struct GNUNET_HashCode *hash_xor)
     330             : {
     331             :   struct GNUNET_JSON_Specification spec[] = {
     332           0 :     GNUNET_JSON_spec_fixed_auto ("master_sig",
     333             :                                  &denom_key->master_sig),
     334           0 :     GNUNET_JSON_spec_timestamp ("stamp_expire_deposit",
     335             :                                 &denom_key->expire_deposit),
     336           0 :     GNUNET_JSON_spec_timestamp ("stamp_expire_withdraw",
     337             :                                 &denom_key->withdraw_valid_until),
     338           0 :     GNUNET_JSON_spec_timestamp ("stamp_start",
     339             :                                 &denom_key->valid_from),
     340           0 :     GNUNET_JSON_spec_timestamp ("stamp_expire_legal",
     341             :                                 &denom_key->expire_legal),
     342           0 :     TALER_JSON_spec_denom_pub_cipher (NULL,
     343             :                                       cipher,
     344             :                                       &denom_key->key),
     345           0 :     GNUNET_JSON_spec_end ()
     346             :   };
     347             : 
     348           0 :   if (GNUNET_OK !=
     349           0 :       GNUNET_JSON_parse (denom_key_obj,
     350             :                          spec,
     351             :                          NULL, NULL))
     352             :   {
     353           0 :     GNUNET_break_op (0);
     354           0 :     return GNUNET_SYSERR;
     355             :   }
     356           0 :   TALER_denom_pub_hash (&denom_key->key,
     357             :                         &denom_key->h_key);
     358           0 :   if (NULL != hash_xor)
     359           0 :     GNUNET_CRYPTO_hash_xor (&denom_key->h_key.hash,
     360             :                             hash_xor,
     361             :                             hash_xor);
     362             : 
     363           0 :   if (! check_sigs)
     364           0 :     return GNUNET_OK;
     365           0 :   EXITIF (GNUNET_SYSERR ==
     366             :           TALER_exchange_offline_denom_validity_verify (
     367             :             &denom_key->h_key,
     368             :             denom_key->valid_from,
     369             :             denom_key->withdraw_valid_until,
     370             :             denom_key->expire_deposit,
     371             :             denom_key->expire_legal,
     372             :             &denom_key->value,
     373             :             &denom_key->fees,
     374             :             master_key,
     375             :             &denom_key->master_sig));
     376           0 :   return GNUNET_OK;
     377           0 : EXITIF_exit:
     378             :   /* invalidate denom_key, just to be sure */
     379           0 :   memset (denom_key,
     380             :           0,
     381             :           sizeof (*denom_key));
     382           0 :   GNUNET_JSON_parse_free (spec);
     383           0 :   return GNUNET_SYSERR;
     384             : }
     385             : 
     386             : 
     387             : /**
     388             :  * Parse a exchange's auditor information encoded in JSON.
     389             :  *
     390             :  * @param[out] auditor where to return the result
     391             :  * @param check_sigs should we check signatures
     392             :  * @param[in] auditor_obj json to parse
     393             :  * @param key_data information about denomination keys
     394             :  * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
     395             :  *        invalid or the json malformed.
     396             :  */
     397             : static enum GNUNET_GenericReturnValue
     398           0 : parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,
     399             :                     bool check_sigs,
     400             :                     json_t *auditor_obj,
     401             :                     const struct TALER_EXCHANGE_Keys *key_data)
     402             : {
     403             :   json_t *keys;
     404             :   json_t *key;
     405             :   unsigned int len;
     406             :   unsigned int off;
     407             :   unsigned int i;
     408             :   const char *auditor_url;
     409             :   struct GNUNET_JSON_Specification spec[] = {
     410           0 :     GNUNET_JSON_spec_fixed_auto ("auditor_pub",
     411             :                                  &auditor->auditor_pub),
     412           0 :     GNUNET_JSON_spec_string ("auditor_url",
     413             :                              &auditor_url),
     414           0 :     GNUNET_JSON_spec_json ("denomination_keys",
     415             :                            &keys),
     416           0 :     GNUNET_JSON_spec_end ()
     417             :   };
     418             : 
     419           0 :   if (GNUNET_OK !=
     420           0 :       GNUNET_JSON_parse (auditor_obj,
     421             :                          spec,
     422             :                          NULL, NULL))
     423             :   {
     424           0 :     GNUNET_break_op (0);
     425             : #if DEBUG
     426             :     json_dumpf (auditor_obj,
     427             :                 stderr,
     428             :                 JSON_INDENT (2));
     429             : #endif
     430           0 :     return GNUNET_SYSERR;
     431             :   }
     432           0 :   auditor->auditor_url = GNUNET_strdup (auditor_url);
     433           0 :   len = json_array_size (keys);
     434           0 :   auditor->denom_keys = GNUNET_new_array (len,
     435             :                                           struct
     436             :                                           TALER_EXCHANGE_AuditorDenominationInfo);
     437           0 :   off = 0;
     438           0 :   json_array_foreach (keys, i, key) {
     439             :     struct TALER_AuditorSignatureP auditor_sig;
     440             :     struct TALER_DenominationHashP denom_h;
     441             :     const struct TALER_EXCHANGE_DenomPublicKey *dk;
     442             :     unsigned int dk_off;
     443             :     struct GNUNET_JSON_Specification kspec[] = {
     444           0 :       GNUNET_JSON_spec_fixed_auto ("auditor_sig",
     445             :                                    &auditor_sig),
     446           0 :       GNUNET_JSON_spec_fixed_auto ("denom_pub_h",
     447             :                                    &denom_h),
     448           0 :       GNUNET_JSON_spec_end ()
     449             :     };
     450             : 
     451           0 :     if (GNUNET_OK !=
     452           0 :         GNUNET_JSON_parse (key,
     453             :                            kspec,
     454             :                            NULL, NULL))
     455             :     {
     456           0 :       GNUNET_break_op (0);
     457           0 :       continue;
     458             :     }
     459           0 :     dk = NULL;
     460           0 :     dk_off = UINT_MAX;
     461           0 :     for (unsigned int j = 0; j<key_data->num_denom_keys; j++)
     462             :     {
     463           0 :       if (0 == GNUNET_memcmp (&denom_h,
     464             :                               &key_data->denom_keys[j].h_key))
     465             :       {
     466           0 :         dk = &key_data->denom_keys[j];
     467           0 :         dk_off = j;
     468           0 :         break;
     469             :       }
     470             :     }
     471           0 :     if (NULL == dk)
     472             :     {
     473           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     474             :                   "Auditor signed denomination %s, which we do not know. Ignoring signature.\n",
     475             :                   GNUNET_h2s (&denom_h.hash));
     476           0 :       continue;
     477             :     }
     478           0 :     if (check_sigs)
     479             :     {
     480           0 :       if (GNUNET_OK !=
     481           0 :           TALER_auditor_denom_validity_verify (
     482             :             auditor_url,
     483             :             &dk->h_key,
     484             :             &key_data->master_pub,
     485             :             dk->valid_from,
     486             :             dk->withdraw_valid_until,
     487             :             dk->expire_deposit,
     488             :             dk->expire_legal,
     489             :             &dk->value,
     490             :             &dk->fees,
     491           0 :             &auditor->auditor_pub,
     492             :             &auditor_sig))
     493             :       {
     494           0 :         GNUNET_break_op (0);
     495           0 :         GNUNET_JSON_parse_free (spec);
     496           0 :         return GNUNET_SYSERR;
     497             :       }
     498             :     }
     499           0 :     auditor->denom_keys[off].denom_key_offset = dk_off;
     500           0 :     auditor->denom_keys[off].auditor_sig = auditor_sig;
     501           0 :     off++;
     502             :   }
     503           0 :   auditor->num_denom_keys = off;
     504           0 :   GNUNET_JSON_parse_free (spec);
     505           0 :   return GNUNET_OK;
     506             : }
     507             : 
     508             : 
     509             : /**
     510             :  * Parse a exchange's global fee information encoded in JSON.
     511             :  *
     512             :  * @param[out] gf where to return the result
     513             :  * @param check_sigs should we check signatures
     514             :  * @param[in] fee_obj json to parse
     515             :  * @param key_data already parsed information about the exchange
     516             :  * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
     517             :  *        invalid or the json malformed.
     518             :  */
     519             : static enum GNUNET_GenericReturnValue
     520           0 : parse_global_fee (struct TALER_EXCHANGE_GlobalFee *gf,
     521             :                   bool check_sigs,
     522             :                   json_t *fee_obj,
     523             :                   const struct TALER_EXCHANGE_Keys *key_data)
     524             : {
     525             :   struct GNUNET_JSON_Specification spec[] = {
     526           0 :     GNUNET_JSON_spec_timestamp ("start_date",
     527             :                                 &gf->start_date),
     528           0 :     GNUNET_JSON_spec_timestamp ("end_date",
     529             :                                 &gf->end_date),
     530           0 :     GNUNET_JSON_spec_relative_time ("purse_timeout",
     531             :                                     &gf->purse_timeout),
     532           0 :     GNUNET_JSON_spec_relative_time ("account_kyc_timeout",
     533             :                                     &gf->kyc_timeout),
     534           0 :     GNUNET_JSON_spec_relative_time ("history_expiration",
     535             :                                     &gf->history_expiration),
     536           0 :     GNUNET_JSON_spec_uint32 ("purse_account_limit",
     537             :                              &gf->purse_account_limit),
     538           0 :     TALER_JSON_SPEC_GLOBAL_FEES (key_data->currency,
     539             :                                  &gf->fees),
     540           0 :     GNUNET_JSON_spec_fixed_auto ("master_sig",
     541             :                                  &gf->master_sig),
     542           0 :     GNUNET_JSON_spec_end ()
     543             :   };
     544             : 
     545           0 :   if (GNUNET_OK !=
     546           0 :       GNUNET_JSON_parse (fee_obj,
     547             :                          spec,
     548             :                          NULL, NULL))
     549             :   {
     550           0 :     GNUNET_break_op (0);
     551             : #if DEBUG
     552             :     json_dumpf (fee_obj,
     553             :                 stderr,
     554             :                 JSON_INDENT (2));
     555             : #endif
     556           0 :     return GNUNET_SYSERR;
     557             :   }
     558           0 :   if (check_sigs)
     559             :   {
     560           0 :     if (GNUNET_OK !=
     561           0 :         TALER_exchange_offline_global_fee_verify (
     562             :           gf->start_date,
     563             :           gf->end_date,
     564           0 :           &gf->fees,
     565             :           gf->purse_timeout,
     566             :           gf->kyc_timeout,
     567             :           gf->history_expiration,
     568             :           gf->purse_account_limit,
     569             :           &key_data->master_pub,
     570           0 :           &gf->master_sig))
     571             :     {
     572           0 :       GNUNET_break_op (0);
     573           0 :       GNUNET_JSON_parse_free (spec);
     574           0 :       return GNUNET_SYSERR;
     575             :     }
     576             :   }
     577           0 :   GNUNET_JSON_parse_free (spec);
     578           0 :   return GNUNET_OK;
     579             : }
     580             : 
     581             : 
     582             : /**
     583             :  * Function called with information about the auditor.  Marks an
     584             :  * auditor as 'up'.
     585             :  *
     586             :  * @param cls closure, a `struct TEAH_AuditorListEntry *`
     587             :  * @param hr http response from the auditor
     588             :  * @param vi basic information about the auditor
     589             :  * @param compat protocol compatibility information
     590             :  */
     591             : static void
     592           0 : auditor_version_cb (
     593             :   void *cls,
     594             :   const struct TALER_AUDITOR_HttpResponse *hr,
     595             :   const struct TALER_AUDITOR_VersionInformation *vi,
     596             :   enum TALER_AUDITOR_VersionCompatibility compat)
     597             : {
     598           0 :   struct TEAH_AuditorListEntry *ale = cls;
     599             : 
     600             :   (void) hr;
     601           0 :   if (NULL == vi)
     602             :   {
     603             :     /* In this case, we don't mark the auditor as 'up' */
     604           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     605             :                 "Auditor `%s' gave unexpected version response.\n",
     606             :                 ale->auditor_url);
     607           0 :     return;
     608             :   }
     609             : 
     610           0 :   if (0 != (TALER_AUDITOR_VC_INCOMPATIBLE & compat))
     611             :   {
     612           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     613             :                 "Auditor `%s' runs incompatible protocol version!\n",
     614             :                 ale->auditor_url);
     615           0 :     if (0 != (TALER_AUDITOR_VC_OLDER & compat))
     616             :     {
     617           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     618             :                   "Auditor `%s' runs outdated protocol version!\n",
     619             :                   ale->auditor_url);
     620             :     }
     621           0 :     if (0 != (TALER_AUDITOR_VC_NEWER & compat))
     622             :     {
     623           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     624             :                   "Auditor `%s' runs more recent incompatible version. We should upgrade!\n",
     625             :                   ale->auditor_url);
     626             :     }
     627           0 :     return;
     628             :   }
     629           0 :   ale->is_up = true;
     630             : }
     631             : 
     632             : 
     633             : /**
     634             :  * Recalculate our auditor list, we got /keys and it may have
     635             :  * changed.
     636             :  *
     637             :  * @param exchange exchange for which to update the list.
     638             :  */
     639             : static void
     640           0 : update_auditors (struct TALER_EXCHANGE_Handle *exchange)
     641             : {
     642           0 :   struct TALER_EXCHANGE_Keys *kd = &exchange->key_data;
     643             : 
     644           0 :   TALER_LOG_DEBUG ("Updating auditors\n");
     645           0 :   for (unsigned int i = 0; i<kd->num_auditors; i++)
     646             :   {
     647             :     /* Compare auditor data from /keys with auditor data
     648             :      * from owned exchange structures.  */
     649           0 :     struct TALER_EXCHANGE_AuditorInformation *auditor = &kd->auditors[i];
     650           0 :     struct TEAH_AuditorListEntry *ale = NULL;
     651             : 
     652           0 :     for (struct TEAH_AuditorListEntry *a = exchange->auditors_head;
     653             :          NULL != a;
     654           0 :          a = a->next)
     655             :     {
     656           0 :       if (0 == GNUNET_memcmp (&auditor->auditor_pub,
     657             :                               &a->auditor_pub))
     658             :       {
     659           0 :         ale = a;
     660           0 :         break;
     661             :       }
     662             :     }
     663           0 :     if (NULL != ale)
     664           0 :       continue; /* found, no need to add */
     665             : 
     666             :     /* new auditor, add */
     667           0 :     TALER_LOG_DEBUG ("Found new auditor %s!\n",
     668             :                      auditor->auditor_url);
     669           0 :     ale = GNUNET_new (struct TEAH_AuditorListEntry);
     670           0 :     ale->auditor_pub = auditor->auditor_pub;
     671           0 :     ale->auditor_url = GNUNET_strdup (auditor->auditor_url);
     672           0 :     GNUNET_CONTAINER_DLL_insert (exchange->auditors_head,
     673             :                                  exchange->auditors_tail,
     674             :                                  ale);
     675           0 :     ale->ah = TALER_AUDITOR_connect (exchange->ctx,
     676           0 :                                      ale->auditor_url,
     677             :                                      &auditor_version_cb,
     678             :                                      ale);
     679             :   }
     680           0 : }
     681             : 
     682             : 
     683             : /**
     684             :  * Compare two denomination keys.  Ignores revocation data.
     685             :  *
     686             :  * @param denom1 first denomination key
     687             :  * @param denom2 second denomination key
     688             :  * @return 0 if the two keys are equal (not necessarily
     689             :  *  the same object), 1 otherwise.
     690             :  */
     691             : static unsigned int
     692           0 : denoms_cmp (const struct TALER_EXCHANGE_DenomPublicKey *denom1,
     693             :             const struct TALER_EXCHANGE_DenomPublicKey *denom2)
     694             : {
     695             :   struct TALER_EXCHANGE_DenomPublicKey tmp1;
     696             :   struct TALER_EXCHANGE_DenomPublicKey tmp2;
     697             : 
     698           0 :   if (0 !=
     699           0 :       TALER_denom_pub_cmp (&denom1->key,
     700             :                            &denom2->key))
     701           0 :     return 1;
     702           0 :   tmp1 = *denom1;
     703           0 :   tmp2 = *denom2;
     704           0 :   tmp1.revoked = false;
     705           0 :   tmp2.revoked = false;
     706           0 :   memset (&tmp1.key,
     707             :           0,
     708             :           sizeof (tmp1.key));
     709           0 :   memset (&tmp2.key,
     710             :           0,
     711             :           sizeof (tmp2.key));
     712           0 :   return GNUNET_memcmp (&tmp1,
     713             :                         &tmp2);
     714             : }
     715             : 
     716             : 
     717             : /**
     718             :  * Decode the JSON in @a resp_obj from the /keys response
     719             :  * and store the data in the @a key_data.
     720             :  *
     721             :  * @param[in] resp_obj JSON object to parse
     722             :  * @param check_sig true if we should check the signature
     723             :  * @param[out] key_data where to store the results we decoded
     724             :  * @param[out] vc where to store version compatibility data
     725             :  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
     726             :  * (malformed JSON)
     727             :  */
     728             : static enum GNUNET_GenericReturnValue
     729           0 : decode_keys_json (const json_t *resp_obj,
     730             :                   bool check_sig,
     731             :                   struct TALER_EXCHANGE_Keys *key_data,
     732             :                   enum TALER_EXCHANGE_VersionCompatibility *vc)
     733             : {
     734             :   struct TALER_ExchangeSignatureP denominations_sig;
     735           0 :   struct GNUNET_HashCode hash_xor = {0};
     736             :   struct TALER_ExchangePublicKeyP pub;
     737             :   const char *currency;
     738           0 :   json_t *wblwk = NULL;
     739             :   struct GNUNET_JSON_Specification mspec[] = {
     740           0 :     GNUNET_JSON_spec_fixed_auto ("denominations_sig",
     741             :                                  &denominations_sig),
     742           0 :     GNUNET_JSON_spec_fixed_auto ("eddsa_pub",
     743             :                                  &pub),
     744           0 :     GNUNET_JSON_spec_fixed_auto ("master_public_key",
     745             :                                  &key_data->master_pub),
     746           0 :     GNUNET_JSON_spec_timestamp ("list_issue_date",
     747             :                                 &key_data->list_issue_date),
     748           0 :     GNUNET_JSON_spec_relative_time ("reserve_closing_delay",
     749             :                                     &key_data->reserve_closing_delay),
     750           0 :     GNUNET_JSON_spec_string ("currency",
     751             :                              &currency),
     752           0 :     GNUNET_JSON_spec_mark_optional (
     753             :       GNUNET_JSON_spec_json ("wallet_balance_limit_without_kyc",
     754             :                              &wblwk),
     755             :       NULL),
     756           0 :     GNUNET_JSON_spec_end ()
     757             :   };
     758             : 
     759           0 :   if (JSON_OBJECT != json_typeof (resp_obj))
     760             :   {
     761           0 :     GNUNET_break_op (0);
     762           0 :     return GNUNET_SYSERR;
     763             :   }
     764             : #if DEBUG
     765             :   json_dumpf (resp_obj,
     766             :               stderr,
     767             :               JSON_INDENT (2));
     768             : #endif
     769             :   /* check the version first */
     770             :   {
     771             :     const char *ver;
     772             :     unsigned int age;
     773             :     unsigned int revision;
     774             :     unsigned int current;
     775             :     char dummy;
     776             :     struct GNUNET_JSON_Specification spec[] = {
     777           0 :       GNUNET_JSON_spec_string ("version",
     778             :                                &ver),
     779           0 :       GNUNET_JSON_spec_end ()
     780             :     };
     781             : 
     782           0 :     if (GNUNET_OK !=
     783           0 :         GNUNET_JSON_parse (resp_obj,
     784             :                            spec,
     785             :                            NULL, NULL))
     786             :     {
     787           0 :       GNUNET_break_op (0);
     788           0 :       return GNUNET_SYSERR;
     789             :     }
     790           0 :     if (3 != sscanf (ver,
     791             :                      "%u:%u:%u%c",
     792             :                      &current,
     793             :                      &revision,
     794             :                      &age,
     795             :                      &dummy))
     796             :     {
     797           0 :       GNUNET_break_op (0);
     798           0 :       return GNUNET_SYSERR;
     799             :     }
     800           0 :     *vc = TALER_EXCHANGE_VC_MATCH;
     801           0 :     if (EXCHANGE_PROTOCOL_CURRENT < current)
     802             :     {
     803           0 :       *vc |= TALER_EXCHANGE_VC_NEWER;
     804           0 :       if (EXCHANGE_PROTOCOL_CURRENT < current - age)
     805           0 :         *vc |= TALER_EXCHANGE_VC_INCOMPATIBLE;
     806             :     }
     807           0 :     if (EXCHANGE_PROTOCOL_CURRENT > current)
     808             :     {
     809           0 :       *vc |= TALER_EXCHANGE_VC_OLDER;
     810           0 :       if (EXCHANGE_PROTOCOL_CURRENT - EXCHANGE_PROTOCOL_AGE > current)
     811           0 :         *vc |= TALER_EXCHANGE_VC_INCOMPATIBLE;
     812             :     }
     813           0 :     key_data->version = GNUNET_strdup (ver);
     814             :   }
     815             : 
     816           0 :   EXITIF (GNUNET_OK !=
     817             :           GNUNET_JSON_parse (resp_obj,
     818             :                              (check_sig) ? mspec : &mspec[2],
     819             :                              NULL, NULL));
     820           0 :   key_data->currency = GNUNET_strdup (currency);
     821             : 
     822             :   /* parse the global fees */
     823             :   {
     824             :     json_t *global_fees;
     825             :     json_t *global_fee;
     826             :     unsigned int index;
     827             : 
     828           0 :     EXITIF (NULL == (global_fees =
     829             :                        json_object_get (resp_obj,
     830             :                                         "global_fees")));
     831           0 :     EXITIF (! json_is_array (global_fees));
     832           0 :     if (0 != (key_data->num_global_fees =
     833           0 :                 json_array_size (global_fees)))
     834             :     {
     835             :       key_data->global_fees
     836           0 :         = GNUNET_new_array (key_data->num_global_fees,
     837             :                             struct TALER_EXCHANGE_GlobalFee);
     838           0 :       json_array_foreach (global_fees, index, global_fee) {
     839           0 :         EXITIF (GNUNET_SYSERR ==
     840             :                 parse_global_fee (&key_data->global_fees[index],
     841             :                                   check_sig,
     842             :                                   global_fee,
     843             :                                   key_data));
     844             :       }
     845             :     }
     846             :   }
     847             : 
     848             :   /* parse the signing keys */
     849             :   {
     850             :     json_t *sign_keys_array;
     851             :     json_t *sign_key_obj;
     852             :     unsigned int index;
     853             : 
     854           0 :     EXITIF (NULL == (sign_keys_array =
     855             :                        json_object_get (resp_obj,
     856             :                                         "signkeys")));
     857           0 :     EXITIF (! json_is_array (sign_keys_array));
     858           0 :     if (0 != (key_data->num_sign_keys =
     859           0 :                 json_array_size (sign_keys_array)))
     860             :     {
     861             :       key_data->sign_keys
     862           0 :         = GNUNET_new_array (key_data->num_sign_keys,
     863             :                             struct TALER_EXCHANGE_SigningPublicKey);
     864           0 :       json_array_foreach (sign_keys_array, index, sign_key_obj) {
     865           0 :         EXITIF (GNUNET_SYSERR ==
     866             :                 parse_json_signkey (&key_data->sign_keys[index],
     867             :                                     check_sig,
     868             :                                     sign_key_obj,
     869             :                                     &key_data->master_pub));
     870             :       }
     871             :     }
     872             :   }
     873             : 
     874             :   /* Parse balance limits */
     875           0 :   if (NULL != wblwk)
     876             :   {
     877           0 :     key_data->wblwk_length = json_array_size (wblwk);
     878             :     key_data->wallet_balance_limit_without_kyc
     879           0 :       = GNUNET_new_array (key_data->wblwk_length,
     880             :                           struct TALER_Amount);
     881           0 :     for (unsigned int i = 0; i<key_data->wblwk_length; i++)
     882             :     {
     883           0 :       struct TALER_Amount *a = &key_data->wallet_balance_limit_without_kyc[i];
     884           0 :       const json_t *aj = json_array_get (wblwk,
     885             :                                          i);
     886             :       struct GNUNET_JSON_Specification spec[] = {
     887           0 :         TALER_JSON_spec_amount (NULL,
     888             :                                 currency,
     889             :                                 a),
     890           0 :         GNUNET_JSON_spec_end ()
     891             :       };
     892             : 
     893           0 :       EXITIF (GNUNET_OK !=
     894             :               GNUNET_JSON_parse (aj,
     895             :                                  spec,
     896             :                                  NULL, NULL));
     897             :     }
     898             :   }
     899             : 
     900             :   /* Parse the supported extension(s): age-restriction. */
     901             :   /* TODO: maybe lift all this into a FP in TALER_Extension ? */
     902             :   {
     903           0 :     struct TALER_MasterSignatureP extensions_sig = {0};
     904           0 :     json_t *extensions = NULL;
     905             :     struct GNUNET_JSON_Specification ext_spec[] = {
     906           0 :       GNUNET_JSON_spec_mark_optional (
     907             :         GNUNET_JSON_spec_json ("extensions",
     908             :                                &extensions),
     909             :         NULL),
     910           0 :       GNUNET_JSON_spec_mark_optional (
     911             :         GNUNET_JSON_spec_fixed_auto (
     912             :           "extensions_sig",
     913             :           &extensions_sig),
     914             :         NULL),
     915           0 :       GNUNET_JSON_spec_end ()
     916             :     };
     917             : 
     918             :     /* 1. Search for extensions in the response to /keys */
     919           0 :     EXITIF (GNUNET_OK !=
     920             :             GNUNET_JSON_parse (resp_obj,
     921             :                                ext_spec,
     922             :                                NULL, NULL));
     923             : 
     924           0 :     if (NULL != extensions)
     925             :     {
     926             :       /* 2. We have an extensions object. Verify its signature. */
     927           0 :       EXITIF (GNUNET_OK !=
     928             :               TALER_extensions_verify_json_config_signature (
     929             :                 extensions,
     930             :                 &extensions_sig,
     931             :                 &key_data->master_pub));
     932             : 
     933             :       /* 3. Parse and set the the configuration of the extensions accordingly */
     934           0 :       EXITIF (GNUNET_OK !=
     935             :               TALER_extensions_load_json_config (extensions));
     936             :     }
     937             : 
     938             :     /* 4. assuming we might have now a new value for age_mask, set it in key_data */
     939           0 :     key_data->age_mask = TALER_extensions_age_restriction_ageMask ();
     940             :   }
     941             : 
     942             :   /**
     943             :    * Parse the denomination keys, merging with the
     944             :    * possibly EXISTING array as required (/keys cherry picking).
     945             :    *
     946             :    * The denominations are grouped by common values of
     947             :    *    {cipher, value, fee, age_mask}.
     948             :    **/
     949             :   {
     950             :     json_t *denominations_by_group;
     951             :     json_t *group_obj;
     952             :     unsigned int group_idx;
     953             : 
     954             :     denominations_by_group =
     955           0 :       json_object_get (
     956             :         resp_obj,
     957             :         "denominations");
     958             : 
     959           0 :     EXITIF (JSON_ARRAY !=
     960             :             json_typeof (denominations_by_group));
     961             : 
     962           0 :     json_array_foreach (denominations_by_group, group_idx, group_obj) {
     963             :       /* Running XOR of each SHA512 hash of the denominations' public key in
     964             :          this group.  Used to compare against group.hash after all keys have
     965             :          been parsed. */
     966           0 :       struct GNUNET_HashCode group_hash_xor = {0};
     967             : 
     968             :       /* First, parse { cipher, fees, value, age_mask, hash } of the current
     969             :          group. */
     970           0 :       struct TALER_DenominationGroup group = {0};
     971             :       struct GNUNET_JSON_Specification group_spec[] = {
     972           0 :         TALER_JSON_spec_denomination_group (NULL,
     973             :                                             currency, &group),
     974           0 :         GNUNET_JSON_spec_end ()
     975             :       };
     976           0 :       EXITIF (GNUNET_SYSERR ==
     977             :               GNUNET_JSON_parse (group_obj,
     978             :                                  group_spec,
     979             :                                  NULL,
     980             :                                  NULL));
     981             : 
     982             :       /* Now, parse the individual denominations */
     983             :       {
     984             :         json_t *denom_keys_array;
     985             :         json_t *denom_key_obj;
     986             :         unsigned int index;
     987           0 :         denom_keys_array = json_object_get (group_obj, "denoms");
     988           0 :         EXITIF (JSON_ARRAY != json_typeof (denom_keys_array));
     989             : 
     990           0 :         json_array_foreach (denom_keys_array, index, denom_key_obj) {
     991           0 :           struct TALER_EXCHANGE_DenomPublicKey dk = {0};
     992           0 :           bool found = false;
     993             : 
     994           0 :           memset (&dk, 0, sizeof (dk));
     995             : 
     996             :           /* Set the common fields from the group for this particular
     997             :              denomination.  Required to make the validity check inside
     998             :              parse_json_denomkey_partially pass */
     999           0 :           dk.key.cipher = group.cipher;
    1000           0 :           dk.value = group.value;
    1001           0 :           dk.fees = group.fees;
    1002           0 :           dk.key.age_mask = group.age_mask;
    1003             : 
    1004           0 :           EXITIF (GNUNET_SYSERR ==
    1005             :                   parse_json_denomkey_partially (&dk,
    1006             :                                                  group.cipher,
    1007             :                                                  check_sig,
    1008             :                                                  denom_key_obj,
    1009             :                                                  &key_data->master_pub,
    1010             :                                                  check_sig ? &hash_xor : NULL));
    1011             : 
    1012             :           /* Build the running xor of the SHA512-hash of the public keys */
    1013             :           {
    1014           0 :             struct TALER_DenominationHashP hc = {0};
    1015           0 :             TALER_denom_pub_hash (&dk.key, &hc);
    1016           0 :             GNUNET_CRYPTO_hash_xor (&hc.hash,
    1017             :                                     &group_hash_xor,
    1018             :                                     &group_hash_xor);
    1019             :           }
    1020             : 
    1021           0 :           for (unsigned int j = 0;
    1022           0 :                j<key_data->num_denom_keys;
    1023           0 :                j++)
    1024             :           {
    1025           0 :             if (0 == denoms_cmp (&dk,
    1026           0 :                                  &key_data->denom_keys[j]))
    1027             :             {
    1028           0 :               found = true;
    1029           0 :               break;
    1030             :             }
    1031             :           }
    1032             : 
    1033           0 :           if (found)
    1034             :           {
    1035             :             /* 0:0:0 did not support /keys cherry picking */
    1036           0 :             TALER_LOG_DEBUG ("Skipping denomination key: already know it\n");
    1037           0 :             TALER_denom_pub_free (&dk.key);
    1038           0 :             continue;
    1039             :           }
    1040             : 
    1041           0 :           if (key_data->denom_keys_size == key_data->num_denom_keys)
    1042           0 :             GNUNET_array_grow (key_data->denom_keys,
    1043             :                                key_data->denom_keys_size,
    1044             :                                key_data->denom_keys_size * 2 + 2);
    1045           0 :           key_data->denom_keys[key_data->num_denom_keys++] = dk;
    1046             : 
    1047             :           /* Update "last_denom_issue_date" */
    1048           0 :           TALER_LOG_DEBUG ("Adding denomination key that is valid_until %s\n",
    1049             :                            GNUNET_TIME_timestamp2s (dk.valid_from));
    1050             :           key_data->last_denom_issue_date
    1051           0 :             = GNUNET_TIME_timestamp_max (key_data->last_denom_issue_date,
    1052             :                                          dk.valid_from);
    1053             :         }; // json_array_foreach over denominations
    1054             : 
    1055             :         // The calculated group_hash_xor must be the same as group.hash from
    1056             :         // the json.
    1057           0 :         EXITIF (0 !=
    1058             :                 GNUNET_CRYPTO_hash_cmp (&group_hash_xor, &group.hash));
    1059             : 
    1060             :       } // block for parsing individual denominations
    1061             :     }; // json_array_foreach over groups of denominations
    1062             :   }
    1063             : 
    1064             :   /* parse the auditor information */
    1065             :   {
    1066             :     json_t *auditors_array;
    1067             :     json_t *auditor_info;
    1068             :     unsigned int index;
    1069             : 
    1070           0 :     EXITIF (NULL == (auditors_array =
    1071             :                        json_object_get (resp_obj,
    1072             :                                         "auditors")));
    1073           0 :     EXITIF (JSON_ARRAY != json_typeof (auditors_array));
    1074             : 
    1075             :     /* Merge with the existing auditor information we have (/keys cherry picking) */
    1076           0 :     json_array_foreach (auditors_array, index, auditor_info) {
    1077             :       struct TALER_EXCHANGE_AuditorInformation ai;
    1078           0 :       bool found = false;
    1079             : 
    1080           0 :       memset (&ai,
    1081             :               0,
    1082             :               sizeof (ai));
    1083           0 :       EXITIF (GNUNET_SYSERR ==
    1084             :               parse_json_auditor (&ai,
    1085             :                                   check_sig,
    1086             :                                   auditor_info,
    1087             :                                   key_data));
    1088           0 :       for (unsigned int j = 0; j<key_data->num_auditors; j++)
    1089             :       {
    1090           0 :         struct TALER_EXCHANGE_AuditorInformation *aix = &key_data->auditors[j];
    1091             : 
    1092           0 :         if (0 == GNUNET_memcmp (&ai.auditor_pub,
    1093             :                                 &aix->auditor_pub))
    1094             :         {
    1095           0 :           found = true;
    1096             :           /* Merge denomination key signatures of downloaded /keys into existing
    1097             :              auditor information 'aix'. */
    1098           0 :           TALER_LOG_DEBUG (
    1099             :             "Merging %u new audited keys with %u known audited keys\n",
    1100             :             aix->num_denom_keys,
    1101             :             ai.num_denom_keys);
    1102           0 :           for (unsigned int i = 0; i<ai.num_denom_keys; i++)
    1103             :           {
    1104           0 :             bool kfound = false;
    1105             : 
    1106           0 :             for (unsigned int k = 0; k<aix->num_denom_keys; k++)
    1107             :             {
    1108           0 :               if (aix->denom_keys[k].denom_key_offset ==
    1109           0 :                   ai.denom_keys[i].denom_key_offset)
    1110             :               {
    1111           0 :                 kfound = true;
    1112           0 :                 break;
    1113             :               }
    1114             :             }
    1115           0 :             if (! kfound)
    1116           0 :               GNUNET_array_append (aix->denom_keys,
    1117             :                                    aix->num_denom_keys,
    1118             :                                    ai.denom_keys[i]);
    1119             :           }
    1120           0 :           break;
    1121             :         }
    1122             :       }
    1123           0 :       if (found)
    1124             :       {
    1125           0 :         GNUNET_array_grow (ai.denom_keys,
    1126             :                            ai.num_denom_keys,
    1127             :                            0);
    1128           0 :         GNUNET_free (ai.auditor_url);
    1129           0 :         continue; /* we are done */
    1130             :       }
    1131           0 :       if (key_data->auditors_size == key_data->num_auditors)
    1132           0 :         GNUNET_array_grow (key_data->auditors,
    1133             :                            key_data->auditors_size,
    1134             :                            key_data->auditors_size * 2 + 2);
    1135           0 :       GNUNET_assert (NULL != ai.auditor_url);
    1136           0 :       key_data->auditors[key_data->num_auditors++] = ai;
    1137             :     };
    1138             :   }
    1139             : 
    1140             :   /* parse the revocation/recoup information */
    1141             :   {
    1142             :     json_t *recoup_array;
    1143             :     json_t *recoup_info;
    1144             :     unsigned int index;
    1145             : 
    1146           0 :     if (NULL != (recoup_array =
    1147           0 :                    json_object_get (resp_obj,
    1148             :                                     "recoup")))
    1149             :     {
    1150           0 :       EXITIF (JSON_ARRAY != json_typeof (recoup_array));
    1151             : 
    1152           0 :       json_array_foreach (recoup_array, index, recoup_info) {
    1153             :         struct TALER_DenominationHashP h_denom_pub;
    1154             :         struct GNUNET_JSON_Specification spec[] = {
    1155           0 :           GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
    1156             :                                        &h_denom_pub),
    1157           0 :           GNUNET_JSON_spec_end ()
    1158             :         };
    1159             : 
    1160           0 :         EXITIF (GNUNET_OK !=
    1161             :                 GNUNET_JSON_parse (recoup_info,
    1162             :                                    spec,
    1163             :                                    NULL, NULL));
    1164           0 :         for (unsigned int j = 0;
    1165           0 :              j<key_data->num_denom_keys;
    1166           0 :              j++)
    1167             :         {
    1168           0 :           if (0 == GNUNET_memcmp (&h_denom_pub,
    1169             :                                   &key_data->denom_keys[j].h_key))
    1170             :           {
    1171           0 :             key_data->denom_keys[j].revoked = GNUNET_YES;
    1172           0 :             break;
    1173             :           }
    1174             :         }
    1175             :       };
    1176             :     }
    1177             :   }
    1178             : 
    1179           0 :   if (check_sig)
    1180             :   {
    1181           0 :     EXITIF (GNUNET_OK !=
    1182             :             TALER_EXCHANGE_test_signing_key (key_data,
    1183             :                                              &pub));
    1184             : 
    1185           0 :     EXITIF (GNUNET_OK !=
    1186             :             TALER_exchange_online_key_set_verify (
    1187             :               key_data->list_issue_date,
    1188             :               &hash_xor,
    1189             :               &pub,
    1190             :               &denominations_sig));
    1191             :   }
    1192             : 
    1193           0 :   return GNUNET_OK;
    1194             : 
    1195           0 : EXITIF_exit:
    1196           0 :   *vc = TALER_EXCHANGE_VC_PROTOCOL_ERROR;
    1197           0 :   return GNUNET_SYSERR;
    1198             : }
    1199             : 
    1200             : 
    1201             : /**
    1202             :  * Free key data object.
    1203             :  *
    1204             :  * @param key_data data to free (pointer itself excluded)
    1205             :  */
    1206             : static void
    1207           0 : free_key_data (struct TALER_EXCHANGE_Keys *key_data)
    1208             : {
    1209           0 :   GNUNET_array_grow (key_data->sign_keys,
    1210             :                      key_data->num_sign_keys,
    1211             :                      0);
    1212           0 :   for (unsigned int i = 0; i<key_data->num_denom_keys; i++)
    1213           0 :     TALER_denom_pub_free (&key_data->denom_keys[i].key);
    1214             : 
    1215           0 :   GNUNET_array_grow (key_data->denom_keys,
    1216             :                      key_data->denom_keys_size,
    1217             :                      0);
    1218           0 :   for (unsigned int i = 0; i<key_data->num_auditors; i++)
    1219             :   {
    1220           0 :     GNUNET_array_grow (key_data->auditors[i].denom_keys,
    1221             :                        key_data->auditors[i].num_denom_keys,
    1222             :                        0);
    1223           0 :     GNUNET_free (key_data->auditors[i].auditor_url);
    1224             :   }
    1225           0 :   GNUNET_array_grow (key_data->auditors,
    1226             :                      key_data->auditors_size,
    1227             :                      0);
    1228           0 :   GNUNET_free (key_data->wallet_balance_limit_without_kyc);
    1229           0 :   GNUNET_free (key_data->version);
    1230           0 :   GNUNET_free (key_data->currency);
    1231           0 :   GNUNET_free (key_data->global_fees);
    1232           0 : }
    1233             : 
    1234             : 
    1235             : /**
    1236             :  * Initiate download of /keys from the exchange.
    1237             :  *
    1238             :  * @param cls exchange where to download /keys from
    1239             :  */
    1240             : static void
    1241             : request_keys (void *cls);
    1242             : 
    1243             : 
    1244             : void
    1245           0 : TALER_EXCHANGE_set_last_denom (struct TALER_EXCHANGE_Handle *exchange,
    1246             :                                struct GNUNET_TIME_Timestamp last_denom_new)
    1247             : {
    1248           0 :   TALER_LOG_DEBUG (
    1249             :     "Application explicitly set last denomination validity to %s\n",
    1250             :     GNUNET_TIME_timestamp2s (last_denom_new));
    1251           0 :   exchange->key_data.last_denom_issue_date = last_denom_new;
    1252           0 : }
    1253             : 
    1254             : 
    1255             : struct GNUNET_TIME_Timestamp
    1256           0 : TALER_EXCHANGE_check_keys_current (struct TALER_EXCHANGE_Handle *exchange,
    1257             :                                    enum TALER_EXCHANGE_CheckKeysFlags flags)
    1258             : {
    1259           0 :   bool force_download = 0 != (flags & TALER_EXCHANGE_CKF_FORCE_DOWNLOAD);
    1260           0 :   bool pull_all_keys = 0 != (flags & TALER_EXCHANGE_CKF_PULL_ALL_KEYS);
    1261             : 
    1262           0 :   if (NULL != exchange->kr)
    1263           0 :     return GNUNET_TIME_UNIT_ZERO_TS;
    1264             : 
    1265           0 :   if (pull_all_keys)
    1266             :   {
    1267           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1268             :                 "Forcing re-download of all exchange keys\n");
    1269           0 :     GNUNET_break (GNUNET_YES == force_download);
    1270           0 :     exchange->state = MHS_INIT;
    1271             :   }
    1272           0 :   if ( (! force_download) &&
    1273           0 :        (GNUNET_TIME_absolute_is_future (
    1274             :           exchange->key_data_expiration.abs_time)) )
    1275           0 :     return exchange->key_data_expiration;
    1276           0 :   if (NULL == exchange->retry_task)
    1277           0 :     exchange->retry_task = GNUNET_SCHEDULER_add_now (&request_keys,
    1278             :                                                      exchange);
    1279           0 :   return GNUNET_TIME_UNIT_ZERO_TS;
    1280             : }
    1281             : 
    1282             : 
    1283             : /**
    1284             :  * Callback used when downloading the reply to a /keys request
    1285             :  * is complete.
    1286             :  *
    1287             :  * @param cls the `struct KeysRequest`
    1288             :  * @param response_code HTTP response code, 0 on error
    1289             :  * @param resp_obj parsed JSON result, NULL on error
    1290             :  */
    1291             : static void
    1292           0 : keys_completed_cb (void *cls,
    1293             :                    long response_code,
    1294             :                    const void *resp_obj)
    1295             : {
    1296           0 :   struct KeysRequest *kr = cls;
    1297           0 :   struct TALER_EXCHANGE_Handle *exchange = kr->exchange;
    1298             :   struct TALER_EXCHANGE_Keys kd;
    1299             :   struct TALER_EXCHANGE_Keys kd_old;
    1300             :   enum TALER_EXCHANGE_VersionCompatibility vc;
    1301           0 :   const json_t *j = resp_obj;
    1302           0 :   struct TALER_EXCHANGE_HttpResponse hr = {
    1303             :     .reply = j,
    1304           0 :     .http_status = (unsigned int) response_code
    1305             :   };
    1306             : 
    1307           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1308             :               "Received keys from URL `%s' with status %ld and expiration %s.\n",
    1309             :               kr->url,
    1310             :               response_code,
    1311             :               GNUNET_TIME_timestamp2s (kr->expire));
    1312           0 :   if (GNUNET_TIME_absolute_is_past (kr->expire.abs_time))
    1313             :   {
    1314           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1315             :                 "Exchange failed to give expiration time, assuming in %s\n",
    1316             :                 GNUNET_TIME_relative2s (DEFAULT_EXPIRATION,
    1317             :                                         true));
    1318             :     kr->expire
    1319           0 :       = GNUNET_TIME_absolute_to_timestamp (
    1320             :           GNUNET_TIME_relative_to_absolute (DEFAULT_EXPIRATION));
    1321             :   }
    1322           0 :   kd_old = exchange->key_data;
    1323           0 :   memset (&kd,
    1324             :           0,
    1325             :           sizeof (struct TALER_EXCHANGE_Keys));
    1326           0 :   vc = TALER_EXCHANGE_VC_PROTOCOL_ERROR;
    1327           0 :   switch (response_code)
    1328             :   {
    1329           0 :   case 0:
    1330           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1331             :                 "Failed to receive /keys response from exchange %s\n",
    1332             :                 exchange->url);
    1333           0 :     free_keys_request (kr);
    1334           0 :     exchange->keys_error_count++;
    1335           0 :     exchange->kr = NULL;
    1336           0 :     GNUNET_assert (NULL == exchange->retry_task);
    1337           0 :     exchange->retry_delay = EXCHANGE_LIB_BACKOFF (exchange->retry_delay);
    1338           0 :     exchange->retry_task = GNUNET_SCHEDULER_add_delayed (exchange->retry_delay,
    1339             :                                                          &request_keys,
    1340             :                                                          exchange);
    1341           0 :     return;
    1342           0 :   case MHD_HTTP_OK:
    1343           0 :     exchange->keys_error_count = 0;
    1344           0 :     if (NULL == j)
    1345             :     {
    1346           0 :       response_code = 0;
    1347           0 :       break;
    1348             :     }
    1349             :     /* We keep the denomination keys and auditor signatures from the
    1350             :        previous iteration (/keys cherry picking) */
    1351           0 :     kd.num_denom_keys = kd_old.num_denom_keys;
    1352           0 :     kd.last_denom_issue_date = kd_old.last_denom_issue_date;
    1353           0 :     GNUNET_array_grow (kd.denom_keys,
    1354             :                        kd.denom_keys_size,
    1355             :                        kd.num_denom_keys);
    1356             : 
    1357             :     /* First make a shallow copy, we then need another pass for the RSA key... */
    1358           0 :     memcpy (kd.denom_keys,
    1359           0 :             kd_old.denom_keys,
    1360           0 :             kd_old.num_denom_keys * sizeof (struct
    1361             :                                             TALER_EXCHANGE_DenomPublicKey));
    1362             : 
    1363           0 :     for (unsigned int i = 0; i<kd_old.num_denom_keys; i++)
    1364           0 :       TALER_denom_pub_deep_copy (&kd.denom_keys[i].key,
    1365           0 :                                  &kd_old.denom_keys[i].key);
    1366             : 
    1367           0 :     kd.num_auditors = kd_old.num_auditors;
    1368           0 :     kd.auditors = GNUNET_new_array (kd.num_auditors,
    1369             :                                     struct TALER_EXCHANGE_AuditorInformation);
    1370             :     /* Now the necessary deep copy... */
    1371           0 :     for (unsigned int i = 0; i<kd_old.num_auditors; i++)
    1372             :     {
    1373           0 :       const struct TALER_EXCHANGE_AuditorInformation *aold =
    1374           0 :         &kd_old.auditors[i];
    1375           0 :       struct TALER_EXCHANGE_AuditorInformation *anew = &kd.auditors[i];
    1376             : 
    1377           0 :       anew->auditor_pub = aold->auditor_pub;
    1378           0 :       GNUNET_assert (NULL != aold->auditor_url);
    1379           0 :       anew->auditor_url = GNUNET_strdup (aold->auditor_url);
    1380           0 :       GNUNET_array_grow (anew->denom_keys,
    1381             :                          anew->num_denom_keys,
    1382             :                          aold->num_denom_keys);
    1383           0 :       memcpy (anew->denom_keys,
    1384           0 :               aold->denom_keys,
    1385           0 :               aold->num_denom_keys
    1386             :               * sizeof (struct TALER_EXCHANGE_AuditorDenominationInfo));
    1387             :     }
    1388             : 
    1389             :     /* Old auditors got just copied into new ones.  */
    1390           0 :     if (GNUNET_OK !=
    1391           0 :         decode_keys_json (j,
    1392             :                           true,
    1393             :                           &kd,
    1394             :                           &vc))
    1395             :     {
    1396           0 :       TALER_LOG_ERROR ("Could not decode /keys response\n");
    1397           0 :       hr.http_status = 0;
    1398           0 :       hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
    1399           0 :       for (unsigned int i = 0; i<kd.num_auditors; i++)
    1400             :       {
    1401           0 :         struct TALER_EXCHANGE_AuditorInformation *anew = &kd.auditors[i];
    1402             : 
    1403           0 :         GNUNET_array_grow (anew->denom_keys,
    1404             :                            anew->num_denom_keys,
    1405             :                            0);
    1406           0 :         GNUNET_free (anew->auditor_url);
    1407             :       }
    1408           0 :       GNUNET_free (kd.auditors);
    1409           0 :       kd.auditors = NULL;
    1410           0 :       kd.num_auditors = 0;
    1411           0 :       for (unsigned int i = 0; i<kd_old.num_denom_keys; i++)
    1412           0 :         TALER_denom_pub_free (&kd.denom_keys[i].key);
    1413           0 :       GNUNET_array_grow (kd.denom_keys,
    1414             :                          kd.denom_keys_size,
    1415             :                          0);
    1416           0 :       kd.num_denom_keys = 0;
    1417           0 :       break;
    1418             :     }
    1419           0 :     json_decref (exchange->key_data_raw);
    1420           0 :     exchange->key_data_raw = json_deep_copy (j);
    1421           0 :     exchange->retry_delay = GNUNET_TIME_UNIT_ZERO;
    1422           0 :     break;
    1423           0 :   case MHD_HTTP_BAD_REQUEST:
    1424             :   case MHD_HTTP_UNAUTHORIZED:
    1425             :   case MHD_HTTP_FORBIDDEN:
    1426             :   case MHD_HTTP_NOT_FOUND:
    1427           0 :     if (NULL == j)
    1428             :     {
    1429           0 :       hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    1430           0 :       hr.hint = TALER_ErrorCode_get_hint (hr.ec);
    1431             :     }
    1432             :     else
    1433             :     {
    1434           0 :       hr.ec = TALER_JSON_get_error_code (j);
    1435           0 :       hr.hint = TALER_JSON_get_error_hint (j);
    1436             :     }
    1437           0 :     break;
    1438           0 :   default:
    1439           0 :     if (MHD_HTTP_GATEWAY_TIMEOUT == response_code)
    1440           0 :       exchange->keys_error_count++;
    1441           0 :     if (NULL == j)
    1442             :     {
    1443           0 :       hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    1444           0 :       hr.hint = TALER_ErrorCode_get_hint (hr.ec);
    1445             :     }
    1446             :     else
    1447             :     {
    1448           0 :       hr.ec = TALER_JSON_get_error_code (j);
    1449           0 :       hr.hint = TALER_JSON_get_error_hint (j);
    1450             :     }
    1451           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1452             :                 "Unexpected response code %u/%d\n",
    1453             :                 (unsigned int) response_code,
    1454             :                 (int) hr.ec);
    1455           0 :     break;
    1456             :   }
    1457           0 :   exchange->key_data = kd;
    1458           0 :   if (GNUNET_TIME_absolute_is_past (
    1459             :         exchange->key_data.last_denom_issue_date.abs_time))
    1460           0 :     TALER_LOG_WARNING ("Last DK issue date from exchange is in the past: %s\n",
    1461             :                        GNUNET_TIME_timestamp2s (
    1462             :                          exchange->key_data.last_denom_issue_date));
    1463             :   else
    1464           0 :     TALER_LOG_DEBUG ("Last DK issue date updated to: %s\n",
    1465             :                      GNUNET_TIME_timestamp2s (
    1466             :                        exchange->key_data.last_denom_issue_date));
    1467             : 
    1468             : 
    1469           0 :   if (MHD_HTTP_OK != response_code)
    1470             :   {
    1471           0 :     exchange->kr = NULL;
    1472           0 :     free_keys_request (kr);
    1473           0 :     exchange->state = MHS_FAILED;
    1474           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1475             :                 "Exchange keys download failed\n");
    1476           0 :     if (NULL != exchange->key_data_raw)
    1477             :     {
    1478           0 :       json_decref (exchange->key_data_raw);
    1479           0 :       exchange->key_data_raw = NULL;
    1480             :     }
    1481           0 :     free_key_data (&kd_old);
    1482             :     /* notify application that we failed */
    1483           0 :     exchange->cert_cb (exchange->cert_cb_cls,
    1484             :                        &hr,
    1485             :                        NULL,
    1486             :                        vc);
    1487           0 :     return;
    1488             :   }
    1489             : 
    1490           0 :   exchange->kr = NULL;
    1491           0 :   exchange->key_data_expiration = kr->expire;
    1492           0 :   free_keys_request (kr);
    1493           0 :   exchange->state = MHS_CERT;
    1494           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1495             :               "Successfully downloaded exchange's keys\n");
    1496           0 :   update_auditors (exchange);
    1497             :   /* notify application about the key information */
    1498           0 :   exchange->cert_cb (exchange->cert_cb_cls,
    1499             :                      &hr,
    1500           0 :                      &exchange->key_data,
    1501             :                      vc);
    1502           0 :   free_key_data (&kd_old);
    1503             : }
    1504             : 
    1505             : 
    1506             : /* ********************* library internal API ********* */
    1507             : 
    1508             : 
    1509             : struct GNUNET_CURL_Context *
    1510           0 : TEAH_handle_to_context (struct TALER_EXCHANGE_Handle *h)
    1511             : {
    1512           0 :   return h->ctx;
    1513             : }
    1514             : 
    1515             : 
    1516             : enum GNUNET_GenericReturnValue
    1517           0 : TEAH_handle_is_ready (struct TALER_EXCHANGE_Handle *h)
    1518             : {
    1519           0 :   return (MHS_CERT == h->state) ? GNUNET_YES : GNUNET_NO;
    1520             : }
    1521             : 
    1522             : 
    1523             : char *
    1524           0 : TEAH_path_to_url (struct TALER_EXCHANGE_Handle *h,
    1525             :                   const char *path)
    1526             : {
    1527           0 :   GNUNET_assert ('/' == path[0]);
    1528           0 :   return TALER_url_join (h->url,
    1529             :                          path + 1,
    1530             :                          NULL);
    1531             : }
    1532             : 
    1533             : 
    1534             : /**
    1535             :  * Define a max length for the HTTP "Expire:" header
    1536             :  */
    1537             : #define MAX_DATE_LINE_LEN 32
    1538             : 
    1539             : 
    1540             : /**
    1541             :  * Parse HTTP timestamp.
    1542             :  *
    1543             :  * @param dateline header to parse header
    1544             :  * @param at where to write the result
    1545             :  * @return #GNUNET_OK on success
    1546             :  */
    1547             : static enum GNUNET_GenericReturnValue
    1548           0 : parse_date_string (const char *dateline,
    1549             :                    struct GNUNET_TIME_Timestamp *at)
    1550             : {
    1551             :   static const char *MONTHS[] =
    1552             :   { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    1553             :     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL };
    1554             :   int year;
    1555             :   int mon;
    1556             :   int day;
    1557             :   int hour;
    1558             :   int min;
    1559             :   int sec;
    1560             :   char month[4];
    1561             :   struct tm tm;
    1562             :   time_t t;
    1563             : 
    1564             :   /* We recognize the three formats in RFC2616, section 3.3.1.  Month
    1565             :      names are always in English.  The formats are:
    1566             :       Sun, 06 Nov 1994 08:49:37 GMT  ; RFC 822, updated by RFC 1123
    1567             :       Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
    1568             :       Sun Nov  6 08:49:37 1994       ; ANSI C's asctime() format
    1569             :      Note that the first is preferred.
    1570             :    */
    1571             : 
    1572           0 :   if (strlen (dateline) > MAX_DATE_LINE_LEN)
    1573             :   {
    1574           0 :     GNUNET_break_op (0);
    1575           0 :     return GNUNET_SYSERR;
    1576             :   }
    1577           0 :   while (*dateline == ' ')
    1578           0 :     ++dateline;
    1579           0 :   while (*dateline && *dateline != ' ')
    1580           0 :     ++dateline;
    1581           0 :   while (*dateline == ' ')
    1582           0 :     ++dateline;
    1583             :   /* We just skipped over the day of the week. Now we have:*/
    1584           0 :   if ( (sscanf (dateline,
    1585             :                 "%d %3s %d %d:%d:%d",
    1586           0 :                 &day, month, &year, &hour, &min, &sec) != 6) &&
    1587           0 :        (sscanf (dateline,
    1588             :                 "%d-%3s-%d %d:%d:%d",
    1589           0 :                 &day, month, &year, &hour, &min, &sec) != 6) &&
    1590           0 :        (sscanf (dateline,
    1591             :                 "%3s %d %d:%d:%d %d",
    1592             :                 month, &day, &hour, &min, &sec, &year) != 6) )
    1593             :   {
    1594           0 :     GNUNET_break (0);
    1595           0 :     return GNUNET_SYSERR;
    1596             :   }
    1597             :   /* Two digit dates are defined to be relative to 1900; all other dates
    1598             :    * are supposed to be represented as four digits. */
    1599           0 :   if (year < 100)
    1600           0 :     year += 1900;
    1601             : 
    1602           0 :   for (mon = 0; ; mon++)
    1603             :   {
    1604           0 :     if (! MONTHS[mon])
    1605             :     {
    1606           0 :       GNUNET_break_op (0);
    1607           0 :       return GNUNET_SYSERR;
    1608             :     }
    1609           0 :     if (0 == strcasecmp (month,
    1610             :                          MONTHS[mon]))
    1611           0 :       break;
    1612             :   }
    1613             : 
    1614           0 :   memset (&tm, 0, sizeof(tm));
    1615           0 :   tm.tm_year = year - 1900;
    1616           0 :   tm.tm_mon = mon;
    1617           0 :   tm.tm_mday = day;
    1618           0 :   tm.tm_hour = hour;
    1619           0 :   tm.tm_min = min;
    1620           0 :   tm.tm_sec = sec;
    1621             : 
    1622           0 :   t = mktime (&tm);
    1623           0 :   if (((time_t) -1) == t)
    1624             :   {
    1625           0 :     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
    1626             :                          "mktime");
    1627           0 :     return GNUNET_SYSERR;
    1628             :   }
    1629           0 :   if (t < 0)
    1630           0 :     t = 0; /* can happen due to timezone issues if date was 1.1.1970 */
    1631           0 :   *at = GNUNET_TIME_timestamp_from_s (t);
    1632           0 :   return GNUNET_OK;
    1633             : }
    1634             : 
    1635             : 
    1636             : /**
    1637             :  * Function called for each header in the HTTP /keys response.
    1638             :  * Finds the "Expire:" header and parses it, storing the result
    1639             :  * in the "expire" field of the keys request.
    1640             :  *
    1641             :  * @param buffer header data received
    1642             :  * @param size size of an item in @a buffer
    1643             :  * @param nitems number of items in @a buffer
    1644             :  * @param userdata the `struct KeysRequest`
    1645             :  * @return `size * nitems` on success (everything else aborts)
    1646             :  */
    1647             : static size_t
    1648           0 : header_cb (char *buffer,
    1649             :            size_t size,
    1650             :            size_t nitems,
    1651             :            void *userdata)
    1652             : {
    1653           0 :   struct KeysRequest *kr = userdata;
    1654           0 :   size_t total = size * nitems;
    1655             :   char *val;
    1656             : 
    1657           0 :   if (total < strlen (MHD_HTTP_HEADER_EXPIRES ": "))
    1658           0 :     return total;
    1659           0 :   if (0 != strncasecmp (MHD_HTTP_HEADER_EXPIRES ": ",
    1660             :                         buffer,
    1661             :                         strlen (MHD_HTTP_HEADER_EXPIRES ": ")))
    1662           0 :     return total;
    1663           0 :   val = GNUNET_strndup (&buffer[strlen (MHD_HTTP_HEADER_EXPIRES ": ")],
    1664             :                         total - strlen (MHD_HTTP_HEADER_EXPIRES ": "));
    1665           0 :   if (GNUNET_OK !=
    1666           0 :       parse_date_string (val,
    1667             :                          &kr->expire))
    1668             :   {
    1669           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1670             :                 "Failed to parse %s-header `%s'\n",
    1671             :                 MHD_HTTP_HEADER_EXPIRES,
    1672             :                 val);
    1673           0 :     kr->expire = GNUNET_TIME_UNIT_ZERO_TS;
    1674             :   }
    1675           0 :   GNUNET_free (val);
    1676           0 :   return total;
    1677             : }
    1678             : 
    1679             : 
    1680             : /* ********************* public API ******************* */
    1681             : 
    1682             : 
    1683             : /**
    1684             :  * Deserialize the key data and use it to bootstrap @a exchange to
    1685             :  * more efficiently recover the state.  Errors in @a data must be
    1686             :  * tolerated (i.e. by re-downloading instead).
    1687             :  *
    1688             :  * @param exchange which exchange's key and wire data should be deserialized
    1689             :  * @param data the data to deserialize
    1690             :  */
    1691             : static void
    1692           0 : deserialize_data (struct TALER_EXCHANGE_Handle *exchange,
    1693             :                   const json_t *data)
    1694             : {
    1695             :   enum TALER_EXCHANGE_VersionCompatibility vc;
    1696             :   json_t *keys;
    1697             :   const char *url;
    1698             :   uint32_t version;
    1699             :   struct GNUNET_TIME_Timestamp expire;
    1700             :   struct GNUNET_JSON_Specification spec[] = {
    1701           0 :     GNUNET_JSON_spec_uint32 ("version",
    1702             :                              &version),
    1703           0 :     GNUNET_JSON_spec_json ("keys",
    1704             :                            &keys),
    1705           0 :     GNUNET_JSON_spec_string ("exchange_url",
    1706             :                              &url),
    1707           0 :     GNUNET_JSON_spec_timestamp ("expire",
    1708             :                                 &expire),
    1709           0 :     GNUNET_JSON_spec_end ()
    1710             :   };
    1711             :   struct TALER_EXCHANGE_Keys key_data;
    1712           0 :   struct TALER_EXCHANGE_HttpResponse hr = {
    1713             :     .ec = TALER_EC_NONE,
    1714             :     .http_status = MHD_HTTP_OK,
    1715             :     .reply = data
    1716             :   };
    1717             : 
    1718           0 :   if (NULL == data)
    1719           0 :     return;
    1720           0 :   if (GNUNET_OK !=
    1721           0 :       GNUNET_JSON_parse (data,
    1722             :                          spec,
    1723             :                          NULL, NULL))
    1724             :   {
    1725           0 :     GNUNET_break_op (0);
    1726           0 :     return;
    1727             :   }
    1728           0 :   if (0 != version)
    1729             :   {
    1730           0 :     GNUNET_JSON_parse_free (spec);
    1731           0 :     return; /* unsupported version */
    1732             :   }
    1733           0 :   if (0 != strcmp (url,
    1734           0 :                    exchange->url))
    1735             :   {
    1736           0 :     GNUNET_break (0);
    1737           0 :     GNUNET_JSON_parse_free (spec);
    1738           0 :     return;
    1739             :   }
    1740           0 :   memset (&key_data,
    1741             :           0,
    1742             :           sizeof (struct TALER_EXCHANGE_Keys));
    1743           0 :   if (GNUNET_OK !=
    1744           0 :       decode_keys_json (keys,
    1745             :                         false,
    1746             :                         &key_data,
    1747             :                         &vc))
    1748             :   {
    1749           0 :     GNUNET_break (0);
    1750           0 :     GNUNET_JSON_parse_free (spec);
    1751           0 :     return;
    1752             :   }
    1753             :   /* decode successful, initialize with the result */
    1754           0 :   GNUNET_assert (NULL == exchange->key_data_raw);
    1755           0 :   exchange->key_data_raw = json_deep_copy (keys);
    1756           0 :   exchange->key_data = key_data;
    1757           0 :   exchange->key_data_expiration = expire;
    1758           0 :   exchange->state = MHS_CERT;
    1759           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1760             :               "Successfully loaded exchange's keys via deserialization\n");
    1761           0 :   update_auditors (exchange);
    1762             :   /* notify application about the key information */
    1763           0 :   exchange->cert_cb (exchange->cert_cb_cls,
    1764             :                      &hr,
    1765           0 :                      &exchange->key_data,
    1766             :                      vc);
    1767           0 :   GNUNET_JSON_parse_free (spec);
    1768             : }
    1769             : 
    1770             : 
    1771             : json_t *
    1772           0 : TALER_EXCHANGE_serialize_data (struct TALER_EXCHANGE_Handle *exchange)
    1773             : {
    1774           0 :   const struct TALER_EXCHANGE_Keys *kd = &exchange->key_data;
    1775             :   struct GNUNET_TIME_Timestamp now;
    1776             :   json_t *keys;
    1777             :   json_t *signkeys;
    1778             :   json_t *denoms;
    1779             :   json_t *auditors;
    1780             : 
    1781           0 :   now = GNUNET_TIME_timestamp_get ();
    1782           0 :   signkeys = json_array ();
    1783           0 :   if (NULL == signkeys)
    1784             :   {
    1785           0 :     GNUNET_break (0);
    1786           0 :     return NULL;
    1787             :   }
    1788           0 :   for (unsigned int i = 0; i<kd->num_sign_keys; i++)
    1789             :   {
    1790           0 :     const struct TALER_EXCHANGE_SigningPublicKey *sk = &kd->sign_keys[i];
    1791             :     json_t *signkey;
    1792             : 
    1793           0 :     if (GNUNET_TIME_timestamp_cmp (now,
    1794             :                                    >,
    1795             :                                    sk->valid_until))
    1796           0 :       continue; /* skip keys that have expired */
    1797           0 :     signkey = GNUNET_JSON_PACK (
    1798             :       GNUNET_JSON_pack_data_auto ("key",
    1799             :                                   &sk->key),
    1800             :       GNUNET_JSON_pack_data_auto ("master_sig",
    1801             :                                   &sk->master_sig),
    1802             :       GNUNET_JSON_pack_timestamp ("stamp_start",
    1803             :                                   sk->valid_from),
    1804             :       GNUNET_JSON_pack_timestamp ("stamp_expire",
    1805             :                                   sk->valid_until),
    1806             :       GNUNET_JSON_pack_timestamp ("stamp_end",
    1807             :                                   sk->valid_legal));
    1808           0 :     if (NULL == signkey)
    1809             :     {
    1810           0 :       GNUNET_break (0);
    1811           0 :       continue;
    1812             :     }
    1813           0 :     if (0 != json_array_append_new (signkeys,
    1814             :                                     signkey))
    1815             :     {
    1816           0 :       GNUNET_break (0);
    1817           0 :       json_decref (signkey);
    1818           0 :       json_decref (signkeys);
    1819           0 :       return NULL;
    1820             :     }
    1821             :   }
    1822           0 :   denoms = json_array ();
    1823           0 :   if (NULL == denoms)
    1824             :   {
    1825           0 :     GNUNET_break (0);
    1826           0 :     json_decref (signkeys);
    1827           0 :     return NULL;
    1828             :   }
    1829           0 :   for (unsigned int i = 0; i<kd->num_denom_keys; i++)
    1830             :   {
    1831           0 :     const struct TALER_EXCHANGE_DenomPublicKey *dk = &kd->denom_keys[i];
    1832             :     json_t *denom;
    1833             : 
    1834           0 :     if (GNUNET_TIME_timestamp_cmp (now,
    1835             :                                    >,
    1836             :                                    dk->expire_deposit))
    1837           0 :       continue; /* skip keys that have expired */
    1838           0 :     denom = GNUNET_JSON_PACK (
    1839             :       GNUNET_JSON_pack_timestamp ("stamp_expire_deposit",
    1840             :                                   dk->expire_deposit),
    1841             :       GNUNET_JSON_pack_timestamp ("stamp_expire_withdraw",
    1842             :                                   dk->withdraw_valid_until),
    1843             :       GNUNET_JSON_pack_timestamp ("stamp_start",
    1844             :                                   dk->valid_from),
    1845             :       GNUNET_JSON_pack_timestamp ("stamp_expire_legal",
    1846             :                                   dk->expire_legal),
    1847             :       TALER_JSON_pack_amount ("value",
    1848             :                               &dk->value),
    1849             :       TALER_JSON_PACK_DENOM_FEES ("fee",
    1850             :                                   &dk->fees),
    1851             :       GNUNET_JSON_pack_data_auto ("master_sig",
    1852             :                                   &dk->master_sig),
    1853             :       TALER_JSON_pack_denom_pub ("denom_pub",
    1854             :                                  &dk->key));
    1855           0 :     GNUNET_assert (0 ==
    1856             :                    json_array_append_new (denoms,
    1857             :                                           denom));
    1858             :   }
    1859           0 :   auditors = json_array ();
    1860           0 :   GNUNET_assert (NULL != auditors);
    1861           0 :   for (unsigned int i = 0; i<kd->num_auditors; i++)
    1862             :   {
    1863           0 :     const struct TALER_EXCHANGE_AuditorInformation *ai = &kd->auditors[i];
    1864             :     json_t *a;
    1865             :     json_t *adenoms;
    1866             : 
    1867           0 :     adenoms = json_array ();
    1868           0 :     if (NULL == adenoms)
    1869             :     {
    1870           0 :       GNUNET_break (0);
    1871           0 :       json_decref (denoms);
    1872           0 :       json_decref (signkeys);
    1873           0 :       json_decref (auditors);
    1874           0 :       return NULL;
    1875             :     }
    1876           0 :     for (unsigned int j = 0; j<ai->num_denom_keys; j++)
    1877             :     {
    1878           0 :       const struct TALER_EXCHANGE_AuditorDenominationInfo *adi =
    1879           0 :         &ai->denom_keys[j];
    1880           0 :       const struct TALER_EXCHANGE_DenomPublicKey *dk =
    1881           0 :         &kd->denom_keys[adi->denom_key_offset];
    1882             :       json_t *k;
    1883             : 
    1884           0 :       if (GNUNET_TIME_timestamp_cmp (now,
    1885             :                                      >,
    1886             :                                      dk->expire_deposit))
    1887           0 :         continue; /* skip auditor signatures for denomination keys that have expired */
    1888           0 :       GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys);
    1889           0 :       k = GNUNET_JSON_PACK (
    1890             :         GNUNET_JSON_pack_data_auto ("denom_pub_h",
    1891             :                                     &dk->h_key),
    1892             :         GNUNET_JSON_pack_data_auto ("auditor_sig",
    1893             :                                     &adi->auditor_sig));
    1894           0 :       GNUNET_assert (0 ==
    1895             :                      json_array_append_new (adenoms,
    1896             :                                             k));
    1897             :     }
    1898             : 
    1899           0 :     a = GNUNET_JSON_PACK (
    1900             :       GNUNET_JSON_pack_data_auto ("auditor_pub",
    1901             :                                   &ai->auditor_pub),
    1902             :       GNUNET_JSON_pack_string ("auditor_url",
    1903             :                                ai->auditor_url),
    1904             :       GNUNET_JSON_pack_array_steal ("denomination_keys",
    1905             :                                     adenoms));
    1906           0 :     GNUNET_assert (0 ==
    1907             :                    json_array_append_new (auditors,
    1908             :                                           a));
    1909             :   }
    1910           0 :   keys = GNUNET_JSON_PACK (
    1911             :     GNUNET_JSON_pack_string ("version",
    1912             :                              kd->version),
    1913             :     GNUNET_JSON_pack_string ("currency",
    1914             :                              kd->currency),
    1915             :     GNUNET_JSON_pack_data_auto ("master_public_key",
    1916             :                                 &kd->master_pub),
    1917             :     GNUNET_JSON_pack_time_rel ("reserve_closing_delay",
    1918             :                                kd->reserve_closing_delay),
    1919             :     GNUNET_JSON_pack_timestamp ("list_issue_date",
    1920             :                                 kd->list_issue_date),
    1921             :     GNUNET_JSON_pack_array_steal ("signkeys",
    1922             :                                   signkeys),
    1923             :     GNUNET_JSON_pack_array_steal ("denoms",
    1924             :                                   denoms),
    1925             :     GNUNET_JSON_pack_array_steal ("auditors",
    1926             :                                   auditors));
    1927           0 :   return GNUNET_JSON_PACK (
    1928             :     GNUNET_JSON_pack_uint64 ("version",
    1929             :                              EXCHANGE_SERIALIZATION_FORMAT_VERSION),
    1930             :     GNUNET_JSON_pack_timestamp ("expire",
    1931             :                                 exchange->key_data_expiration),
    1932             :     GNUNET_JSON_pack_string ("exchange_url",
    1933             :                              exchange->url),
    1934             :     GNUNET_JSON_pack_object_steal ("keys",
    1935             :                                    keys));
    1936             : }
    1937             : 
    1938             : 
    1939             : struct TALER_EXCHANGE_Handle *
    1940           0 : TALER_EXCHANGE_connect (
    1941             :   struct GNUNET_CURL_Context *ctx,
    1942             :   const char *url,
    1943             :   TALER_EXCHANGE_CertificationCallback cert_cb,
    1944             :   void *cert_cb_cls,
    1945             :   ...)
    1946             : {
    1947             :   struct TALER_EXCHANGE_Handle *exchange;
    1948             :   va_list ap;
    1949             :   enum TALER_EXCHANGE_Option opt;
    1950             : 
    1951           0 :   TALER_LOG_DEBUG ("Connecting to the exchange (%s)\n",
    1952             :                    url);
    1953             :   /* Disable 100 continue processing */
    1954           0 :   GNUNET_break (GNUNET_OK ==
    1955             :                 GNUNET_CURL_append_header (ctx,
    1956             :                                            MHD_HTTP_HEADER_EXPECT ":"));
    1957           0 :   exchange = GNUNET_new (struct TALER_EXCHANGE_Handle);
    1958           0 :   exchange->ctx = ctx;
    1959           0 :   exchange->url = GNUNET_strdup (url);
    1960           0 :   exchange->cert_cb = cert_cb;
    1961           0 :   exchange->cert_cb_cls = cert_cb_cls;
    1962           0 :   exchange->retry_task = GNUNET_SCHEDULER_add_now (&request_keys,
    1963             :                                                    exchange);
    1964           0 :   va_start (ap, cert_cb_cls);
    1965           0 :   while (TALER_EXCHANGE_OPTION_END !=
    1966           0 :          (opt = va_arg (ap, int)))
    1967             :   {
    1968           0 :     switch (opt)
    1969             :     {
    1970           0 :     case TALER_EXCHANGE_OPTION_END:
    1971           0 :       GNUNET_assert (0);
    1972             :       break;
    1973           0 :     case TALER_EXCHANGE_OPTION_DATA:
    1974             :       {
    1975           0 :         const json_t *data = va_arg (ap, const json_t *);
    1976             : 
    1977           0 :         deserialize_data (exchange,
    1978             :                           data);
    1979           0 :         break;
    1980             :       }
    1981           0 :     default:
    1982           0 :       GNUNET_assert (0);
    1983             :       break;
    1984             :     }
    1985             :   }
    1986           0 :   va_end (ap);
    1987           0 :   return exchange;
    1988             : }
    1989             : 
    1990             : 
    1991             : /**
    1992             :  * Compute the network timeout for the next request to /keys.
    1993             :  *
    1994             :  * @param exchange the exchange handle
    1995             :  * @returns the timeout in seconds (for use by CURL)
    1996             :  */
    1997             : static long
    1998           0 : get_keys_timeout_seconds (struct TALER_EXCHANGE_Handle *exchange)
    1999             : {
    2000             :   unsigned int kec;
    2001             : 
    2002             :   /* if retry counter >= 8, do not bother to go further, we
    2003             :      stop the exponential back-off at 128 anyway. */
    2004           0 :   kec = GNUNET_MIN (7,
    2005             :                     exchange->keys_error_count);
    2006           0 :   return GNUNET_MIN (120,
    2007             :                      5 + (1L << kec));
    2008             : }
    2009             : 
    2010             : 
    2011             : /**
    2012             :  * Initiate download of /keys from the exchange.
    2013             :  *
    2014             :  * @param cls exchange where to download /keys from
    2015             :  */
    2016             : static void
    2017           0 : request_keys (void *cls)
    2018             : {
    2019           0 :   struct TALER_EXCHANGE_Handle *exchange = cls;
    2020             :   struct KeysRequest *kr;
    2021             :   CURL *eh;
    2022           0 :   char url[200] = "/keys?";
    2023             : 
    2024           0 :   exchange->retry_task = NULL;
    2025           0 :   GNUNET_assert (NULL == exchange->kr);
    2026           0 :   kr = GNUNET_new (struct KeysRequest);
    2027           0 :   kr->exchange = exchange;
    2028             : 
    2029           0 :   if (GNUNET_YES == TEAH_handle_is_ready (exchange))
    2030             :   {
    2031           0 :     TALER_LOG_DEBUG ("Last DK issue date (before GETting /keys): %s\n",
    2032             :                      GNUNET_TIME_timestamp2s (
    2033             :                        exchange->key_data.last_denom_issue_date));
    2034           0 :     sprintf (&url[strlen (url)],
    2035             :              "last_issue_date=%llu&",
    2036             :              (unsigned long long)
    2037           0 :              exchange->key_data.last_denom_issue_date.abs_time.abs_value_us
    2038             :              / 1000000LLU);
    2039             :   }
    2040             : 
    2041             :   /* Clean the last '&'/'?' sign that we optimistically put.  */
    2042           0 :   url[strlen (url) - 1] = '\0';
    2043           0 :   kr->url = TEAH_path_to_url (exchange,
    2044             :                               url);
    2045           0 :   if (NULL == kr->url)
    2046             :   {
    2047           0 :     struct TALER_EXCHANGE_HttpResponse hr = {
    2048             :       .ec = TALER_EC_GENERIC_CONFIGURATION_INVALID
    2049             :     };
    2050             : 
    2051           0 :     GNUNET_free (kr);
    2052           0 :     exchange->keys_error_count++;
    2053           0 :     exchange->state = MHS_FAILED;
    2054           0 :     exchange->cert_cb (exchange->cert_cb_cls,
    2055             :                        &hr,
    2056             :                        NULL,
    2057             :                        TALER_EXCHANGE_VC_PROTOCOL_ERROR);
    2058           0 :     return;
    2059             :   }
    2060             : 
    2061           0 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    2062             :               "Requesting keys with URL `%s'.\n",
    2063             :               kr->url);
    2064           0 :   eh = TALER_EXCHANGE_curl_easy_get_ (kr->url);
    2065           0 :   if (NULL == eh)
    2066             :   {
    2067           0 :     GNUNET_free (kr->url);
    2068           0 :     GNUNET_free (kr);
    2069           0 :     exchange->retry_delay = EXCHANGE_LIB_BACKOFF (exchange->retry_delay);
    2070           0 :     exchange->retry_task = GNUNET_SCHEDULER_add_delayed (exchange->retry_delay,
    2071             :                                                          &request_keys,
    2072             :                                                          exchange);
    2073           0 :     return;
    2074             :   }
    2075           0 :   GNUNET_break (CURLE_OK ==
    2076             :                 curl_easy_setopt (eh,
    2077             :                                   CURLOPT_VERBOSE,
    2078             :                                   0));
    2079           0 :   GNUNET_break (CURLE_OK ==
    2080             :                 curl_easy_setopt (eh,
    2081             :                                   CURLOPT_TIMEOUT,
    2082             :                                   get_keys_timeout_seconds (exchange)));
    2083           0 :   GNUNET_assert (CURLE_OK ==
    2084             :                  curl_easy_setopt (eh,
    2085             :                                    CURLOPT_HEADERFUNCTION,
    2086             :                                    &header_cb));
    2087           0 :   GNUNET_assert (CURLE_OK ==
    2088             :                  curl_easy_setopt (eh,
    2089             :                                    CURLOPT_HEADERDATA,
    2090             :                                    kr));
    2091           0 :   kr->job = GNUNET_CURL_job_add_with_ct_json (exchange->ctx,
    2092             :                                               eh,
    2093             :                                               &keys_completed_cb,
    2094             :                                               kr);
    2095           0 :   exchange->kr = kr;
    2096             : }
    2097             : 
    2098             : 
    2099             : void
    2100           0 : TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange)
    2101             : {
    2102             :   struct TEAH_AuditorListEntry *ale;
    2103             : 
    2104           0 :   while (NULL != (ale = exchange->auditors_head))
    2105             :   {
    2106             :     struct TEAH_AuditorInteractionEntry *aie;
    2107             : 
    2108           0 :     while (NULL != (aie = ale->ai_head))
    2109             :     {
    2110           0 :       GNUNET_assert (aie->ale == ale);
    2111           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    2112             :                   "Not sending deposit confirmation to auditor `%s' due to exchange disconnect\n",
    2113             :                   ale->auditor_url);
    2114           0 :       TALER_AUDITOR_deposit_confirmation_cancel (aie->dch);
    2115           0 :       GNUNET_CONTAINER_DLL_remove (ale->ai_head,
    2116             :                                    ale->ai_tail,
    2117             :                                    aie);
    2118           0 :       GNUNET_free (aie);
    2119             :     }
    2120           0 :     GNUNET_CONTAINER_DLL_remove (exchange->auditors_head,
    2121             :                                  exchange->auditors_tail,
    2122             :                                  ale);
    2123           0 :     TALER_LOG_DEBUG ("Disconnecting the auditor `%s'\n",
    2124             :                      ale->auditor_url);
    2125           0 :     TALER_AUDITOR_disconnect (ale->ah);
    2126           0 :     GNUNET_free (ale->auditor_url);
    2127           0 :     GNUNET_free (ale);
    2128             :   }
    2129           0 :   if (NULL != exchange->kr)
    2130             :   {
    2131           0 :     GNUNET_CURL_job_cancel (exchange->kr->job);
    2132           0 :     free_keys_request (exchange->kr);
    2133           0 :     exchange->kr = NULL;
    2134             :   }
    2135           0 :   free_key_data (&exchange->key_data);
    2136           0 :   if (NULL != exchange->key_data_raw)
    2137             :   {
    2138           0 :     json_decref (exchange->key_data_raw);
    2139           0 :     exchange->key_data_raw = NULL;
    2140             :   }
    2141           0 :   if (NULL != exchange->retry_task)
    2142             :   {
    2143           0 :     GNUNET_SCHEDULER_cancel (exchange->retry_task);
    2144           0 :     exchange->retry_task = NULL;
    2145             :   }
    2146           0 :   GNUNET_free (exchange->url);
    2147           0 :   GNUNET_free (exchange);
    2148           0 : }
    2149             : 
    2150             : 
    2151             : enum GNUNET_GenericReturnValue
    2152           0 : TALER_EXCHANGE_test_signing_key (const struct TALER_EXCHANGE_Keys *keys,
    2153             :                                  const struct TALER_ExchangePublicKeyP *pub)
    2154             : {
    2155             :   struct GNUNET_TIME_Absolute now;
    2156             : 
    2157             :   /* we will check using a tolerance of 1h for the time */
    2158           0 :   now = GNUNET_TIME_absolute_get ();
    2159           0 :   for (unsigned int i = 0; i<keys->num_sign_keys; i++)
    2160           0 :     if ( (GNUNET_TIME_absolute_cmp (
    2161             :             keys->sign_keys[i].valid_from.abs_time,
    2162             :             <=,
    2163             :             GNUNET_TIME_absolute_add (now,
    2164           0 :                                       LIFETIME_TOLERANCE))) &&
    2165           0 :          (GNUNET_TIME_absolute_cmp (
    2166             :             keys->sign_keys[i].valid_until.abs_time,
    2167             :             >,
    2168             :             GNUNET_TIME_absolute_subtract (now,
    2169           0 :                                            LIFETIME_TOLERANCE))) &&
    2170           0 :          (0 == GNUNET_memcmp (pub,
    2171             :                               &keys->sign_keys[i].key)) )
    2172           0 :       return GNUNET_OK;
    2173           0 :   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    2174             :               "Signing key not valid at time %s\n",
    2175             :               GNUNET_TIME_absolute2s (now));
    2176           0 :   return GNUNET_SYSERR;
    2177             : }
    2178             : 
    2179             : 
    2180             : const char *
    2181           0 : TALER_EXCHANGE_get_base_url (const struct TALER_EXCHANGE_Handle *exchange)
    2182             : {
    2183           0 :   return exchange->url;
    2184             : }
    2185             : 
    2186             : 
    2187             : const struct TALER_EXCHANGE_DenomPublicKey *
    2188           0 : TALER_EXCHANGE_get_denomination_key (
    2189             :   const struct TALER_EXCHANGE_Keys *keys,
    2190             :   const struct TALER_DenominationPublicKey *pk)
    2191             : {
    2192           0 :   for (unsigned int i = 0; i<keys->num_denom_keys; i++)
    2193           0 :     if (0 ==
    2194           0 :         TALER_denom_pub_cmp (pk,
    2195           0 :                              &keys->denom_keys[i].key))
    2196           0 :       return &keys->denom_keys[i];
    2197           0 :   return NULL;
    2198             : }
    2199             : 
    2200             : 
    2201             : const struct TALER_EXCHANGE_GlobalFee *
    2202           0 : TALER_EXCHANGE_get_global_fee (
    2203             :   const struct TALER_EXCHANGE_Keys *keys,
    2204             :   struct GNUNET_TIME_Timestamp ts)
    2205             : {
    2206           0 :   for (unsigned int i = 0; i<keys->num_global_fees; i++)
    2207             :   {
    2208           0 :     const struct TALER_EXCHANGE_GlobalFee *gf = &keys->global_fees[i];
    2209             : 
    2210           0 :     if (GNUNET_TIME_timestamp_cmp (ts,
    2211             :                                    >=,
    2212           0 :                                    gf->start_date) &&
    2213           0 :         GNUNET_TIME_timestamp_cmp (ts,
    2214             :                                    <,
    2215             :                                    gf->end_date))
    2216           0 :       return gf;
    2217             :   }
    2218           0 :   return NULL;
    2219             : }
    2220             : 
    2221             : 
    2222             : struct TALER_EXCHANGE_DenomPublicKey *
    2223           0 : TALER_EXCHANGE_copy_denomination_key (
    2224             :   const struct TALER_EXCHANGE_DenomPublicKey *key)
    2225             : {
    2226             :   struct TALER_EXCHANGE_DenomPublicKey *copy;
    2227             : 
    2228           0 :   copy = GNUNET_new (struct TALER_EXCHANGE_DenomPublicKey);
    2229           0 :   *copy = *key;
    2230           0 :   TALER_denom_pub_deep_copy (&copy->key,
    2231             :                              &key->key);
    2232           0 :   return copy;
    2233             : }
    2234             : 
    2235             : 
    2236             : void
    2237           0 : TALER_EXCHANGE_destroy_denomination_key (
    2238             :   struct TALER_EXCHANGE_DenomPublicKey *key)
    2239             : {
    2240           0 :   TALER_denom_pub_free (&key->key);
    2241           0 :   GNUNET_free (key);
    2242           0 : }
    2243             : 
    2244             : 
    2245             : const struct TALER_EXCHANGE_DenomPublicKey *
    2246           0 : TALER_EXCHANGE_get_denomination_key_by_hash (
    2247             :   const struct TALER_EXCHANGE_Keys *keys,
    2248             :   const struct TALER_DenominationHashP *hc)
    2249             : {
    2250           0 :   for (unsigned int i = 0; i<keys->num_denom_keys; i++)
    2251           0 :     if (0 == GNUNET_memcmp (hc,
    2252             :                             &keys->denom_keys[i].h_key))
    2253           0 :       return &keys->denom_keys[i];
    2254           0 :   return NULL;
    2255             : }
    2256             : 
    2257             : 
    2258             : const struct TALER_EXCHANGE_Keys *
    2259           0 : TALER_EXCHANGE_get_keys (struct TALER_EXCHANGE_Handle *exchange)
    2260             : {
    2261           0 :   (void) TALER_EXCHANGE_check_keys_current (exchange,
    2262             :                                             TALER_EXCHANGE_CKF_NONE);
    2263           0 :   return &exchange->key_data;
    2264             : }
    2265             : 
    2266             : 
    2267             : json_t *
    2268           0 : TALER_EXCHANGE_get_keys_raw (struct TALER_EXCHANGE_Handle *exchange)
    2269             : {
    2270           0 :   (void) TALER_EXCHANGE_check_keys_current (exchange,
    2271             :                                             TALER_EXCHANGE_CKF_NONE);
    2272           0 :   return json_deep_copy (exchange->key_data_raw);
    2273             : }
    2274             : 
    2275             : 
    2276             : /* end of exchange_api_handle.c */

Generated by: LCOV version 1.14