LCOV - code coverage report
Current view: top level - exchange-lib - exchange_api_handle.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 251 388 64.7 %
Date: 2017-09-17 17:24:28 Functions: 19 22 86.4 %

          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           0 : 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           0 :   struct GNUNET_JSON_Specification spec[] = {
     395           0 :     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           0 :   if (GNUNET_OK !=
     405           0 :       GNUNET_JSON_parse (auditor_obj,
     406             :                          spec,
     407             :                          NULL, NULL))
     408             :   {
     409           0 :     GNUNET_break_op (0);
     410           0 :     return GNUNET_SYSERR;
     411             :   }
     412           0 :   auditor->auditor_url = GNUNET_strdup (auditor_url);
     413           0 :   kv.purpose.purpose = htonl (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS);
     414           0 :   kv.purpose.size = htonl (sizeof (struct TALER_ExchangeKeyValidityPS));
     415           0 :   GNUNET_CRYPTO_hash (auditor_url,
     416           0 :                       strlen (auditor_url) + 1,
     417             :                       &kv.auditor_url_hash);
     418           0 :   kv.master = key_data->master_pub;
     419           0 :   len = json_array_size (keys);
     420           0 :   auditor->denom_keys = GNUNET_new_array (len,
     421             :                                           const struct TALER_EXCHANGE_DenomPublicKey *);
     422           0 :   i = 0;
     423           0 :   off = 0;
     424           0 :   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           0 :     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           0 :     if (GNUNET_OK !=
     437           0 :         GNUNET_JSON_parse (key,
     438             :                            kspec,
     439             :                            NULL, NULL))
     440             :     {
     441           0 :       GNUNET_break_op (0);
     442           0 :       continue;
     443             :     }
     444           0 :     dk = NULL;
     445           0 :     for (unsigned int j=0;j<key_data->num_denom_keys;j++)
     446             :     {
     447           0 :       if (0 == memcmp (&denom_h,
     448           0 :                        &key_data->denom_keys[j].h_key,
     449             :                        sizeof (struct GNUNET_HashCode)))
     450             :       {
     451           0 :         dk = &key_data->denom_keys[j];
     452           0 :         break;
     453             :       }
     454             :     }
     455           0 :     if (NULL == dk)
     456             :     {
     457           0 :       GNUNET_break_op (0);
     458           0 :       continue;
     459             :     }
     460           0 :     kv.start = GNUNET_TIME_absolute_hton (dk->valid_from);
     461           0 :     kv.expire_withdraw = GNUNET_TIME_absolute_hton (dk->withdraw_valid_until);
     462           0 :     kv.expire_deposit = GNUNET_TIME_absolute_hton (dk->expire_deposit);
     463           0 :     kv.expire_legal = GNUNET_TIME_absolute_hton (dk->expire_legal);
     464           0 :     TALER_amount_hton (&kv.value,
     465             :                        &dk->value);
     466           0 :     TALER_amount_hton (&kv.fee_withdraw,
     467             :                        &dk->fee_withdraw);
     468           0 :     TALER_amount_hton (&kv.fee_deposit,
     469             :                        &dk->fee_deposit);
     470           0 :     TALER_amount_hton (&kv.fee_refresh,
     471             :                        &dk->fee_refresh);
     472           0 :     TALER_amount_hton (&kv.fee_refund,
     473             :                        &dk->fee_refund);
     474           0 :     kv.denom_hash = dk->h_key;
     475           0 :     if (GNUNET_OK !=
     476           0 :         GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS,
     477             :                                     &kv.purpose,
     478             :                                     &auditor_sig.eddsa_sig,
     479           0 :                                     &auditor->auditor_pub.eddsa_pub))
     480             :     {
     481           0 :       GNUNET_break_op (0);
     482           0 :       GNUNET_JSON_parse_free (spec);
     483           0 :       return GNUNET_SYSERR;
     484             :     }
     485           0 :     auditor->denom_keys[off] = dk;
     486           0 :     off++;
     487             :   }
     488           0 :   auditor->num_denom_keys = off;
     489           0 :   GNUNET_JSON_parse_free (spec);
     490           0 :   return GNUNET_OK;
     491             : }
     492             : 
     493             : 
     494             : /**
     495             :  * Decode the JSON in @a resp_obj from the /keys response and store the data
     496             :  * in the @a key_data.
     497             :  *
     498             :  * @param[in] resp_obj JSON object to parse
     499             :  * @param[out] key_data where to store the results we decoded
     500             :  * @param[out] where to store version compatibility data
     501             :  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (malformed JSON)
     502             :  */
     503             : static int
     504           3 : decode_keys_json (const json_t *resp_obj,
     505             :                   struct TALER_EXCHANGE_Keys *key_data,
     506             :                   enum TALER_EXCHANGE_VersionCompatibility *vc)
     507             : {
     508             :   struct GNUNET_TIME_Absolute list_issue_date;
     509             :   struct GNUNET_TIME_Absolute last_denom_issue_date;
     510             :   struct TALER_ExchangeSignatureP sig;
     511             :   struct TALER_ExchangeKeySetPS ks;
     512             :   struct GNUNET_HashContext *hash_context;
     513             :   struct TALER_ExchangePublicKeyP pub;
     514             :   unsigned int age;
     515             :   unsigned int revision;
     516             :   unsigned int current;
     517             : 
     518           3 :   if (JSON_OBJECT != json_typeof (resp_obj))
     519           0 :     return GNUNET_SYSERR;
     520             : 
     521             :   /* check the version */
     522             :   {
     523             :     const char *ver;
     524           3 :     struct GNUNET_JSON_Specification spec[] = {
     525             :       GNUNET_JSON_spec_string ("version",
     526             :                                &ver),
     527             :       GNUNET_JSON_spec_end()
     528             :     };
     529             : 
     530           3 :     EXITIF (GNUNET_OK !=
     531             :             GNUNET_JSON_parse (resp_obj,
     532             :                                spec,
     533             :                                NULL, NULL));
     534           3 :     if (3 != sscanf (ver,
     535             :                      "%u:%u:%u",
     536             :                      &current,
     537             :                      &revision,
     538             :                      &age))
     539             :     {
     540           0 :       GNUNET_break_op (0);
     541           0 :       return GNUNET_SYSERR;
     542             :     }
     543           3 :     *vc = TALER_EXCHANGE_VC_MATCH;
     544           3 :     if (TALER_PROTOCOL_CURRENT < current)
     545             :     {
     546           0 :       *vc |= TALER_EXCHANGE_VC_NEWER;
     547           0 :       if (TALER_PROTOCOL_CURRENT < current - age)
     548           0 :         *vc |= TALER_EXCHANGE_VC_INCOMPATIBLE;
     549             :     }
     550           3 :     if (TALER_PROTOCOL_CURRENT > current)
     551             :     {
     552           0 :       *vc |= TALER_EXCHANGE_VC_OLDER;
     553             :       if (TALER_PROTOCOL_CURRENT - TALER_PROTOCOL_AGE > current)
     554             :         *vc |= TALER_EXCHANGE_VC_INCOMPATIBLE;
     555             :     }
     556           3 :     key_data->version = GNUNET_strdup (ver);
     557             :   }
     558             : 
     559             :   /* parse the master public key and issue date of the response */
     560           3 :   hash_context = GNUNET_CRYPTO_hash_context_start ();
     561             :   {
     562           3 :     struct GNUNET_JSON_Specification spec[] = {
     563           3 :       GNUNET_JSON_spec_fixed_auto ("master_public_key",
     564             :                                    &key_data->master_pub),
     565             :       GNUNET_JSON_spec_fixed_auto ("eddsa_sig",
     566             :                                    &sig),
     567             :       GNUNET_JSON_spec_fixed_auto ("eddsa_pub",
     568             :                                    &pub),
     569             :       GNUNET_JSON_spec_absolute_time ("list_issue_date",
     570             :                                       &list_issue_date),
     571             :       GNUNET_JSON_spec_end()
     572             :     };
     573             : 
     574           3 :     EXITIF (GNUNET_OK !=
     575             :             GNUNET_JSON_parse (resp_obj,
     576             :                                spec,
     577             :                                NULL, NULL));
     578             :   }
     579             : 
     580             :   /* parse the signing keys */
     581             :   {
     582             :     json_t *sign_keys_array;
     583             :     json_t *sign_key_obj;
     584             :     unsigned int index;
     585             : 
     586           3 :     EXITIF (NULL == (sign_keys_array =
     587             :                      json_object_get (resp_obj,
     588             :                                       "signkeys")));
     589           3 :     EXITIF (JSON_ARRAY != json_typeof (sign_keys_array));
     590           3 :     EXITIF (0 == (key_data->num_sign_keys =
     591             :                   json_array_size (sign_keys_array)));
     592             :     key_data->sign_keys
     593           3 :       = GNUNET_new_array (key_data->num_sign_keys,
     594             :                           struct TALER_EXCHANGE_SigningPublicKey);
     595           3 :     index = 0;
     596           6 :     json_array_foreach (sign_keys_array, index, sign_key_obj) {
     597           3 :       EXITIF (GNUNET_SYSERR ==
     598             :               parse_json_signkey (&key_data->sign_keys[index],
     599             :                                   sign_key_obj,
     600             :                                   &key_data->master_pub));
     601             :     }
     602             :   }
     603             : 
     604             :   /* parse the denomination keys, merging with the
     605             :      possibly EXISTING array as required (/keys cherry picking) */
     606           3 :   last_denom_issue_date.abs_value_us = 0LLU;
     607             :   {
     608             :     json_t *denom_keys_array;
     609             :     json_t *denom_key_obj;
     610             :     unsigned int index;
     611             : 
     612           3 :     EXITIF (NULL == (denom_keys_array =
     613             :                      json_object_get (resp_obj, "denoms")));
     614           3 :     EXITIF (JSON_ARRAY != json_typeof (denom_keys_array));
     615             : 
     616           3 :     index = 0;
     617          16 :     json_array_foreach (denom_keys_array, index, denom_key_obj) {
     618             :       struct TALER_EXCHANGE_DenomPublicKey dk;
     619          13 :       bool found = false;
     620             : 
     621          13 :       EXITIF (GNUNET_SYSERR ==
     622             :               parse_json_denomkey (&dk,
     623             :                                    denom_key_obj,
     624             :                                    &key_data->master_pub,
     625             :                                    hash_context));
     626          51 :       for (unsigned int j=0;j<key_data->num_denom_keys;j++)
     627             :       {
     628          38 :         if (0 == memcmp (&dk,
     629          38 :                          &key_data->denom_keys[j],
     630             :                          sizeof (dk)))
     631             :         {
     632           0 :           found = true;
     633           0 :           break;
     634             :         }
     635             :       }
     636          13 :       if (found)
     637             :       {
     638             :         /* 0:0:0 did not support /keys cherry picking */
     639           0 :         GNUNET_break_op (0 == current);
     640           0 :         continue;
     641             :       }
     642          13 :       if (key_data->denom_keys_size == key_data->num_denom_keys)
     643           5 :         GNUNET_array_grow (key_data->denom_keys,
     644             :                            key_data->denom_keys_size,
     645             :                            key_data->denom_keys_size * 2 + 2);
     646          13 :       key_data->denom_keys[key_data->num_denom_keys++] = dk;
     647             : 
     648             :       /* Update "last_denom_issue_date" */
     649             :       last_denom_issue_date
     650          13 :         = GNUNET_TIME_absolute_max (last_denom_issue_date,
     651             :                                     dk.valid_from);
     652             :     };
     653             :   }
     654           3 :   key_data->last_denom_issue_date = last_denom_issue_date;
     655             : 
     656             :   /* parse the auditor information */
     657             :   {
     658             :     json_t *auditors_array;
     659             :     json_t *auditor_info;
     660             :     unsigned int index;
     661             : 
     662           3 :     EXITIF (NULL == (auditors_array =
     663             :                      json_object_get (resp_obj, "auditors")));
     664           3 :     EXITIF (JSON_ARRAY != json_typeof (auditors_array));
     665             : 
     666             :     /* Merge with the existing auditor information we have (/keys cherry picking) */
     667           3 :     index = 0;
     668           3 :     json_array_foreach (auditors_array, index, auditor_info) {
     669             :       struct TALER_EXCHANGE_AuditorInformation ai;
     670           0 :       bool found = false;
     671             : 
     672           0 :       EXITIF (GNUNET_SYSERR ==
     673             :               parse_json_auditor (&ai,
     674             :                                   auditor_info,
     675             :                                   key_data));
     676           0 :       for (unsigned int j=0;j<key_data->num_auditors;j++)
     677             :       {
     678           0 :         struct TALER_EXCHANGE_AuditorInformation *aix = &key_data->auditors[j];
     679           0 :         if (0 == memcmp (&ai.auditor_pub,
     680           0 :                          &aix->auditor_pub,
     681             :                          sizeof (struct TALER_AuditorPublicKeyP)))
     682             :         {
     683           0 :           found = true;
     684             :           /* Merge denomination key signatures of downloaded /keys into existing
     685             :              auditor information 'aix'. */
     686           0 :           GNUNET_array_grow (aix->denom_keys,
     687             :                              aix->num_denom_keys,
     688             :                              aix->num_denom_keys + ai.num_denom_keys);
     689           0 :           memcpy (&aix->denom_keys[aix->num_denom_keys - ai.num_denom_keys],
     690           0 :                   ai.denom_keys,
     691           0 :                   ai.num_denom_keys * sizeof (struct TALER_EXCHANGE_DenomPublicKey *));
     692           0 :           break;
     693             :         }
     694             :       }
     695           0 :       if (found)
     696           0 :         continue; /* we are done */
     697           0 :       if (key_data->auditors_size == key_data->num_auditors)
     698           0 :         GNUNET_array_grow (key_data->auditors,
     699             :                            key_data->auditors_size,
     700             :                            key_data->auditors_size * 2 + 2);
     701           0 :       key_data->auditors[key_data->num_auditors++] = ai;
     702             :     };
     703             :   }
     704             : 
     705             :   /* Validate signature... */
     706           3 :   ks.purpose.size = htonl (sizeof (ks));
     707           3 :   ks.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_KEY_SET);
     708           3 :   ks.list_issue_date = GNUNET_TIME_absolute_hton (list_issue_date);
     709           3 :   GNUNET_CRYPTO_hash_context_finish (hash_context,
     710             :                                      &ks.hc);
     711           3 :   hash_context = NULL;
     712           3 :   EXITIF (GNUNET_OK !=
     713             :           TALER_EXCHANGE_test_signing_key (key_data,
     714             :                                            &pub));
     715           3 :   EXITIF (GNUNET_OK !=
     716             :           GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_KEY_SET,
     717             :                                       &ks.purpose,
     718             :                                       &sig.eddsa_signature,
     719             :                                       &pub.eddsa_pub));
     720           3 :   return GNUNET_OK;
     721             :  EXITIF_exit:
     722             : 
     723           0 :   if (NULL != hash_context)
     724           0 :     GNUNET_CRYPTO_hash_context_abort (hash_context);
     725           0 :   return GNUNET_SYSERR;
     726             : }
     727             : 
     728             : 
     729             : /**
     730             :  * Free key data object.
     731             :  *
     732             :  * @param key_data data to free (pointer itself excluded)
     733             :  */
     734             : static void
     735           5 : free_key_data (struct TALER_EXCHANGE_Keys *key_data)
     736             : {
     737           5 :   GNUNET_array_grow (key_data->sign_keys,
     738             :                      key_data->num_sign_keys,
     739             :                      0);
     740          22 :   for (unsigned int i=0;i<key_data->num_denom_keys;i++)
     741          17 :     GNUNET_CRYPTO_rsa_public_key_free (key_data->denom_keys[i].key.rsa_public_key);
     742           5 :   GNUNET_array_grow (key_data->denom_keys,
     743             :                      key_data->denom_keys_size,
     744             :                      0);
     745           5 :   for (unsigned int i=0;i<key_data->num_auditors;i++)
     746             :   {
     747           0 :     GNUNET_array_grow (key_data->auditors[i].denom_keys,
     748             :                        key_data->auditors[i].num_denom_keys,
     749             :                        0);
     750           0 :     GNUNET_free (key_data->auditors[i].auditor_url);
     751             :   }
     752           5 :   GNUNET_array_grow (key_data->auditors,
     753             :                      key_data->auditors_size,
     754             :                      0);
     755           5 :   GNUNET_free_non_null (key_data->version);
     756           5 :   key_data->version = NULL;
     757           5 : }
     758             : 
     759             : 
     760             : /**
     761             :  * Initiate download of /keys from the exchange.
     762             :  *
     763             :  * @param exchange where to download /keys from
     764             :  */
     765             : static void
     766             : request_keys (struct TALER_EXCHANGE_Handle *exchange);
     767             : 
     768             : 
     769             : /**
     770             :  * Check if our current response for /keys is valid, and if
     771             :  * not trigger download.
     772             :  *
     773             :  * @param exchange exchange to check keys for
     774             :  * @param force_download #GNUNET_YES to force download even if /keys is still valid
     775             :  * @return until when the response is current, 0 if we are re-downloading
     776             :  */
     777             : struct GNUNET_TIME_Absolute
     778          38 : TALER_EXCHANGE_check_keys_current (struct TALER_EXCHANGE_Handle *exchange,
     779             :                                    int force_download)
     780             : {
     781          38 :   if (NULL != exchange->kr)
     782           0 :     return GNUNET_TIME_UNIT_ZERO_ABS;
     783          75 :   if ( (GNUNET_NO == force_download) &&
     784          37 :        (0 < GNUNET_TIME_absolute_get_remaining (exchange->key_data_expiration).rel_value_us) )
     785          37 :     return exchange->key_data_expiration;
     786           1 :   request_keys (exchange);
     787           1 :   return GNUNET_TIME_UNIT_ZERO_ABS;
     788             : }
     789             : 
     790             : 
     791             : /**
     792             :  * Callback used when downloading the reply to a /keys request
     793             :  * is complete.
     794             :  *
     795             :  * @param cls the `struct KeysRequest`
     796             :  * @param response_code HTTP response code, 0 on error
     797             :  * @param resp_obj parsed JSON result, NULL on error
     798             :  */
     799             : static void
     800           3 : keys_completed_cb (void *cls,
     801             :                    long response_code,
     802             :                    const json_t *resp_obj)
     803             : {
     804           3 :   struct KeysRequest *kr = cls;
     805           3 :   struct TALER_EXCHANGE_Handle *exchange = kr->exchange;
     806             :   struct TALER_EXCHANGE_Keys kd;
     807             :   struct TALER_EXCHANGE_Keys kd_old;
     808             :   enum TALER_EXCHANGE_VersionCompatibility vc;
     809             : 
     810           3 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     811             :               "Received keys from URL `%s' with status %ld.\n",
     812             :               kr->url,
     813             :               response_code);
     814           3 :   kd_old = exchange->key_data;
     815           3 :   memset (&kd,
     816             :           0,
     817             :           sizeof (struct TALER_EXCHANGE_Keys));
     818           3 :   vc = TALER_EXCHANGE_VC_PROTOCOL_ERROR;
     819           3 :   switch (response_code)
     820             :   {
     821             :   case 0:
     822           0 :     break;
     823             :   case MHD_HTTP_OK:
     824           3 :     if (NULL == resp_obj)
     825             :     {
     826           0 :       response_code = 0;
     827           0 :       break;
     828             :     }
     829             :     /* We keep the denomination keys and auditor signatures from the
     830             :        previous iteration (/keys cherry picking) */
     831           3 :     kd.num_denom_keys = kd_old.num_denom_keys;
     832           3 :     GNUNET_array_grow (kd.denom_keys,
     833             :                        kd.denom_keys_size,
     834             :                        kd.num_denom_keys);
     835             :     /* First make a shallow copy, we then need another pass for the RSA key... */
     836           6 :     memcpy (kd.denom_keys,
     837           3 :             kd_old.denom_keys,
     838           3 :             kd_old.num_denom_keys * sizeof (struct TALER_EXCHANGE_DenomPublicKey));
     839           7 :     for (unsigned int i=0;i<kd_old.num_denom_keys;i++)
     840           4 :       kd.denom_keys[i].key.rsa_public_key
     841           4 :         = GNUNET_CRYPTO_rsa_public_key_dup (kd_old.denom_keys[i].key.rsa_public_key);
     842             : 
     843           3 :     kd.num_auditors = kd_old.num_auditors;
     844           3 :     kd.auditors = GNUNET_new_array (kd.num_auditors,
     845             :                                     struct TALER_EXCHANGE_AuditorInformation);
     846             :     /* Now the necessary deep copy... */
     847           3 :     for (unsigned int i=0;i<kd_old.num_auditors;i++)
     848             :     {
     849           0 :       const struct TALER_EXCHANGE_AuditorInformation *aold = &kd_old.auditors[i];
     850           0 :       struct TALER_EXCHANGE_AuditorInformation *anew = &kd.auditors[i];
     851             : 
     852           0 :       anew->auditor_pub = aold->auditor_pub;
     853           0 :       anew->auditor_url = GNUNET_strdup (aold->auditor_url);
     854           0 :       GNUNET_array_grow (anew->denom_keys,
     855             :                          anew->num_denom_keys,
     856             :                          aold->num_denom_keys);
     857           0 :       for (unsigned int j=0;j<aold->num_denom_keys;j++)
     858             :       {
     859             :         /* offsets will map 1:1 */
     860           0 :         unsigned int off = aold->denom_keys[j] - kd_old.denom_keys;
     861             : 
     862           0 :         GNUNET_assert (off < kd_old.num_denom_keys);
     863           0 :         anew->denom_keys[j] = &kd.denom_keys[off];
     864             :       }
     865             :     }
     866             : 
     867           3 :     if (GNUNET_OK !=
     868           3 :         decode_keys_json (resp_obj,
     869             :                           &kd,
     870             :                           &vc))
     871             :     {
     872           0 :       response_code = 0;
     873           0 :       break;
     874             :     }
     875           3 :     json_decref (exchange->key_data_raw);
     876           3 :     exchange->key_data_raw = json_deep_copy (resp_obj);
     877           3 :     break;
     878             :   default:
     879           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     880             :                 "Unexpected response code %u\n",
     881             :                 (unsigned int) response_code);
     882           0 :     break;
     883             :   }
     884           3 :   exchange->key_data = kd;
     885             : 
     886           3 :   if (MHD_HTTP_OK != response_code)
     887             :   {
     888           0 :     exchange->kr = NULL;
     889           0 :     free_keys_request (kr);
     890           0 :     exchange->state = MHS_FAILED;
     891             :     /* notify application that we failed */
     892           0 :     exchange->cert_cb (exchange->cert_cb_cls,
     893             :                        NULL,
     894             :                        vc);
     895           0 :     if (NULL != exchange->key_data_raw)
     896             :       {
     897           0 :         json_decref (exchange->key_data_raw);
     898           0 :         exchange->key_data_raw = NULL;
     899             :       }
     900           0 :     free_key_data (&kd_old);
     901           0 :     return;
     902             :   }
     903             : 
     904           3 :   exchange->kr = NULL;
     905           3 :   exchange->key_data_expiration = kr->expire;
     906           3 :   free_keys_request (kr);
     907           3 :   exchange->state = MHS_CERT;
     908             :   /* notify application about the key information */
     909           6 :   exchange->cert_cb (exchange->cert_cb_cls,
     910           3 :                      &exchange->key_data,
     911             :                      vc);
     912           3 :   free_key_data (&kd_old);
     913             : }
     914             : 
     915             : 
     916             : /* ********************* library internal API ********* */
     917             : 
     918             : 
     919             : /**
     920             :  * Get the context of a exchange.
     921             :  *
     922             :  * @param h the exchange handle to query
     923             :  * @return ctx context to execute jobs in
     924             :  */
     925             : struct GNUNET_CURL_Context *
     926          46 : MAH_handle_to_context (struct TALER_EXCHANGE_Handle *h)
     927             : {
     928          46 :   return h->ctx;
     929             : }
     930             : 
     931             : 
     932             : /**
     933             :  * Check if the handle is ready to process requests.
     934             :  *
     935             :  * @param h the exchange handle to query
     936             :  * @return #GNUNET_YES if we are ready, #GNUNET_NO if not
     937             :  */
     938             : int
     939          41 : MAH_handle_is_ready (struct TALER_EXCHANGE_Handle *h)
     940             : {
     941          41 :   return (MHS_CERT == h->state) ? GNUNET_YES : GNUNET_NO;
     942             : }
     943             : 
     944             : 
     945             : /**
     946             :  * Obtain the URL to use for an API request.
     947             :  *
     948             :  * @param h handle for the exchange
     949             :  * @param path Taler API path (i.e. "/reserve/withdraw")
     950             :  * @return the full URI to use with cURL
     951             :  */
     952             : char *
     953          43 : MAH_path_to_url (struct TALER_EXCHANGE_Handle *h,
     954             :                  const char *path)
     955             : {
     956          43 :   return MAH_path_to_url2 (h->url,
     957             :                            path);
     958             : }
     959             : 
     960             : 
     961             : /**
     962             :  * Obtain the URL to use for an API request.
     963             :  *
     964             :  * @param base_url base URL of the exchange (i.e. "http://exchange/")
     965             :  * @param path Taler API path (i.e. "/reserve/withdraw")
     966             :  * @return the full URI to use with cURL
     967             :  */
     968             : char *
     969          49 : MAH_path_to_url2 (const char *base_url,
     970             :                   const char *path)
     971             : {
     972             :   char *url;
     973             : 
     974          98 :   if ( ('/' == path[0]) &&
     975          98 :        (0 < strlen (base_url)) &&
     976          49 :        ('/' == base_url[strlen (base_url) - 1]) )
     977           6 :     path++; /* avoid generating URL with "//" from concat */
     978          49 :   GNUNET_asprintf (&url,
     979             :                    "%s%s",
     980             :                    base_url,
     981             :                    path);
     982          49 :   return url;
     983             : }
     984             : 
     985             : 
     986             : /**
     987             :  * Parse HTTP timestamp.
     988             :  *
     989             :  * @param date header to parse header
     990             :  * @param at where to write the result
     991             :  * @return #GNUNET_OK on success
     992             :  */
     993             : static int
     994           3 : parse_date_string (const char *date,
     995             :                    struct GNUNET_TIME_Absolute *at)
     996             : {
     997             :   static const char *const days[] =
     998             :     { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
     999             :   static const char *const mons[] =
    1000             :     { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    1001             :       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"  };
    1002             :   struct tm now;
    1003             :   time_t t;
    1004             :   char day[4];
    1005             :   char mon[4];
    1006             :   unsigned int mday;
    1007             :   unsigned int year;
    1008             :   unsigned int h;
    1009             :   unsigned int m;
    1010             :   unsigned int s;
    1011             : 
    1012           3 :   if (7 != sscanf (date,
    1013             :                    "%3s, %02u %3s %04u %02u:%02u:%02u GMT",
    1014             :                    day,
    1015             :                    &mday,
    1016             :                    mon,
    1017             :                    &year,
    1018             :                    &h,
    1019             :                    &m,
    1020             :                    &s))
    1021           0 :     return GNUNET_SYSERR;
    1022           3 :   memset (&now, 0, sizeof (now));
    1023           3 :   now.tm_year = year - 1900;
    1024           3 :   now.tm_mday = mday;
    1025           3 :   now.tm_hour = h;
    1026           3 :   now.tm_min = m;
    1027           3 :   now.tm_sec = s;
    1028           3 :   now.tm_wday = 7;
    1029          24 :   for (unsigned int i=0;i<7;i++)
    1030          21 :     if (0 == strcasecmp (days[i], day))
    1031           3 :       now.tm_wday = i;
    1032           3 :   now.tm_mon = 12;
    1033          39 :   for (unsigned int i=0;i<12;i++)
    1034          36 :     if (0 == strcasecmp (mons[i], mon))
    1035           3 :       now.tm_mon = i;
    1036           6 :   if ( (7 == now.tm_wday) ||
    1037           3 :        (12 == now.tm_mon) )
    1038           0 :     return GNUNET_SYSERR;
    1039           3 :   t = mktime (&now);
    1040           3 :   at->abs_value_us = 1000LL * 1000LL * t;
    1041           3 :   return GNUNET_OK;
    1042             : }
    1043             : 
    1044             : 
    1045             : /**
    1046             :  * Function called for each header in the HTTP /keys response.
    1047             :  * Finds the "Expire:" header and parses it, storing the result
    1048             :  * in the "expire" field fo the keys request.
    1049             :  *
    1050             :  * @param buffer header data received
    1051             :  * @param size size of an item in @a buffer
    1052             :  * @param nitems number of items in @a buffer
    1053             :  * @param userdata the `struct KeysRequest`
    1054             :  * @return `size * nitems` on success (everything else aborts)
    1055             :  */
    1056             : static size_t
    1057          24 : header_cb (char *buffer,
    1058             :            size_t size,
    1059             :            size_t nitems,
    1060             :            void *userdata)
    1061             : {
    1062          24 :   struct KeysRequest *kr = userdata;
    1063          24 :   size_t total = size * nitems;
    1064             :   char *val;
    1065             : 
    1066          24 :   if (total < strlen (MHD_HTTP_HEADER_EXPIRES ": "))
    1067           3 :     return total;
    1068          21 :   if (0 != strncasecmp (MHD_HTTP_HEADER_EXPIRES ": ",
    1069             :                         buffer,
    1070             :                         strlen (MHD_HTTP_HEADER_EXPIRES ": ")))
    1071          18 :     return total;
    1072           3 :   val = GNUNET_strndup (&buffer[strlen (MHD_HTTP_HEADER_EXPIRES ": ")],
    1073             :                         total - strlen (MHD_HTTP_HEADER_EXPIRES ": "));
    1074           3 :   if (GNUNET_OK !=
    1075           3 :       parse_date_string (val,
    1076             :                          &kr->expire))
    1077             :   {
    1078           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1079             :                 "Failed to parse %s-header `%s'\n",
    1080             :                 MHD_HTTP_HEADER_EXPIRES,
    1081             :                 val);
    1082             :   }
    1083           3 :   GNUNET_free (val);
    1084           3 :   return total;
    1085             : }
    1086             : 
    1087             : /* ********************* public API ******************* */
    1088             : 
    1089             : /**
    1090             :  * Initialise a connection to the exchange. Will connect to the
    1091             :  * exchange and obtain information about the exchange's master public
    1092             :  * key and the exchange's auditor.  The respective information will
    1093             :  * be passed to the @a cert_cb once available, and all future
    1094             :  * interactions with the exchange will be checked to be signed
    1095             :  * (where appropriate) by the respective master key.
    1096             :  *
    1097             :  * @param ctx the context
    1098             :  * @param url HTTP base URL for the exchange
    1099             :  * @param cert_cb function to call with the exchange's certification information
    1100             :  * @param cert_cb_cls closure for @a cert_cb
    1101             :  * @param ... list of additional arguments, terminated by #TALER_EXCHANGE_OPTION_END.
    1102             :  * @return the exchange handle; NULL upon error
    1103             :  */
    1104             : struct TALER_EXCHANGE_Handle *
    1105           2 : TALER_EXCHANGE_connect (struct GNUNET_CURL_Context *ctx,
    1106             :                         const char *url,
    1107             :                         TALER_EXCHANGE_CertificationCallback cert_cb,
    1108             :                         void *cert_cb_cls,
    1109             :                         ...)
    1110             : {
    1111             :   struct TALER_EXCHANGE_Handle *exchange;
    1112             : 
    1113           2 :   exchange = GNUNET_new (struct TALER_EXCHANGE_Handle);
    1114           2 :   exchange->ctx = ctx;
    1115           2 :   exchange->url = GNUNET_strdup (url);
    1116           2 :   exchange->cert_cb = cert_cb;
    1117           2 :   exchange->cert_cb_cls = cert_cb_cls;
    1118           2 :   request_keys (exchange);
    1119           2 :   return exchange;
    1120             : }
    1121             : 
    1122             : 
    1123             : /**
    1124             :  * Initiate download of /keys from the exchange.
    1125             :  *
    1126             :  * @param exchange where to download /keys from
    1127             :  */
    1128             : static void
    1129           3 : request_keys (struct TALER_EXCHANGE_Handle *exchange)
    1130             : {
    1131             :   struct KeysRequest *kr;
    1132             :   CURL *eh;
    1133             : 
    1134           3 :   GNUNET_assert (NULL == exchange->kr);
    1135           3 :   kr = GNUNET_new (struct KeysRequest);
    1136           3 :   kr->exchange = exchange;
    1137           3 :   if (GNUNET_YES == MAH_handle_is_ready (exchange))
    1138             :   {
    1139             :     char *arg;
    1140             : 
    1141           1 :     GNUNET_asprintf (&arg,
    1142             :                      "/keys?last_issue_date=%llu",
    1143           1 :                      (unsigned long long) exchange->key_data.last_denom_issue_date.abs_value_us / 1000000LLU);
    1144           1 :     kr->url = MAH_path_to_url (exchange,
    1145             :                                arg);
    1146           1 :     GNUNET_free (arg);
    1147             :   }
    1148             :   else
    1149             :   {
    1150           2 :     kr->url = MAH_path_to_url (exchange,
    1151             :                                "/keys");
    1152             :   }
    1153           3 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    1154             :               "Requesting keys with URL `%s'.\n",
    1155             :               kr->url);
    1156           3 :   eh = curl_easy_init ();
    1157           3 :   GNUNET_assert (CURLE_OK ==
    1158             :                  curl_easy_setopt (eh,
    1159             :                                    CURLOPT_VERBOSE,
    1160             :                                    0));
    1161           3 :   GNUNET_assert (CURLE_OK ==
    1162             :                  curl_easy_setopt (eh,
    1163             :                                    CURLOPT_TIMEOUT,
    1164             :                                    (long) 300));
    1165           3 :   GNUNET_assert (CURLE_OK ==
    1166             :                  curl_easy_setopt (eh,
    1167             :                                    CURLOPT_HEADERFUNCTION,
    1168             :                                    &header_cb));
    1169           3 :   GNUNET_assert (CURLE_OK ==
    1170             :                  curl_easy_setopt (eh,
    1171             :                                    CURLOPT_HEADERDATA,
    1172             :                                    kr));
    1173           3 :   GNUNET_assert (CURLE_OK ==
    1174             :                  curl_easy_setopt (eh,
    1175             :                                    CURLOPT_URL,
    1176             :                                    kr->url));
    1177           3 :   kr->job = GNUNET_CURL_job_add (exchange->ctx,
    1178             :                                  eh,
    1179             :                                  GNUNET_NO,
    1180             :                                  &keys_completed_cb,
    1181             :                                  kr);
    1182           3 :   exchange->kr = kr;
    1183           3 : }
    1184             : 
    1185             : 
    1186             : /**
    1187             :  * Disconnect from the exchange
    1188             :  *
    1189             :  * @param exchange the exchange handle
    1190             :  */
    1191             : void
    1192           2 : TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange)
    1193             : {
    1194           2 :   if (NULL != exchange->kr)
    1195             :   {
    1196           0 :     GNUNET_CURL_job_cancel (exchange->kr->job);
    1197           0 :     free_keys_request (exchange->kr);
    1198           0 :     exchange->kr = NULL;
    1199             :   }
    1200           2 :   free_key_data (&exchange->key_data);
    1201           2 :   if (NULL != exchange->key_data_raw)
    1202             :   {
    1203           2 :     json_decref (exchange->key_data_raw);
    1204           2 :     exchange->key_data_raw = NULL;
    1205             :   }
    1206           2 :   GNUNET_free (exchange->url);
    1207           2 :   GNUNET_free (exchange);
    1208           2 : }
    1209             : 
    1210             : 
    1211             : /**
    1212             :  * Test if the given @a pub is a the current signing key from the exchange
    1213             :  * according to @a keys.
    1214             :  *
    1215             :  * @param keys the exchange's key set
    1216             :  * @param pub claimed current online signing key for the exchange
    1217             :  * @return #GNUNET_OK if @a pub is (according to /keys) a current signing key
    1218             :  */
    1219             : int
    1220          20 : TALER_EXCHANGE_test_signing_key (const struct TALER_EXCHANGE_Keys *keys,
    1221             :                                  const struct TALER_ExchangePublicKeyP *pub)
    1222             : {
    1223             :   struct GNUNET_TIME_Absolute now;
    1224             : 
    1225             :   /* we will check using a tolerance of 1h for the time */
    1226          20 :   now = GNUNET_TIME_absolute_get ();
    1227          20 :   for (unsigned int i=0;i<keys->num_sign_keys;i++)
    1228          40 :     if ( (keys->sign_keys[i].valid_from.abs_value_us <= now.abs_value_us + 60 * 60 * 1000LL * 1000LL) &&
    1229          40 :          (keys->sign_keys[i].valid_until.abs_value_us > now.abs_value_us - 60 * 60 * 1000LL * 1000LL) &&
    1230          20 :          (0 == memcmp (pub,
    1231          20 :                        &keys->sign_keys[i].key,
    1232             :                        sizeof (struct TALER_ExchangePublicKeyP))) )
    1233          20 :       return GNUNET_OK;
    1234           0 :   return GNUNET_SYSERR;
    1235             : }
    1236             : 
    1237             : 
    1238             : /**
    1239             :  * Obtain the denomination key details from the exchange.
    1240             :  *
    1241             :  * @param keys the exchange's key set
    1242             :  * @param pk public key of the denomination to lookup
    1243             :  * @return details about the given denomination key, NULL if the key is
    1244             :  * not found
    1245             :  */
    1246             : const struct TALER_EXCHANGE_DenomPublicKey *
    1247          12 : TALER_EXCHANGE_get_denomination_key (const struct TALER_EXCHANGE_Keys *keys,
    1248             :                                      const struct TALER_DenominationPublicKey *pk)
    1249             : {
    1250          53 :   for (unsigned int i=0;i<keys->num_denom_keys;i++)
    1251          53 :     if (0 == GNUNET_CRYPTO_rsa_public_key_cmp (pk->rsa_public_key,
    1252          53 :                                                keys->denom_keys[i].key.rsa_public_key))
    1253          12 :       return &keys->denom_keys[i];
    1254           0 :   return NULL;
    1255             : }
    1256             : 
    1257             : 
    1258             : /**
    1259             :  * Obtain the denomination key details from the exchange.
    1260             :  *
    1261             :  * @param keys the exchange's key set
    1262             :  * @param hc hash of the public key of the denomination to lookup
    1263             :  * @return details about the given denomination key
    1264             :  */
    1265             : const struct TALER_EXCHANGE_DenomPublicKey *
    1266           0 : TALER_EXCHANGE_get_denomination_key_by_hash (const struct TALER_EXCHANGE_Keys *keys,
    1267             :                                              const struct GNUNET_HashCode *hc)
    1268             : {
    1269           0 :   for (unsigned int i=0;i<keys->num_denom_keys;i++)
    1270           0 :     if (0 == memcmp (hc,
    1271           0 :                      &keys->denom_keys[i].h_key,
    1272             :                      sizeof (struct GNUNET_HashCode)))
    1273           0 :       return &keys->denom_keys[i];
    1274           0 :   return NULL;
    1275             : }
    1276             : 
    1277             : 
    1278             : /**
    1279             :  * Obtain the keys from the exchange.
    1280             :  *
    1281             :  * @param exchange the exchange handle
    1282             :  * @return the exchange's key set
    1283             :  */
    1284             : const struct TALER_EXCHANGE_Keys *
    1285          37 : TALER_EXCHANGE_get_keys (struct TALER_EXCHANGE_Handle *exchange)
    1286             : {
    1287          37 :   (void) TALER_EXCHANGE_check_keys_current (exchange,
    1288             :                                             GNUNET_NO);
    1289          37 :   return &exchange->key_data;
    1290             : }
    1291             : 
    1292             : 
    1293             : /**
    1294             :  * Obtain the keys from the exchange in the
    1295             :  * raw JSON format
    1296             :  *
    1297             :  * @param exchange the exchange handle
    1298             :  * @return the exchange's keys in raw JSON
    1299             :  */
    1300             : json_t *
    1301           0 : TALER_EXCHANGE_get_keys_raw (struct TALER_EXCHANGE_Handle *exchange)
    1302             : {
    1303           0 :   (void) TALER_EXCHANGE_check_keys_current (exchange,
    1304             :                                             GNUNET_NO);
    1305           0 :   return json_deep_copy (exchange->key_data_raw);
    1306             : }
    1307             : 
    1308             : 
    1309             : /* end of exchange_api_handle.c */

Generated by: LCOV version 1.13