LCOV - code coverage report
Current view: top level - exchange-lib - exchange_api_handle.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 314 386 81.3 %
Date: 2017-11-25 11:31:41 Functions: 20 22 90.9 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014-2017 GNUnet e.V.
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU General Public License as published by the Free Software
       7             :   Foundation; either version 3, or (at your option) any later version.
       8             : 
       9             :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10             :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11             :   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU General Public License along with
      14             :   TALER; see the file COPYING.  If not, see
      15             :   <http://www.gnu.org/licenses/>
      16             : */
      17             : /**
      18             :  * @file exchange-lib/exchange_api_handle.c
      19             :  * @brief Implementation of the "handle" component of the exchange's HTTP API
      20             :  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
      21             :  * @author Christian Grothoff
      22             :  */
      23             : #include "platform.h"
      24             : #include <curl/curl.h>
      25             : #include <microhttpd.h>
      26             : #include <gnunet/gnunet_curl_lib.h>
      27             : #include "taler_json_lib.h"
      28             : #include "taler_exchange_service.h"
      29             : #include "taler_signatures.h"
      30             : #include "exchange_api_handle.h"
      31             : 
      32             : /**
      33             :  * Which revision of the Taler protocol is implemented
      34             :  * by this library?  Used to determine compatibility.
      35             :  */
      36             : #define TALER_PROTOCOL_CURRENT 1
      37             : 
      38             : /**
      39             :  * How many revisions back are we compatible to?
      40             :  */
      41             : #define TALER_PROTOCOL_AGE 1
      42             : 
      43             : 
      44             : /**
      45             :  * Log error related to CURL operations.
      46             :  *
      47             :  * @param type log level
      48             :  * @param function which function failed to run
      49             :  * @param code what was the curl error code
      50             :  */
      51             : #define CURL_STRERROR(type, function, code)      \
      52             :  GNUNET_log (type, "Curl function `%s' has failed at `%s:%d' with error: %s", \
      53             :              function, __FILE__, __LINE__, curl_easy_strerror (code));
      54             : 
      55             : 
      56             : /**
      57             :  * Stages of initialization for the `struct TALER_EXCHANGE_Handle`
      58             :  */
      59             : enum ExchangeHandleState
      60             : {
      61             :   /**
      62             :    * Just allocated.
      63             :    */
      64             :   MHS_INIT = 0,
      65             : 
      66             :   /**
      67             :    * Obtained the exchange's certification data and keys.
      68             :    */
      69             :   MHS_CERT = 1,
      70             : 
      71             :   /**
      72             :    * Failed to initialize (fatal).
      73             :    */
      74             :   MHS_FAILED = 2
      75             : };
      76             : 
      77             : 
      78             : /**
      79             :  * Data for the request to get the /keys of a exchange.
      80             :  */
      81             : struct KeysRequest;
      82             : 
      83             : 
      84             : /**
      85             :  * Handle to the exchange
      86             :  */
      87             : struct TALER_EXCHANGE_Handle
      88             : {
      89             :   /**
      90             :    * The context of this handle
      91             :    */
      92             :   struct GNUNET_CURL_Context *ctx;
      93             : 
      94             :   /**
      95             :    * The URL of the exchange (i.e. "http://exchange.taler.net/")
      96             :    */
      97             :   char *url;
      98             : 
      99             :   /**
     100             :    * Function to call with the exchange's certification data,
     101             :    * NULL if this has already been done.
     102             :    */
     103             :   TALER_EXCHANGE_CertificationCallback cert_cb;
     104             : 
     105             :   /**
     106             :    * Closure to pass to @e cert_cb.
     107             :    */
     108             :   void *cert_cb_cls;
     109             : 
     110             :   /**
     111             :    * Data for the request to get the /keys of a exchange,
     112             :    * NULL once we are past stage #MHS_INIT.
     113             :    */
     114             :   struct KeysRequest *kr;
     115             : 
     116             :   /**
     117             :    * Key data of the exchange, only valid if
     118             :    * @e handshake_complete is past stage #MHS_CERT.
     119             :    */
     120             :   struct TALER_EXCHANGE_Keys key_data;
     121             : 
     122             :   /**
     123             :    * When does @e key_data expire?
     124             :    */
     125             :   struct GNUNET_TIME_Absolute key_data_expiration;
     126             : 
     127             :   /**
     128             :    * Raw key data of the exchange, only valid if
     129             :    * @e handshake_complete is past stage #MHS_CERT.
     130             :    */
     131             :   json_t *key_data_raw;
     132             : 
     133             :   /**
     134             :    * Stage of the exchange's initialization routines.
     135             :    */
     136             :   enum ExchangeHandleState state;
     137             : 
     138             : };
     139             : 
     140             : 
     141             : /* ***************** Internal /keys fetching ************* */
     142             : 
     143             : /**
     144             :  * Data for the request to get the /keys of a exchange.
     145             :  */
     146             : struct KeysRequest
     147             : {
     148             :   /**
     149             :    * The connection to exchange this request handle will use
     150             :    */
     151             :   struct TALER_EXCHANGE_Handle *exchange;
     152             : 
     153             :   /**
     154             :    * The url for this handle
     155             :    */
     156             :   char *url;
     157             : 
     158             :   /**
     159             :    * Entry for this request with the `struct GNUNET_CURL_Context`.
     160             :    */
     161             :   struct GNUNET_CURL_Job *job;
     162             : 
     163             :   /**
     164             :    * Expiration time according to "Expire:" header.
     165             :    * 0 if not provided by the server.
     166             :    */
     167             :   struct GNUNET_TIME_Absolute expire;
     168             : 
     169             : };
     170             : 
     171             : 
     172             : /**
     173             :  * Release memory occupied by a keys request.
     174             :  * Note that this does not cancel the request
     175             :  * itself.
     176             :  *
     177             :  * @param kr request to free
     178             :  */
     179             : static void
     180           3 : free_keys_request (struct KeysRequest *kr)
     181             : {
     182           3 :   GNUNET_free (kr->url);
     183           3 :   GNUNET_free (kr);
     184           3 : }
     185             : 
     186             : 
     187             : #define EXITIF(cond)                                              \
     188             :   do {                                                            \
     189             :     if (cond) { GNUNET_break (0); goto EXITIF_exit; }             \
     190             :   } while (0)
     191             : 
     192             : 
     193             : /**
     194             :  * Parse a exchange's signing key encoded in JSON.
     195             :  *
     196             :  * @param[out] sign_key where to return the result
     197             :  * @param[in] sign_key_obj json to parse
     198             :  * @param master_key master key to use to verify signature
     199             :  * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
     200             :  *        invalid or the json malformed.
     201             :  */
     202             : static int
     203           3 : parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key,
     204             :                     json_t *sign_key_obj,
     205             :                     const struct TALER_MasterPublicKeyP *master_key)
     206             : {
     207             :   struct TALER_ExchangeSigningKeyValidityPS sign_key_issue;
     208             :   struct GNUNET_CRYPTO_EddsaSignature sig;
     209             :   struct GNUNET_TIME_Absolute valid_from;
     210             :   struct GNUNET_TIME_Absolute valid_until;
     211             :   struct GNUNET_TIME_Absolute valid_legal;
     212           3 :   struct GNUNET_JSON_Specification spec[] = {
     213             :     GNUNET_JSON_spec_fixed_auto ("master_sig",
     214             :                                  &sig),
     215             :     GNUNET_JSON_spec_fixed_auto ("key",
     216             :                                  &sign_key_issue.signkey_pub),
     217             :     GNUNET_JSON_spec_absolute_time ("stamp_start",
     218             :                                     &valid_from),
     219             :     GNUNET_JSON_spec_absolute_time ("stamp_expire",
     220             :                                     &valid_until),
     221             :     GNUNET_JSON_spec_absolute_time ("stamp_end",
     222             :                                     &valid_legal),
     223             :     GNUNET_JSON_spec_end()
     224             :   };
     225             : 
     226           3 :   if (GNUNET_OK !=
     227           3 :       GNUNET_JSON_parse (sign_key_obj,
     228             :                          spec,
     229             :                          NULL, NULL))
     230             :   {
     231           0 :     GNUNET_break_op (0);
     232           0 :     return GNUNET_SYSERR;
     233             :   }
     234             : 
     235           3 :   sign_key_issue.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY);
     236           3 :   sign_key_issue.purpose.size =
     237           3 :     htonl (sizeof (struct TALER_ExchangeSigningKeyValidityPS)
     238             :            - offsetof (struct TALER_ExchangeSigningKeyValidityPS,
     239             :                        purpose));
     240           3 :   sign_key_issue.master_public_key = *master_key;
     241           3 :   sign_key_issue.start = GNUNET_TIME_absolute_hton (valid_from);
     242           3 :   sign_key_issue.expire = GNUNET_TIME_absolute_hton (valid_until);
     243           3 :   sign_key_issue.end = GNUNET_TIME_absolute_hton (valid_legal);
     244           3 :   if (GNUNET_OK !=
     245           3 :       GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY,
     246             :                                   &sign_key_issue.purpose,
     247             :                                   &sig,
     248             :                                   &master_key->eddsa_pub))
     249             :   {
     250           0 :     GNUNET_break_op (0);
     251           0 :     return GNUNET_SYSERR;
     252             :   }
     253           3 :   sign_key->valid_from = valid_from;
     254           3 :   sign_key->valid_until = valid_until;
     255           3 :   sign_key->key = sign_key_issue.signkey_pub;
     256           3 :   return GNUNET_OK;
     257             : }
     258             : 
     259             : 
     260             : /**
     261             :  * Parse a exchange's denomination key encoded in JSON.
     262             :  *
     263             :  * @param[out] denom_key where to return the result
     264             :  * @param[in] denom_key_obj json to parse
     265             :  * @param master_key master key to use to verify signature
     266             :  * @param hash_context where to accumulate data for signature verification
     267             :  * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
     268             :  *        invalid or the json malformed.
     269             :  */
     270             : static int
     271          13 : parse_json_denomkey (struct TALER_EXCHANGE_DenomPublicKey *denom_key,
     272             :                      json_t *denom_key_obj,
     273             :                      struct TALER_MasterPublicKeyP *master_key,
     274             :                      struct GNUNET_HashContext *hash_context)
     275             : {
     276             :   struct GNUNET_TIME_Absolute valid_from;
     277             :   struct GNUNET_TIME_Absolute withdraw_valid_until;
     278             :   struct GNUNET_TIME_Absolute expire_deposit;
     279             :   struct GNUNET_TIME_Absolute expire_legal;
     280             :   struct TALER_Amount value;
     281             :   struct TALER_Amount fee_withdraw;
     282             :   struct TALER_Amount fee_deposit;
     283             :   struct TALER_Amount fee_refresh;
     284             :   struct TALER_Amount fee_refund;
     285             :   struct TALER_DenominationKeyValidityPS denom_key_issue;
     286             :   struct GNUNET_CRYPTO_RsaPublicKey *pk;
     287             :   struct GNUNET_CRYPTO_EddsaSignature sig;
     288          13 :   struct GNUNET_JSON_Specification spec[] = {
     289             :     GNUNET_JSON_spec_fixed_auto ("master_sig",
     290             :                                  &sig),
     291             :     GNUNET_JSON_spec_absolute_time ("stamp_expire_deposit",
     292             :                                     &expire_deposit),
     293             :     GNUNET_JSON_spec_absolute_time ("stamp_expire_withdraw",
     294             :                                     &withdraw_valid_until),
     295             :     GNUNET_JSON_spec_absolute_time ("stamp_start",
     296             :                                     &valid_from),
     297             :     GNUNET_JSON_spec_absolute_time ("stamp_expire_legal",
     298             :                                     &expire_legal),
     299             :     TALER_JSON_spec_amount ("value",
     300             :                             &value),
     301             :     TALER_JSON_spec_amount ("fee_withdraw",
     302             :                             &fee_withdraw),
     303             :     TALER_JSON_spec_amount ("fee_deposit",
     304             :                             &fee_deposit),
     305             :     TALER_JSON_spec_amount ("fee_refresh",
     306             :                             &fee_refresh),
     307             :     TALER_JSON_spec_amount ("fee_refund",
     308             :                             &fee_refund),
     309             :     GNUNET_JSON_spec_rsa_public_key ("denom_pub",
     310             :                              &pk),
     311             :     GNUNET_JSON_spec_end()
     312             :   };
     313             : 
     314          13 :   if (GNUNET_OK !=
     315          13 :       GNUNET_JSON_parse (denom_key_obj,
     316             :                          spec, NULL, NULL))
     317             :   {
     318           0 :     GNUNET_break_op (0);
     319           0 :     return GNUNET_SYSERR;
     320             :   }
     321             : 
     322          13 :   memset (&denom_key_issue,
     323             :           0,
     324             :           sizeof (denom_key_issue));
     325          13 :   GNUNET_CRYPTO_rsa_public_key_hash (pk,
     326             :                                      &denom_key_issue.denom_hash);
     327             :   denom_key_issue.purpose.purpose
     328          13 :     = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY);
     329             :   denom_key_issue.purpose.size
     330          13 :     = htonl (sizeof (struct TALER_DenominationKeyValidityPS));
     331          13 :   denom_key_issue.master = *master_key;
     332          13 :   denom_key_issue.start = GNUNET_TIME_absolute_hton (valid_from);
     333          13 :   denom_key_issue.expire_withdraw = GNUNET_TIME_absolute_hton (withdraw_valid_until);
     334          13 :   denom_key_issue.expire_deposit = GNUNET_TIME_absolute_hton (expire_deposit);
     335          13 :   denom_key_issue.expire_legal = GNUNET_TIME_absolute_hton (expire_legal);
     336          13 :   TALER_amount_hton (&denom_key_issue.value,
     337             :                      &value);
     338          13 :   TALER_amount_hton (&denom_key_issue.fee_withdraw,
     339             :                      &fee_withdraw);
     340          13 :   TALER_amount_hton (&denom_key_issue.fee_deposit,
     341             :                      &fee_deposit);
     342          13 :   TALER_amount_hton (&denom_key_issue.fee_refresh,
     343             :                      &fee_refresh);
     344          13 :   TALER_amount_hton (&denom_key_issue.fee_refund,
     345             :                      &fee_refund);
     346          13 :   EXITIF (GNUNET_SYSERR ==
     347             :           GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY,
     348             :                                       &denom_key_issue.purpose,
     349             :                                       &sig,
     350             :                                       &master_key->eddsa_pub));
     351          13 :   GNUNET_CRYPTO_hash_context_read (hash_context,
     352             :                                    &denom_key_issue.denom_hash,
     353             :                                    sizeof (struct GNUNET_HashCode));
     354          13 :   denom_key->key.rsa_public_key = pk;
     355          13 :   denom_key->h_key = denom_key_issue.denom_hash;
     356          13 :   denom_key->valid_from = valid_from;
     357          13 :   denom_key->withdraw_valid_until = withdraw_valid_until;
     358          13 :   denom_key->expire_deposit = expire_deposit;
     359          13 :   denom_key->expire_legal = expire_legal;
     360          13 :   denom_key->value = value;
     361          13 :   denom_key->fee_withdraw = fee_withdraw;
     362          13 :   denom_key->fee_deposit = fee_deposit;
     363          13 :   denom_key->fee_refresh = fee_refresh;
     364          13 :   denom_key->fee_refund = fee_refund;
     365          13 :   return GNUNET_OK;
     366             : 
     367             :  EXITIF_exit:
     368           0 :   GNUNET_JSON_parse_free (spec);
     369           0 :   return GNUNET_SYSERR;
     370             : }
     371             : 
     372             : 
     373             : /**
     374             :  * Parse a exchange's auditor information encoded in JSON.
     375             :  *
     376             :  * @param[out] auditor where to return the result
     377             :  * @param[in] auditor_obj json to parse
     378             :  * @param key_data information about denomination keys
     379             :  * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
     380             :  *        invalid or the json malformed.
     381             :  */
     382             : static int
     383           3 : parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,
     384             :                     json_t *auditor_obj,
     385             :                     const struct TALER_EXCHANGE_Keys *key_data)
     386             : {
     387             :   json_t *keys;
     388             :   json_t *key;
     389             :   unsigned int len;
     390             :   unsigned int off;
     391             :   unsigned int i;
     392             :   const char *auditor_url;
     393             :   struct TALER_ExchangeKeyValidityPS kv;
     394           3 :   struct GNUNET_JSON_Specification spec[] = {
     395           3 :     GNUNET_JSON_spec_fixed_auto ("auditor_pub",
     396             :                                  &auditor->auditor_pub),
     397             :     GNUNET_JSON_spec_string ("auditor_url",
     398             :                              &auditor_url),
     399             :     GNUNET_JSON_spec_json ("denomination_keys",
     400             :                            &keys),
     401             :     GNUNET_JSON_spec_end()
     402             :   };
     403             : 
     404           3 :   if (GNUNET_OK !=
     405           3 :       GNUNET_JSON_parse (auditor_obj,
     406             :                          spec,
     407             :                          NULL, NULL))
     408             :   {
     409           0 :     GNUNET_break_op (0);
     410           0 :     return GNUNET_SYSERR;
     411             :   }
     412           3 :   auditor->auditor_url = GNUNET_strdup (auditor_url);
     413           3 :   kv.purpose.purpose = htonl (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS);
     414           3 :   kv.purpose.size = htonl (sizeof (struct TALER_ExchangeKeyValidityPS));
     415           3 :   GNUNET_CRYPTO_hash (auditor_url,
     416           3 :                       strlen (auditor_url) + 1,
     417             :                       &kv.auditor_url_hash);
     418           3 :   kv.master = key_data->master_pub;
     419           3 :   len = json_array_size (keys);
     420           3 :   auditor->denom_keys = GNUNET_new_array (len,
     421             :                                           const struct TALER_EXCHANGE_DenomPublicKey *);
     422           3 :   i = 0;
     423           3 :   off = 0;
     424          16 :   json_array_foreach (keys, i, key) {
     425             :     struct TALER_AuditorSignatureP auditor_sig;
     426             :     struct GNUNET_HashCode denom_h;
     427             :     const struct TALER_EXCHANGE_DenomPublicKey *dk;
     428          13 :     struct GNUNET_JSON_Specification kspec[] = {
     429             :       GNUNET_JSON_spec_fixed_auto ("denom_pub_h",
     430             :                                    &denom_h),
     431             :       GNUNET_JSON_spec_fixed_auto ("auditor_sig",
     432             :                                    &auditor_sig),
     433             :       GNUNET_JSON_spec_end()
     434             :     };
     435             : 
     436          13 :     if (GNUNET_OK !=
     437          13 :         GNUNET_JSON_parse (key,
     438             :                            kspec,
     439             :                            NULL, NULL))
     440             :     {
     441           0 :       GNUNET_break_op (0);
     442           0 :       continue;
     443             :     }
     444          13 :     dk = NULL;
     445          51 :     for (unsigned int j=0;j<key_data->num_denom_keys;j++)
     446             :     {
     447          51 :       if (0 == memcmp (&denom_h,
     448          51 :                        &key_data->denom_keys[j].h_key,
     449             :                        sizeof (struct GNUNET_HashCode)))
     450             :       {
     451          13 :         dk = &key_data->denom_keys[j];
     452          13 :         break;
     453             :       }
     454             :     }
     455          13 :     if (NULL == dk)
     456             :     {
     457           0 :       GNUNET_break_op (0);
     458           0 :       continue;
     459             :     }
     460          13 :     kv.start = GNUNET_TIME_absolute_hton (dk->valid_from);
     461          13 :     kv.expire_withdraw = GNUNET_TIME_absolute_hton (dk->withdraw_valid_until);
     462          13 :     kv.expire_deposit = GNUNET_TIME_absolute_hton (dk->expire_deposit);
     463          13 :     kv.expire_legal = GNUNET_TIME_absolute_hton (dk->expire_legal);
     464          13 :     TALER_amount_hton (&kv.value,
     465             :                        &dk->value);
     466          13 :     TALER_amount_hton (&kv.fee_withdraw,
     467             :                        &dk->fee_withdraw);
     468          13 :     TALER_amount_hton (&kv.fee_deposit,
     469             :                        &dk->fee_deposit);
     470          13 :     TALER_amount_hton (&kv.fee_refresh,
     471             :                        &dk->fee_refresh);
     472          13 :     TALER_amount_hton (&kv.fee_refund,
     473             :                        &dk->fee_refund);
     474          13 :     kv.denom_hash = dk->h_key;
     475             : 
     476          13 :     if (GNUNET_OK !=
     477          13 :         GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS,
     478             :                                     &kv.purpose,
     479             :                                     &auditor_sig.eddsa_sig,
     480          13 :                                     &auditor->auditor_pub.eddsa_pub))
     481             :     {
     482           0 :       GNUNET_break_op (0);
     483           0 :       GNUNET_JSON_parse_free (spec);
     484           0 :       return GNUNET_SYSERR;
     485             :     }
     486          13 :     auditor->denom_keys[off] = dk;
     487          13 :     off++;
     488             :   }
     489           3 :   auditor->num_denom_keys = off;
     490           3 :   GNUNET_JSON_parse_free (spec);
     491           3 :   return GNUNET_OK;
     492             : }
     493             : 
     494             : 
     495             : /**
     496             :  * Decode the JSON in @a resp_obj from the /keys response and store the data
     497             :  * in the @a key_data.
     498             :  *
     499             :  * @param[in] resp_obj JSON object to parse
     500             :  * @param[out] key_data where to store the results we decoded
     501             :  * @param[out] where to store version compatibility data
     502             :  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (malformed JSON)
     503             :  */
     504             : static int
     505           3 : decode_keys_json (const json_t *resp_obj,
     506             :                   struct TALER_EXCHANGE_Keys *key_data,
     507             :                   enum TALER_EXCHANGE_VersionCompatibility *vc)
     508             : {
     509             :   struct GNUNET_TIME_Absolute list_issue_date;
     510             :   struct GNUNET_TIME_Absolute last_denom_issue_date;
     511             :   struct TALER_ExchangeSignatureP sig;
     512             :   struct TALER_ExchangeKeySetPS ks;
     513             :   struct GNUNET_HashContext *hash_context;
     514             :   struct TALER_ExchangePublicKeyP pub;
     515             :   unsigned int age;
     516             :   unsigned int revision;
     517             :   unsigned int current;
     518             : 
     519           3 :   if (JSON_OBJECT != json_typeof (resp_obj))
     520             :   {
     521           0 :     GNUNET_break_op (0);
     522           0 :     return GNUNET_SYSERR;
     523             :   }
     524             :   /* check the version */
     525             :   {
     526             :     const char *ver;
     527           3 :     struct GNUNET_JSON_Specification spec[] = {
     528             :       GNUNET_JSON_spec_string ("version",
     529             :                                &ver),
     530             :       GNUNET_JSON_spec_end()
     531             :     };
     532             : 
     533           3 :     if (GNUNET_OK !=
     534           3 :         GNUNET_JSON_parse (resp_obj,
     535             :                            spec,
     536             :                            NULL, NULL))
     537             :     {
     538           0 :       GNUNET_break_op (0);
     539           0 :       return GNUNET_SYSERR;
     540             :     }
     541           3 :     if (3 != sscanf (ver,
     542             :                      "%u:%u:%u",
     543             :                      &current,
     544             :                      &revision,
     545             :                      &age))
     546             :     {
     547           0 :       GNUNET_break_op (0);
     548           0 :       return GNUNET_SYSERR;
     549             :     }
     550           3 :     *vc = TALER_EXCHANGE_VC_MATCH;
     551           3 :     if (TALER_PROTOCOL_CURRENT < current)
     552             :     {
     553           0 :       *vc |= TALER_EXCHANGE_VC_NEWER;
     554           0 :       if (TALER_PROTOCOL_CURRENT < current - age)
     555           0 :         *vc |= TALER_EXCHANGE_VC_INCOMPATIBLE;
     556             :     }
     557           3 :     if (TALER_PROTOCOL_CURRENT > current)
     558             :     {
     559           0 :       *vc |= TALER_EXCHANGE_VC_OLDER;
     560             :       if (TALER_PROTOCOL_CURRENT - TALER_PROTOCOL_AGE > current)
     561             :         *vc |= TALER_EXCHANGE_VC_INCOMPATIBLE;
     562             :     }
     563           3 :     key_data->version = GNUNET_strdup (ver);
     564             :   }
     565             : 
     566             :   /* parse the master public key and issue date of the response */
     567           3 :   hash_context = GNUNET_CRYPTO_hash_context_start ();
     568             :   {
     569           3 :     struct GNUNET_JSON_Specification spec[] = {
     570           3 :       GNUNET_JSON_spec_fixed_auto ("master_public_key",
     571             :                                    &key_data->master_pub),
     572             :       GNUNET_JSON_spec_fixed_auto ("eddsa_sig",
     573             :                                    &sig),
     574             :       GNUNET_JSON_spec_fixed_auto ("eddsa_pub",
     575             :                                    &pub),
     576             :       GNUNET_JSON_spec_absolute_time ("list_issue_date",
     577             :                                       &list_issue_date),
     578             :       GNUNET_JSON_spec_end()
     579             :     };
     580             : 
     581           3 :     EXITIF (GNUNET_OK !=
     582             :             GNUNET_JSON_parse (resp_obj,
     583             :                                spec,
     584             :                                NULL, NULL));
     585             :   }
     586             : 
     587             :   /* parse the signing keys */
     588             :   {
     589             :     json_t *sign_keys_array;
     590             :     json_t *sign_key_obj;
     591             :     unsigned int index;
     592             : 
     593           3 :     EXITIF (NULL == (sign_keys_array =
     594             :                      json_object_get (resp_obj,
     595             :                                       "signkeys")));
     596           3 :     EXITIF (JSON_ARRAY != json_typeof (sign_keys_array));
     597           3 :     EXITIF (0 == (key_data->num_sign_keys =
     598             :                   json_array_size (sign_keys_array)));
     599             :     key_data->sign_keys
     600           3 :       = GNUNET_new_array (key_data->num_sign_keys,
     601             :                           struct TALER_EXCHANGE_SigningPublicKey);
     602           3 :     index = 0;
     603           6 :     json_array_foreach (sign_keys_array, index, sign_key_obj) {
     604           3 :       EXITIF (GNUNET_SYSERR ==
     605             :               parse_json_signkey (&key_data->sign_keys[index],
     606             :                                   sign_key_obj,
     607             :                                   &key_data->master_pub));
     608             :     }
     609             :   }
     610             : 
     611             :   /* parse the denomination keys, merging with the
     612             :      possibly EXISTING array as required (/keys cherry picking) */
     613           3 :   last_denom_issue_date.abs_value_us = 0LLU;
     614             :   {
     615             :     json_t *denom_keys_array;
     616             :     json_t *denom_key_obj;
     617             :     unsigned int index;
     618             : 
     619           3 :     EXITIF (NULL == (denom_keys_array =
     620             :                      json_object_get (resp_obj, "denoms")));
     621           3 :     EXITIF (JSON_ARRAY != json_typeof (denom_keys_array));
     622             : 
     623           3 :     index = 0;
     624          16 :     json_array_foreach (denom_keys_array, index, denom_key_obj) {
     625             :       struct TALER_EXCHANGE_DenomPublicKey dk;
     626          13 :       bool found = false;
     627             : 
     628          13 :       EXITIF (GNUNET_SYSERR ==
     629             :               parse_json_denomkey (&dk,
     630             :                                    denom_key_obj,
     631             :                                    &key_data->master_pub,
     632             :                                    hash_context));
     633          51 :       for (unsigned int j=0;j<key_data->num_denom_keys;j++)
     634             :       {
     635          38 :         if (0 == memcmp (&dk,
     636          38 :                          &key_data->denom_keys[j],
     637             :                          sizeof (dk)))
     638             :         {
     639           0 :           found = true;
     640           0 :           break;
     641             :         }
     642             :       }
     643          13 :       if (found)
     644             :       {
     645             :         /* 0:0:0 did not support /keys cherry picking */
     646           0 :         GNUNET_break_op (0 == current);
     647           0 :         continue;
     648             :       }
     649          13 :       if (key_data->denom_keys_size == key_data->num_denom_keys)
     650           5 :         GNUNET_array_grow (key_data->denom_keys,
     651             :                            key_data->denom_keys_size,
     652             :                            key_data->denom_keys_size * 2 + 2);
     653          13 :       key_data->denom_keys[key_data->num_denom_keys++] = dk;
     654             : 
     655             :       /* Update "last_denom_issue_date" */
     656             :       last_denom_issue_date
     657          13 :         = GNUNET_TIME_absolute_max (last_denom_issue_date,
     658             :                                     dk.valid_from);
     659             :     };
     660             :   }
     661           3 :   key_data->last_denom_issue_date = last_denom_issue_date;
     662             : 
     663             :   /* parse the auditor information */
     664             :   {
     665             :     json_t *auditors_array;
     666             :     json_t *auditor_info;
     667             :     unsigned int index;
     668             : 
     669           3 :     EXITIF (NULL == (auditors_array =
     670             :                      json_object_get (resp_obj, "auditors")));
     671           3 :     EXITIF (JSON_ARRAY != json_typeof (auditors_array));
     672             : 
     673             :     /* Merge with the existing auditor information we have (/keys cherry picking) */
     674           3 :     index = 0;
     675           6 :     json_array_foreach (auditors_array, index, auditor_info) {
     676             :       struct TALER_EXCHANGE_AuditorInformation ai;
     677           3 :       bool found = false;
     678             : 
     679           3 :       EXITIF (GNUNET_SYSERR ==
     680             :               parse_json_auditor (&ai,
     681             :                                   auditor_info,
     682             :                                   key_data));
     683           3 :       for (unsigned int j=0;j<key_data->num_auditors;j++)
     684             :       {
     685           1 :         struct TALER_EXCHANGE_AuditorInformation *aix = &key_data->auditors[j];
     686           1 :         if (0 == memcmp (&ai.auditor_pub,
     687           1 :                          &aix->auditor_pub,
     688             :                          sizeof (struct TALER_AuditorPublicKeyP)))
     689             :         {
     690           1 :           found = true;
     691             :           /* Merge denomination key signatures of downloaded /keys into existing
     692             :              auditor information 'aix'. */
     693           1 :           GNUNET_array_grow (aix->denom_keys,
     694             :                              aix->num_denom_keys,
     695             :                              aix->num_denom_keys + ai.num_denom_keys);
     696           2 :           memcpy (&aix->denom_keys[aix->num_denom_keys - ai.num_denom_keys],
     697           1 :                   ai.denom_keys,
     698           1 :                   ai.num_denom_keys * sizeof (struct TALER_EXCHANGE_DenomPublicKey *));
     699           1 :           break;
     700             :         }
     701             :       }
     702           3 :       if (found)
     703           1 :         continue; /* we are done */
     704           2 :       if (key_data->auditors_size == key_data->num_auditors)
     705           2 :         GNUNET_array_grow (key_data->auditors,
     706             :                            key_data->auditors_size,
     707             :                            key_data->auditors_size * 2 + 2);
     708           2 :       key_data->auditors[key_data->num_auditors++] = ai;
     709             :     };
     710             :   }
     711             : 
     712             :   /* Validate signature... */
     713           3 :   ks.purpose.size = htonl (sizeof (ks));
     714           3 :   ks.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_KEY_SET);
     715           3 :   ks.list_issue_date = GNUNET_TIME_absolute_hton (list_issue_date);
     716           3 :   GNUNET_CRYPTO_hash_context_finish (hash_context,
     717             :                                      &ks.hc);
     718           3 :   hash_context = NULL;
     719           3 :   EXITIF (GNUNET_OK !=
     720             :           TALER_EXCHANGE_test_signing_key (key_data,
     721             :                                            &pub));
     722           3 :   EXITIF (GNUNET_OK !=
     723             :           GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_KEY_SET,
     724             :                                       &ks.purpose,
     725             :                                       &sig.eddsa_signature,
     726             :                                       &pub.eddsa_pub));
     727           3 :   return GNUNET_OK;
     728             :  EXITIF_exit:
     729             : 
     730           0 :   if (NULL != hash_context)
     731           0 :     GNUNET_CRYPTO_hash_context_abort (hash_context);
     732           0 :   return GNUNET_SYSERR;
     733             : }
     734             : 
     735             : 
     736             : /**
     737             :  * Free key data object.
     738             :  *
     739             :  * @param key_data data to free (pointer itself excluded)
     740             :  */
     741             : static void
     742           5 : free_key_data (struct TALER_EXCHANGE_Keys *key_data)
     743             : {
     744           5 :   GNUNET_array_grow (key_data->sign_keys,
     745             :                      key_data->num_sign_keys,
     746             :                      0);
     747          22 :   for (unsigned int i=0;i<key_data->num_denom_keys;i++)
     748          17 :     GNUNET_CRYPTO_rsa_public_key_free (key_data->denom_keys[i].key.rsa_public_key);
     749           5 :   GNUNET_array_grow (key_data->denom_keys,
     750             :                      key_data->denom_keys_size,
     751             :                      0);
     752           8 :   for (unsigned int i=0;i<key_data->num_auditors;i++)
     753             :   {
     754           3 :     GNUNET_array_grow (key_data->auditors[i].denom_keys,
     755             :                        key_data->auditors[i].num_denom_keys,
     756             :                        0);
     757           3 :     GNUNET_free (key_data->auditors[i].auditor_url);
     758             :   }
     759           5 :   GNUNET_array_grow (key_data->auditors,
     760             :                      key_data->auditors_size,
     761             :                      0);
     762           5 :   GNUNET_free_non_null (key_data->version);
     763           5 :   key_data->version = NULL;
     764           5 : }
     765             : 
     766             : 
     767             : /**
     768             :  * Initiate download of /keys from the exchange.
     769             :  *
     770             :  * @param exchange where to download /keys from
     771             :  */
     772             : static void
     773             : request_keys (struct TALER_EXCHANGE_Handle *exchange);
     774             : 
     775             : 
     776             : /**
     777             :  * Check if our current response for /keys is valid, and if
     778             :  * not trigger download.
     779             :  *
     780             :  * @param exchange exchange to check keys for
     781             :  * @param force_download #GNUNET_YES to force download even if /keys is still valid
     782             :  * @return until when the response is current, 0 if we are re-downloading
     783             :  */
     784             : struct GNUNET_TIME_Absolute
     785          38 : TALER_EXCHANGE_check_keys_current (struct TALER_EXCHANGE_Handle *exchange,
     786             :                                    int force_download)
     787             : {
     788          38 :   if (NULL != exchange->kr)
     789           0 :     return GNUNET_TIME_UNIT_ZERO_ABS;
     790          75 :   if ( (GNUNET_NO == force_download) &&
     791          37 :        (0 < GNUNET_TIME_absolute_get_remaining (exchange->key_data_expiration).rel_value_us) )
     792          37 :     return exchange->key_data_expiration;
     793           1 :   request_keys (exchange);
     794           1 :   return GNUNET_TIME_UNIT_ZERO_ABS;
     795             : }
     796             : 
     797             : 
     798             : /**
     799             :  * Callback used when downloading the reply to a /keys request
     800             :  * is complete.
     801             :  *
     802             :  * @param cls the `struct KeysRequest`
     803             :  * @param response_code HTTP response code, 0 on error
     804             :  * @param resp_obj parsed JSON result, NULL on error
     805             :  */
     806             : static void
     807           3 : keys_completed_cb (void *cls,
     808             :                    long response_code,
     809             :                    const json_t *resp_obj)
     810             : {
     811           3 :   struct KeysRequest *kr = cls;
     812           3 :   struct TALER_EXCHANGE_Handle *exchange = kr->exchange;
     813             :   struct TALER_EXCHANGE_Keys kd;
     814             :   struct TALER_EXCHANGE_Keys kd_old;
     815             :   enum TALER_EXCHANGE_VersionCompatibility vc;
     816             : 
     817           3 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     818             :               "Received keys from URL `%s' with status %ld.\n",
     819             :               kr->url,
     820             :               response_code);
     821           3 :   kd_old = exchange->key_data;
     822           3 :   memset (&kd,
     823             :           0,
     824             :           sizeof (struct TALER_EXCHANGE_Keys));
     825           3 :   vc = TALER_EXCHANGE_VC_PROTOCOL_ERROR;
     826           3 :   switch (response_code)
     827             :   {
     828             :   case 0:
     829           0 :     break;
     830             :   case MHD_HTTP_OK:
     831           3 :     if (NULL == resp_obj)
     832             :     {
     833           0 :       response_code = 0;
     834           0 :       break;
     835             :     }
     836             :     /* We keep the denomination keys and auditor signatures from the
     837             :        previous iteration (/keys cherry picking) */
     838           3 :     kd.num_denom_keys = kd_old.num_denom_keys;
     839           3 :     GNUNET_array_grow (kd.denom_keys,
     840             :                        kd.denom_keys_size,
     841             :                        kd.num_denom_keys);
     842             :     /* First make a shallow copy, we then need another pass for the RSA key... */
     843           6 :     memcpy (kd.denom_keys,
     844           3 :             kd_old.denom_keys,
     845           3 :             kd_old.num_denom_keys * sizeof (struct TALER_EXCHANGE_DenomPublicKey));
     846           7 :     for (unsigned int i=0;i<kd_old.num_denom_keys;i++)
     847           4 :       kd.denom_keys[i].key.rsa_public_key
     848           4 :         = GNUNET_CRYPTO_rsa_public_key_dup (kd_old.denom_keys[i].key.rsa_public_key);
     849             : 
     850           3 :     kd.num_auditors = kd_old.num_auditors;
     851           3 :     kd.auditors = GNUNET_new_array (kd.num_auditors,
     852             :                                     struct TALER_EXCHANGE_AuditorInformation);
     853             :     /* Now the necessary deep copy... */
     854           4 :     for (unsigned int i=0;i<kd_old.num_auditors;i++)
     855             :     {
     856           1 :       const struct TALER_EXCHANGE_AuditorInformation *aold = &kd_old.auditors[i];
     857           1 :       struct TALER_EXCHANGE_AuditorInformation *anew = &kd.auditors[i];
     858             : 
     859           1 :       anew->auditor_pub = aold->auditor_pub;
     860           1 :       anew->auditor_url = GNUNET_strdup (aold->auditor_url);
     861           1 :       GNUNET_array_grow (anew->denom_keys,
     862             :                          anew->num_denom_keys,
     863             :                          aold->num_denom_keys);
     864           5 :       for (unsigned int j=0;j<aold->num_denom_keys;j++)
     865             :       {
     866             :         /* offsets will map 1:1 */
     867           4 :         unsigned int off = aold->denom_keys[j] - kd_old.denom_keys;
     868             : 
     869           4 :         GNUNET_assert (off < kd_old.num_denom_keys);
     870           4 :         anew->denom_keys[j] = &kd.denom_keys[off];
     871             :       }
     872             :     }
     873             : 
     874           3 :     if (GNUNET_OK !=
     875           3 :         decode_keys_json (resp_obj,
     876             :                           &kd,
     877             :                           &vc))
     878             :     {
     879           0 :       response_code = 0;
     880           0 :       break;
     881             :     }
     882           3 :     json_decref (exchange->key_data_raw);
     883           3 :     exchange->key_data_raw = json_deep_copy (resp_obj);
     884           3 :     break;
     885             :   default:
     886           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     887             :                 "Unexpected response code %u\n",
     888             :                 (unsigned int) response_code);
     889           0 :     break;
     890             :   }
     891           3 :   exchange->key_data = kd;
     892             : 
     893           3 :   if (MHD_HTTP_OK != response_code)
     894             :   {
     895           0 :     exchange->kr = NULL;
     896           0 :     free_keys_request (kr);
     897           0 :     exchange->state = MHS_FAILED;
     898             :     /* notify application that we failed */
     899           0 :     exchange->cert_cb (exchange->cert_cb_cls,
     900             :                        NULL,
     901             :                        vc);
     902           0 :     if (NULL != exchange->key_data_raw)
     903             :       {
     904           0 :         json_decref (exchange->key_data_raw);
     905           0 :         exchange->key_data_raw = NULL;
     906             :       }
     907           0 :     free_key_data (&kd_old);
     908           0 :     return;
     909             :   }
     910             : 
     911           3 :   exchange->kr = NULL;
     912           3 :   exchange->key_data_expiration = kr->expire;
     913           3 :   free_keys_request (kr);
     914           3 :   exchange->state = MHS_CERT;
     915             :   /* notify application about the key information */
     916           6 :   exchange->cert_cb (exchange->cert_cb_cls,
     917           3 :                      &exchange->key_data,
     918             :                      vc);
     919           3 :   free_key_data (&kd_old);
     920             : }
     921             : 
     922             : 
     923             : /* ********************* library internal API ********* */
     924             : 
     925             : 
     926             : /**
     927             :  * Get the context of a exchange.
     928             :  *
     929             :  * @param h the exchange handle to query
     930             :  * @return ctx context to execute jobs in
     931             :  */
     932             : struct GNUNET_CURL_Context *
     933          46 : MAH_handle_to_context (struct TALER_EXCHANGE_Handle *h)
     934             : {
     935          46 :   return h->ctx;
     936             : }
     937             : 
     938             : 
     939             : /**
     940             :  * Check if the handle is ready to process requests.
     941             :  *
     942             :  * @param h the exchange handle to query
     943             :  * @return #GNUNET_YES if we are ready, #GNUNET_NO if not
     944             :  */
     945             : int
     946          41 : MAH_handle_is_ready (struct TALER_EXCHANGE_Handle *h)
     947             : {
     948          41 :   return (MHS_CERT == h->state) ? GNUNET_YES : GNUNET_NO;
     949             : }
     950             : 
     951             : 
     952             : /**
     953             :  * Obtain the URL to use for an API request.
     954             :  *
     955             :  * @param h handle for the exchange
     956             :  * @param path Taler API path (i.e. "/reserve/withdraw")
     957             :  * @return the full URI to use with cURL
     958             :  */
     959             : char *
     960          43 : MAH_path_to_url (struct TALER_EXCHANGE_Handle *h,
     961             :                  const char *path)
     962             : {
     963          43 :   return MAH_path_to_url2 (h->url,
     964             :                            path);
     965             : }
     966             : 
     967             : 
     968             : /**
     969             :  * Obtain the URL to use for an API request.
     970             :  *
     971             :  * @param base_url base URL of the exchange (i.e. "http://exchange/")
     972             :  * @param path Taler API path (i.e. "/reserve/withdraw")
     973             :  * @return the full URI to use with cURL
     974             :  */
     975             : char *
     976          49 : MAH_path_to_url2 (const char *base_url,
     977             :                   const char *path)
     978             : {
     979             :   char *url;
     980             : 
     981          98 :   if ( ('/' == path[0]) &&
     982          98 :        (0 < strlen (base_url)) &&
     983          49 :        ('/' == base_url[strlen (base_url) - 1]) )
     984           6 :     path++; /* avoid generating URL with "//" from concat */
     985          49 :   GNUNET_asprintf (&url,
     986             :                    "%s%s",
     987             :                    base_url,
     988             :                    path);
     989          49 :   return url;
     990             : }
     991             : 
     992             : 
     993             : /**
     994             :  * Parse HTTP timestamp.
     995             :  *
     996             :  * @param date header to parse header
     997             :  * @param at where to write the result
     998             :  * @return #GNUNET_OK on success
     999             :  */
    1000             : static int
    1001           3 : parse_date_string (const char *date,
    1002             :                    struct GNUNET_TIME_Absolute *at)
    1003             : {
    1004             :   struct tm now;
    1005             :   time_t t;
    1006             :   const char *end;
    1007             : 
    1008           3 :   memset (&now,
    1009             :           0,
    1010             :           sizeof (now));
    1011           3 :   end = strptime (date,
    1012             :                   "%a, %d %b %Y %H:%M:%S %Z", /* RFC-1123 standard spec */
    1013             :                   &now);
    1014           6 :   if ( (NULL == end) ||
    1015           6 :        ( (*end != '\n') &&
    1016           3 :          (*end != '\r') ) )
    1017             :   {
    1018           0 :     GNUNET_break_op (0);
    1019           0 :     return GNUNET_SYSERR;
    1020             :   }
    1021           3 :   t = mktime (&now);
    1022           3 :   if (((time_t) -1) == t)
    1023             :   {
    1024           0 :     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
    1025             :                          "mktime");
    1026           0 :     return GNUNET_SYSERR;
    1027             :   }
    1028           3 :   if (t < 0)
    1029           0 :     t = 0; /* can happen due to timezone issues if date was 1.1.1970 */
    1030           3 :   at->abs_value_us = 1000LL * 1000LL * t;
    1031           3 :   return GNUNET_OK;
    1032             : }
    1033             : 
    1034             : 
    1035             : /**
    1036             :  * Function called for each header in the HTTP /keys response.
    1037             :  * Finds the "Expire:" header and parses it, storing the result
    1038             :  * in the "expire" field fo the keys request.
    1039             :  *
    1040             :  * @param buffer header data received
    1041             :  * @param size size of an item in @a buffer
    1042             :  * @param nitems number of items in @a buffer
    1043             :  * @param userdata the `struct KeysRequest`
    1044             :  * @return `size * nitems` on success (everything else aborts)
    1045             :  */
    1046             : static size_t
    1047          24 : header_cb (char *buffer,
    1048             :            size_t size,
    1049             :            size_t nitems,
    1050             :            void *userdata)
    1051             : {
    1052          24 :   struct KeysRequest *kr = userdata;
    1053          24 :   size_t total = size * nitems;
    1054             :   char *val;
    1055             : 
    1056          24 :   if (total < strlen (MHD_HTTP_HEADER_EXPIRES ": "))
    1057           3 :     return total;
    1058          21 :   if (0 != strncasecmp (MHD_HTTP_HEADER_EXPIRES ": ",
    1059             :                         buffer,
    1060             :                         strlen (MHD_HTTP_HEADER_EXPIRES ": ")))
    1061          18 :     return total;
    1062           3 :   val = GNUNET_strndup (&buffer[strlen (MHD_HTTP_HEADER_EXPIRES ": ")],
    1063             :                         total - strlen (MHD_HTTP_HEADER_EXPIRES ": "));
    1064           3 :   if (GNUNET_OK !=
    1065           3 :       parse_date_string (val,
    1066             :                          &kr->expire))
    1067             :   {
    1068           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1069             :                 "Failed to parse %s-header `%s'\n",
    1070             :                 MHD_HTTP_HEADER_EXPIRES,
    1071             :                 val);
    1072           0 :     kr->expire = GNUNET_TIME_UNIT_ZERO_ABS;
    1073             :   }
    1074           3 :   GNUNET_free (val);
    1075           3 :   return total;
    1076             : }
    1077             : 
    1078             : /* ********************* public API ******************* */
    1079             : 
    1080             : /**
    1081             :  * Initialise a connection to the exchange. Will connect to the
    1082             :  * exchange and obtain information about the exchange's master public
    1083             :  * key and the exchange's auditor.  The respective information will
    1084             :  * be passed to the @a cert_cb once available, and all future
    1085             :  * interactions with the exchange will be checked to be signed
    1086             :  * (where appropriate) by the respective master key.
    1087             :  *
    1088             :  * @param ctx the context
    1089             :  * @param url HTTP base URL for the exchange
    1090             :  * @param cert_cb function to call with the exchange's certification information
    1091             :  * @param cert_cb_cls closure for @a cert_cb
    1092             :  * @param ... list of additional arguments, terminated by #TALER_EXCHANGE_OPTION_END.
    1093             :  * @return the exchange handle; NULL upon error
    1094             :  */
    1095             : struct TALER_EXCHANGE_Handle *
    1096           2 : TALER_EXCHANGE_connect (struct GNUNET_CURL_Context *ctx,
    1097             :                         const char *url,
    1098             :                         TALER_EXCHANGE_CertificationCallback cert_cb,
    1099             :                         void *cert_cb_cls,
    1100             :                         ...)
    1101             : {
    1102             :   struct TALER_EXCHANGE_Handle *exchange;
    1103             : 
    1104           2 :   exchange = GNUNET_new (struct TALER_EXCHANGE_Handle);
    1105           2 :   exchange->ctx = ctx;
    1106           2 :   exchange->url = GNUNET_strdup (url);
    1107           2 :   exchange->cert_cb = cert_cb;
    1108           2 :   exchange->cert_cb_cls = cert_cb_cls;
    1109           2 :   request_keys (exchange);
    1110           2 :   return exchange;
    1111             : }
    1112             : 
    1113             : 
    1114             : /**
    1115             :  * Initiate download of /keys from the exchange.
    1116             :  *
    1117             :  * @param exchange where to download /keys from
    1118             :  */
    1119             : static void
    1120           3 : request_keys (struct TALER_EXCHANGE_Handle *exchange)
    1121             : {
    1122             :   struct KeysRequest *kr;
    1123             :   CURL *eh;
    1124             : 
    1125           3 :   GNUNET_assert (NULL == exchange->kr);
    1126           3 :   kr = GNUNET_new (struct KeysRequest);
    1127           3 :   kr->exchange = exchange;
    1128           3 :   if (GNUNET_YES == MAH_handle_is_ready (exchange))
    1129             :   {
    1130             :     char *arg;
    1131             : 
    1132           1 :     GNUNET_asprintf (&arg,
    1133             :                      "/keys?last_issue_date=%llu",
    1134           1 :                      (unsigned long long) exchange->key_data.last_denom_issue_date.abs_value_us / 1000000LLU);
    1135           1 :     kr->url = MAH_path_to_url (exchange,
    1136             :                                arg);
    1137           1 :     GNUNET_free (arg);
    1138             :   }
    1139             :   else
    1140             :   {
    1141           2 :     kr->url = MAH_path_to_url (exchange,
    1142             :                                "/keys");
    1143             :   }
    1144           3 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1145             :               "Requesting keys with URL `%s'.\n",
    1146             :               kr->url);
    1147           3 :   eh = curl_easy_init ();
    1148           3 :   GNUNET_assert (CURLE_OK ==
    1149             :                  curl_easy_setopt (eh,
    1150             :                                    CURLOPT_VERBOSE,
    1151             :                                    0));
    1152           3 :   GNUNET_assert (CURLE_OK ==
    1153             :                  curl_easy_setopt (eh,
    1154             :                                    CURLOPT_TIMEOUT,
    1155             :                                    (long) 300));
    1156           3 :   GNUNET_assert (CURLE_OK ==
    1157             :                  curl_easy_setopt (eh,
    1158             :                                    CURLOPT_HEADERFUNCTION,
    1159             :                                    &header_cb));
    1160           3 :   GNUNET_assert (CURLE_OK ==
    1161             :                  curl_easy_setopt (eh,
    1162             :                                    CURLOPT_HEADERDATA,
    1163             :                                    kr));
    1164           3 :   GNUNET_assert (CURLE_OK ==
    1165             :                  curl_easy_setopt (eh,
    1166             :                                    CURLOPT_URL,
    1167             :                                    kr->url));
    1168           3 :   kr->job = GNUNET_CURL_job_add (exchange->ctx,
    1169             :                                  eh,
    1170             :                                  GNUNET_NO,
    1171             :                                  &keys_completed_cb,
    1172             :                                  kr);
    1173           3 :   exchange->kr = kr;
    1174           3 : }
    1175             : 
    1176             : 
    1177             : /**
    1178             :  * Disconnect from the exchange
    1179             :  *
    1180             :  * @param exchange the exchange handle
    1181             :  */
    1182             : void
    1183           2 : TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange)
    1184             : {
    1185           2 :   if (NULL != exchange->kr)
    1186             :   {
    1187           0 :     GNUNET_CURL_job_cancel (exchange->kr->job);
    1188           0 :     free_keys_request (exchange->kr);
    1189           0 :     exchange->kr = NULL;
    1190             :   }
    1191           2 :   free_key_data (&exchange->key_data);
    1192           2 :   if (NULL != exchange->key_data_raw)
    1193             :   {
    1194           2 :     json_decref (exchange->key_data_raw);
    1195           2 :     exchange->key_data_raw = NULL;
    1196             :   }
    1197           2 :   GNUNET_free (exchange->url);
    1198           2 :   GNUNET_free (exchange);
    1199           2 : }
    1200             : 
    1201             : 
    1202             : /**
    1203             :  * Test if the given @a pub is a the current signing key from the exchange
    1204             :  * according to @a keys.
    1205             :  *
    1206             :  * @param keys the exchange's key set
    1207             :  * @param pub claimed current online signing key for the exchange
    1208             :  * @return #GNUNET_OK if @a pub is (according to /keys) a current signing key
    1209             :  */
    1210             : int
    1211          20 : TALER_EXCHANGE_test_signing_key (const struct TALER_EXCHANGE_Keys *keys,
    1212             :                                  const struct TALER_ExchangePublicKeyP *pub)
    1213             : {
    1214             :   struct GNUNET_TIME_Absolute now;
    1215             : 
    1216             :   /* we will check using a tolerance of 1h for the time */
    1217          20 :   now = GNUNET_TIME_absolute_get ();
    1218          20 :   for (unsigned int i=0;i<keys->num_sign_keys;i++)
    1219          40 :     if ( (keys->sign_keys[i].valid_from.abs_value_us <= now.abs_value_us + 60 * 60 * 1000LL * 1000LL) &&
    1220          40 :          (keys->sign_keys[i].valid_until.abs_value_us > now.abs_value_us - 60 * 60 * 1000LL * 1000LL) &&
    1221          20 :          (0 == memcmp (pub,
    1222          20 :                        &keys->sign_keys[i].key,
    1223             :                        sizeof (struct TALER_ExchangePublicKeyP))) )
    1224          20 :       return GNUNET_OK;
    1225           0 :   return GNUNET_SYSERR;
    1226             : }
    1227             : 
    1228             : 
    1229             : /**
    1230             :  * Obtain the denomination key details from the exchange.
    1231             :  *
    1232             :  * @param keys the exchange's key set
    1233             :  * @param pk public key of the denomination to lookup
    1234             :  * @return details about the given denomination key, NULL if the key is
    1235             :  * not found
    1236             :  */
    1237             : const struct TALER_EXCHANGE_DenomPublicKey *
    1238          12 : TALER_EXCHANGE_get_denomination_key (const struct TALER_EXCHANGE_Keys *keys,
    1239             :                                      const struct TALER_DenominationPublicKey *pk)
    1240             : {
    1241          31 :   for (unsigned int i=0;i<keys->num_denom_keys;i++)
    1242          31 :     if (0 == GNUNET_CRYPTO_rsa_public_key_cmp (pk->rsa_public_key,
    1243          31 :                                                keys->denom_keys[i].key.rsa_public_key))
    1244          12 :       return &keys->denom_keys[i];
    1245           0 :   return NULL;
    1246             : }
    1247             : 
    1248             : 
    1249             : /**
    1250             :  * Obtain the denomination key details from the exchange.
    1251             :  *
    1252             :  * @param keys the exchange's key set
    1253             :  * @param hc hash of the public key of the denomination to lookup
    1254             :  * @return details about the given denomination key
    1255             :  */
    1256             : const struct TALER_EXCHANGE_DenomPublicKey *
    1257           0 : TALER_EXCHANGE_get_denomination_key_by_hash (const struct TALER_EXCHANGE_Keys *keys,
    1258             :                                              const struct GNUNET_HashCode *hc)
    1259             : {
    1260           0 :   for (unsigned int i=0;i<keys->num_denom_keys;i++)
    1261           0 :     if (0 == memcmp (hc,
    1262           0 :                      &keys->denom_keys[i].h_key,
    1263             :                      sizeof (struct GNUNET_HashCode)))
    1264           0 :       return &keys->denom_keys[i];
    1265           0 :   return NULL;
    1266             : }
    1267             : 
    1268             : 
    1269             : /**
    1270             :  * Obtain the keys from the exchange.
    1271             :  *
    1272             :  * @param exchange the exchange handle
    1273             :  * @return the exchange's key set
    1274             :  */
    1275             : const struct TALER_EXCHANGE_Keys *
    1276          37 : TALER_EXCHANGE_get_keys (struct TALER_EXCHANGE_Handle *exchange)
    1277             : {
    1278          37 :   (void) TALER_EXCHANGE_check_keys_current (exchange,
    1279             :                                             GNUNET_NO);
    1280          37 :   return &exchange->key_data;
    1281             : }
    1282             : 
    1283             : 
    1284             : /**
    1285             :  * Obtain the keys from the exchange in the
    1286             :  * raw JSON format
    1287             :  *
    1288             :  * @param exchange the exchange handle
    1289             :  * @return the exchange's keys in raw JSON
    1290             :  */
    1291             : json_t *
    1292           0 : TALER_EXCHANGE_get_keys_raw (struct TALER_EXCHANGE_Handle *exchange)
    1293             : {
    1294           0 :   (void) TALER_EXCHANGE_check_keys_current (exchange,
    1295             :                                             GNUNET_NO);
    1296           0 :   return json_deep_copy (exchange->key_data_raw);
    1297             : }
    1298             : 
    1299             : 
    1300             : /* end of exchange_api_handle.c */

Generated by: LCOV version 1.13