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: 495 711 69.6 %
Date: 2021-08-30 06:43:37 Functions: 31 33 93.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14