diff options
author | Christian Grothoff <christian@grothoff.org> | 2019-01-11 21:27:34 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2019-01-11 21:43:15 +0100 |
commit | 54fc83ee6b910d482948c6ec8185df7aab1b0cb1 (patch) | |
tree | 10c04cad1392659a9ccef469271f866e393ebb48 /src/exchange-lib/exchange_api_handle.c | |
parent | 57ab9f9fdba607fcc3817adf58f37c5390f8d220 (diff) |
fix cyclic dependency by combining exchange-lib and auditor-lib directories
Diffstat (limited to 'src/exchange-lib/exchange_api_handle.c')
-rw-r--r-- | src/exchange-lib/exchange_api_handle.c | 1779 |
1 files changed, 0 insertions, 1779 deletions
diff --git a/src/exchange-lib/exchange_api_handle.c b/src/exchange-lib/exchange_api_handle.c deleted file mode 100644 index afaabd85b..000000000 --- a/src/exchange-lib/exchange_api_handle.c +++ /dev/null @@ -1,1779 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2018 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - TALER is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with TALER; see the file COPYING. If not, see - <http://www.gnu.org/licenses/> -*/ - -/** - * @file exchange-lib/exchange_api_handle.c - * @brief Implementation of the "handle" component of the exchange's HTTP API - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - * @author Christian Grothoff - */ -#include "platform.h" -#include <microhttpd.h> -#include <gnunet/gnunet_curl_lib.h> -#include "taler_json_lib.h" -#include "taler_exchange_service.h" -#include "taler_auditor_service.h" -#include "taler_signatures.h" -#include "exchange_api_handle.h" -#include "curl_defaults.h" -#include "backoff.h" - -/** - * Which revision of the Taler protocol is implemented - * by this library? Used to determine compatibility. - */ -#define TALER_PROTOCOL_CURRENT 2 - -/** - * How many revisions back are we compatible to? - */ -#define TALER_PROTOCOL_AGE 0 - -/** - * Current version for (local) JSON serialization of persisted - * /keys data. - */ -#define TALER_SERIALIZATION_FORMAT_VERSION 0 - - -/** - * Log error related to CURL operations. - * - * @param type log level - * @param function which function failed to run - * @param code what was the curl error code - */ -#define CURL_STRERROR(type, function, code) \ - GNUNET_log (type, "Curl function `%s' has failed at `%s:%d' with error: %s", \ - function, __FILE__, __LINE__, curl_easy_strerror (code)); - -/** - * Stages of initialization for the `struct TALER_EXCHANGE_Handle` - */ -enum ExchangeHandleState -{ - /** - * Just allocated. - */ - MHS_INIT = 0, - - /** - * Obtained the exchange's certification data and keys. - */ - MHS_CERT = 1, - - /** - * Failed to initialize (fatal). - */ - MHS_FAILED = 2 -}; - - -/** - * Data for the request to get the /keys of a exchange. - */ -struct KeysRequest; - - -/** - * Entry in list of ongoing interactions with an auditor. - */ -struct AuditorInteractionEntry -{ - /** - * DLL entry. - */ - struct AuditorInteractionEntry *next; - - /** - * DLL entry. - */ - struct AuditorInteractionEntry *prev; - - /** - * Interaction state. - */ - struct TALER_AUDITOR_DepositConfirmationHandle *dch; -}; - - -/** - * Entry in DLL of auditors used by an exchange. - */ -struct AuditorListEntry -{ - /** - * Next pointer of DLL. - */ - struct AuditorListEntry *next; - - /** - * Prev pointer of DLL. - */ - struct AuditorListEntry *prev; - - /** - * Base URL of the auditor. - */ - const char *auditor_url; - - /** - * Handle to the auditor. - */ - struct TALER_AUDITOR_Handle *ah; - - /** - * Head of DLL of interactions with this auditor. - */ - struct AuditorInteractionEntry *ai_head; - - /** - * Tail of DLL of interactions with this auditor. - */ - struct AuditorInteractionEntry *ai_tail; - - /** - * Public key of the auditor. - */ - struct TALER_AuditorPublicKeyP auditor_pub; - - /** - * Flag indicating that the auditor is available and that protocol - * version compatibility is given. - */ - int is_up; - -}; - - -/** - * Handle to the exchange - */ -struct TALER_EXCHANGE_Handle -{ - /** - * The context of this handle - */ - struct GNUNET_CURL_Context *ctx; - - /** - * The URL of the exchange (i.e. "http://exchange.taler.net/") - */ - char *url; - - /** - * Function to call with the exchange's certification data, - * NULL if this has already been done. - */ - TALER_EXCHANGE_CertificationCallback cert_cb; - - /** - * Closure to pass to @e cert_cb. - */ - void *cert_cb_cls; - - /** - * Data for the request to get the /keys of a exchange, - * NULL once we are past stage #MHS_INIT. - */ - struct KeysRequest *kr; - - /** - * Task for retrying /keys request. - */ - struct GNUNET_SCHEDULER_Task *retry_task; - - /** - * Raw key data of the exchange, only valid if - * @e handshake_complete is past stage #MHS_CERT. - */ - json_t *key_data_raw; - - /** - * Head of DLL of auditors of this exchange. - */ - struct AuditorListEntry *auditors_head; - - /** - * Tail of DLL of auditors of this exchange. - */ - struct AuditorListEntry *auditors_tail; - - /** - * Key data of the exchange, only valid if - * @e handshake_complete is past stage #MHS_CERT. - */ - struct TALER_EXCHANGE_Keys key_data; - - /** - * Retry /keys frequency. - */ - struct GNUNET_TIME_Relative retry_delay; - - /** - * When does @e key_data expire? - */ - struct GNUNET_TIME_Absolute key_data_expiration; - - /** - * Stage of the exchange's initialization routines. - */ - enum ExchangeHandleState state; - -}; - - -/* ***************** Internal /keys fetching ************* */ - -/** - * Data for the request to get the /keys of a exchange. - */ -struct KeysRequest -{ - /** - * The connection to exchange this request handle will use - */ - struct TALER_EXCHANGE_Handle *exchange; - - /** - * The url for this handle - */ - char *url; - - /** - * Entry for this request with the `struct GNUNET_CURL_Context`. - */ - struct GNUNET_CURL_Job *job; - - /** - * Expiration time according to "Expire:" header. - * 0 if not provided by the server. - */ - struct GNUNET_TIME_Absolute expire; - -}; - - -/** - * Iterate over all available auditors for @a h, calling - * @param ah and giving it a chance to start a deposit - * confirmation interaction. - * - * @param h exchange to go over auditors for - * @param ac function to call per auditor - * @param ac_cls closure for @a ac - */ -void -TEAH_get_auditors_for_dc (struct TALER_EXCHANGE_Handle *h, - TEAH_AuditorCallback ac, - void *ac_cls) -{ - // FIXME! -} - - -/** - * Release memory occupied by a keys request. - * Note that this does not cancel the request - * itself. - * - * @param kr request to free - */ -static void -free_keys_request (struct KeysRequest *kr) -{ - GNUNET_free (kr->url); - GNUNET_free (kr); -} - - -#define EXITIF(cond) \ - do { \ - if (cond) { GNUNET_break (0); goto EXITIF_exit; } \ - } while (0) - - -/** - * Parse a exchange's signing key encoded in JSON. - * - * @param[out] sign_key where to return the result - * @param check_sigs should we check signatures? - * @param[in] sign_key_obj json to parse - * @param master_key master key to use to verify signature - * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is - * invalid or the json malformed. - */ -static int -parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key, - int check_sigs, - json_t *sign_key_obj, - const struct TALER_MasterPublicKeyP *master_key) -{ - struct TALER_ExchangeSigningKeyValidityPS sign_key_issue; - struct TALER_MasterSignatureP sign_key_issue_sig; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ("master_sig", - &sign_key_issue_sig), - GNUNET_JSON_spec_fixed_auto ("key", - &sign_key->key), - GNUNET_JSON_spec_absolute_time ("stamp_start", - &sign_key->valid_from), - GNUNET_JSON_spec_absolute_time ("stamp_expire", - &sign_key->valid_until), - GNUNET_JSON_spec_absolute_time ("stamp_end", - &sign_key->valid_legal), - GNUNET_JSON_spec_end() - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (sign_key_obj, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - if (! check_sigs) - return GNUNET_OK; - sign_key_issue.signkey_pub = sign_key->key; - sign_key_issue.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY); - sign_key_issue.purpose.size = htonl (sizeof (struct TALER_ExchangeSigningKeyValidityPS)); - sign_key_issue.master_public_key = *master_key; - sign_key_issue.start = GNUNET_TIME_absolute_hton (sign_key->valid_from); - sign_key_issue.expire = GNUNET_TIME_absolute_hton (sign_key->valid_until); - sign_key_issue.end = GNUNET_TIME_absolute_hton (sign_key->valid_legal); - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY, - &sign_key_issue.purpose, - &sign_key_issue_sig.eddsa_signature, - &master_key->eddsa_pub)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - sign_key->master_sig = sign_key_issue_sig; - return GNUNET_OK; -} - - -/** - * Parse a exchange's denomination key encoded in JSON. - * - * @param[out] denom_key where to return the result - * @param check_sigs should we check signatures? - * @param[in] denom_key_obj json to parse - * @param master_key master key to use to verify signature - * @param hash_context where to accumulate data for signature verification - * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is - * invalid or the json malformed. - */ -static int -parse_json_denomkey (struct TALER_EXCHANGE_DenomPublicKey *denom_key, - int check_sigs, - json_t *denom_key_obj, - struct TALER_MasterPublicKeyP *master_key, - struct GNUNET_HashContext *hash_context) -{ - struct TALER_DenominationKeyValidityPS denom_key_issue; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ("master_sig", - &denom_key->master_sig), - GNUNET_JSON_spec_absolute_time ("stamp_expire_deposit", - &denom_key->expire_deposit), - GNUNET_JSON_spec_absolute_time ("stamp_expire_withdraw", - &denom_key->withdraw_valid_until), - GNUNET_JSON_spec_absolute_time ("stamp_start", - &denom_key->valid_from), - GNUNET_JSON_spec_absolute_time ("stamp_expire_legal", - &denom_key->expire_legal), - TALER_JSON_spec_amount ("value", - &denom_key->value), - TALER_JSON_spec_amount ("fee_withdraw", - &denom_key->fee_withdraw), - TALER_JSON_spec_amount ("fee_deposit", - &denom_key->fee_deposit), - TALER_JSON_spec_amount ("fee_refresh", - &denom_key->fee_refresh), - TALER_JSON_spec_amount ("fee_refund", - &denom_key->fee_refund), - GNUNET_JSON_spec_rsa_public_key ("denom_pub", - &denom_key->key.rsa_public_key), - GNUNET_JSON_spec_end() - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (denom_key_obj, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - GNUNET_CRYPTO_rsa_public_key_hash (denom_key->key.rsa_public_key, - &denom_key->h_key); - if (! check_sigs) - return GNUNET_OK; - memset (&denom_key_issue, - 0, - sizeof (denom_key_issue)); - denom_key_issue.purpose.purpose - = htonl (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY); - denom_key_issue.purpose.size - = htonl (sizeof (struct TALER_DenominationKeyValidityPS)); - denom_key_issue.master = *master_key; - denom_key_issue.denom_hash = denom_key->h_key; - denom_key_issue.start = GNUNET_TIME_absolute_hton (denom_key->valid_from); - denom_key_issue.expire_withdraw = GNUNET_TIME_absolute_hton (denom_key->withdraw_valid_until); - denom_key_issue.expire_deposit = GNUNET_TIME_absolute_hton (denom_key->expire_deposit); - denom_key_issue.expire_legal = GNUNET_TIME_absolute_hton (denom_key->expire_legal); - TALER_amount_hton (&denom_key_issue.value, - &denom_key->value); - TALER_amount_hton (&denom_key_issue.fee_withdraw, - &denom_key->fee_withdraw); - TALER_amount_hton (&denom_key_issue.fee_deposit, - &denom_key->fee_deposit); - TALER_amount_hton (&denom_key_issue.fee_refresh, - &denom_key->fee_refresh); - TALER_amount_hton (&denom_key_issue.fee_refund, - &denom_key->fee_refund); - EXITIF (GNUNET_SYSERR == - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY, - &denom_key_issue.purpose, - &denom_key->master_sig.eddsa_signature, - &master_key->eddsa_pub)); - GNUNET_CRYPTO_hash_context_read (hash_context, - &denom_key_issue.denom_hash, - sizeof (struct GNUNET_HashCode)); - return GNUNET_OK; - - EXITIF_exit: - GNUNET_JSON_parse_free (spec); - return GNUNET_SYSERR; -} - - -/** - * Parse a exchange's auditor information encoded in JSON. - * - * @param[out] auditor where to return the result - * @param check_sig should we check signatures - * @param[in] auditor_obj json to parse - * @param key_data information about denomination keys - * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is - * invalid or the json malformed. - */ -static int -parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor, - int check_sigs, - json_t *auditor_obj, - const struct TALER_EXCHANGE_Keys *key_data) -{ - json_t *keys; - json_t *key; - unsigned int len; - unsigned int off; - unsigned int i; - const char *auditor_url; - struct TALER_ExchangeKeyValidityPS kv; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ("auditor_pub", - &auditor->auditor_pub), - GNUNET_JSON_spec_string ("auditor_url", - &auditor_url), - GNUNET_JSON_spec_json ("denomination_keys", - &keys), - GNUNET_JSON_spec_end() - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (auditor_obj, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - auditor->auditor_url = GNUNET_strdup (auditor_url); - kv.purpose.purpose = htonl (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS); - kv.purpose.size = htonl (sizeof (struct TALER_ExchangeKeyValidityPS)); - GNUNET_CRYPTO_hash (auditor_url, - strlen (auditor_url) + 1, - &kv.auditor_url_hash); - kv.master = key_data->master_pub; - len = json_array_size (keys); - auditor->denom_keys = GNUNET_new_array (len, - struct TALER_EXCHANGE_AuditorDenominationInfo); - i = 0; - off = 0; - json_array_foreach (keys, i, key) { - struct TALER_AuditorSignatureP auditor_sig; - struct GNUNET_HashCode denom_h; - const struct TALER_EXCHANGE_DenomPublicKey *dk; - unsigned int dk_off; - struct GNUNET_JSON_Specification kspec[] = { - GNUNET_JSON_spec_fixed_auto ("auditor_sig", - &auditor_sig), - GNUNET_JSON_spec_fixed_auto ("denom_pub_h", - &denom_h), - GNUNET_JSON_spec_end() - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (key, - kspec, - NULL, NULL)) - { - GNUNET_break_op (0); - continue; - } - dk = NULL; - dk_off = UINT_MAX; - for (unsigned int j=0;j<key_data->num_denom_keys;j++) - { - if (0 == memcmp (&denom_h, - &key_data->denom_keys[j].h_key, - sizeof (struct GNUNET_HashCode))) - { - dk = &key_data->denom_keys[j]; - dk_off = j; - break; - } - } - if (NULL == dk) - { - GNUNET_break_op (0); - continue; - } - if (check_sigs) - { - kv.start = GNUNET_TIME_absolute_hton (dk->valid_from); - kv.expire_withdraw = GNUNET_TIME_absolute_hton (dk->withdraw_valid_until); - kv.expire_deposit = GNUNET_TIME_absolute_hton (dk->expire_deposit); - kv.expire_legal = GNUNET_TIME_absolute_hton (dk->expire_legal); - TALER_amount_hton (&kv.value, - &dk->value); - TALER_amount_hton (&kv.fee_withdraw, - &dk->fee_withdraw); - TALER_amount_hton (&kv.fee_deposit, - &dk->fee_deposit); - TALER_amount_hton (&kv.fee_refresh, - &dk->fee_refresh); - TALER_amount_hton (&kv.fee_refund, - &dk->fee_refund); - kv.denom_hash = dk->h_key; - - if (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS, - &kv.purpose, - &auditor_sig.eddsa_sig, - &auditor->auditor_pub.eddsa_pub)) - { - GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); - return GNUNET_SYSERR; - } - } - auditor->denom_keys[off].denom_key_offset = dk_off; - auditor->denom_keys[off].auditor_sig = auditor_sig; - off++; - } - auditor->num_denom_keys = off; - GNUNET_JSON_parse_free (spec); - return GNUNET_OK; -} - - -/** - * Decode the JSON in @a resp_obj from the /keys response - * and store the data in the @a key_data. - * - * @param[in] resp_obj JSON object to parse - * @param check_sig #GNUNET_YES if we should check the signature - * @param[out] key_data where to store the results we decoded - * @param[out] where to store version compatibility data - * @return #GNUNET_OK on success, #GNUNET_SYSERR on error - * (malformed JSON) - */ -static int -decode_keys_json (const json_t *resp_obj, - int check_sig, - struct TALER_EXCHANGE_Keys *key_data, - enum TALER_EXCHANGE_VersionCompatibility *vc) -{ - struct TALER_ExchangeSignatureP sig; - struct GNUNET_HashContext *hash_context; - struct TALER_ExchangePublicKeyP pub; - unsigned int age; - unsigned int revision; - unsigned int current; - struct GNUNET_JSON_Specification mspec[] = { - GNUNET_JSON_spec_fixed_auto ("eddsa_sig", - &sig), - GNUNET_JSON_spec_fixed_auto ("eddsa_pub", - &pub), - /* sig and pub must be first, as we skip those if - check_sig is false! */ - GNUNET_JSON_spec_fixed_auto ("master_public_key", - &key_data->master_pub), - GNUNET_JSON_spec_absolute_time ("list_issue_date", - &key_data->list_issue_date), - GNUNET_JSON_spec_relative_time - ("reserve_closing_delay", - &key_data->reserve_closing_delay), - GNUNET_JSON_spec_end() - }; - - if (JSON_OBJECT != json_typeof (resp_obj)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - /* check the version */ - { - const char *ver; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_string ("version", - &ver), - GNUNET_JSON_spec_end() - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (resp_obj, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (3 != sscanf (ver, - "%u:%u:%u", - ¤t, - &revision, - &age)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - *vc = TALER_EXCHANGE_VC_MATCH; - if (TALER_PROTOCOL_CURRENT < current) - { - *vc |= TALER_EXCHANGE_VC_NEWER; - if (TALER_PROTOCOL_CURRENT < current - age) - *vc |= TALER_EXCHANGE_VC_INCOMPATIBLE; - } - if (TALER_PROTOCOL_CURRENT > current) - { - *vc |= TALER_EXCHANGE_VC_OLDER; - if (TALER_PROTOCOL_CURRENT - TALER_PROTOCOL_AGE > current) - *vc |= TALER_EXCHANGE_VC_INCOMPATIBLE; - } - key_data->version = GNUNET_strdup (ver); - } - - hash_context = NULL; - EXITIF (GNUNET_OK != - GNUNET_JSON_parse (resp_obj, - (check_sig) ? mspec : &mspec[2], - NULL, NULL)); - - /* parse the master public key and issue date of the response */ - if (check_sig) - hash_context = GNUNET_CRYPTO_hash_context_start (); - - /* parse the signing keys */ - { - json_t *sign_keys_array; - json_t *sign_key_obj; - unsigned int index; - - EXITIF (NULL == (sign_keys_array = - json_object_get (resp_obj, - "signkeys"))); - EXITIF (JSON_ARRAY != json_typeof (sign_keys_array)); - EXITIF (0 == (key_data->num_sign_keys = - json_array_size (sign_keys_array))); - key_data->sign_keys - = GNUNET_new_array (key_data->num_sign_keys, - struct TALER_EXCHANGE_SigningPublicKey); - index = 0; - json_array_foreach (sign_keys_array, index, sign_key_obj) { - EXITIF (GNUNET_SYSERR == - parse_json_signkey (&key_data->sign_keys[index], - check_sig, - sign_key_obj, - &key_data->master_pub)); - } - } - - /* parse the denomination keys, merging with the - possibly EXISTING array as required (/keys cherry picking) */ - { - json_t *denom_keys_array; - json_t *denom_key_obj; - unsigned int index; - - EXITIF (NULL == (denom_keys_array = - json_object_get (resp_obj, - "denoms"))); - EXITIF (JSON_ARRAY != json_typeof (denom_keys_array)); - - index = 0; - json_array_foreach (denom_keys_array, index, denom_key_obj) { - struct TALER_EXCHANGE_DenomPublicKey dk; - bool found = false; - - EXITIF (GNUNET_SYSERR == - parse_json_denomkey (&dk, - check_sig, - denom_key_obj, - &key_data->master_pub, - hash_context)); - for (unsigned int j=0;j<key_data->num_denom_keys;j++) - { - if (0 == memcmp (&dk, - &key_data->denom_keys[j], - sizeof (dk))) - { - found = true; - break; - } - } - if (found) - { - /* 0:0:0 did not support /keys cherry picking */ - GNUNET_break_op (0 == current); - continue; - } - if (key_data->denom_keys_size == key_data->num_denom_keys) - GNUNET_array_grow (key_data->denom_keys, - key_data->denom_keys_size, - key_data->denom_keys_size * 2 + 2); - key_data->denom_keys[key_data->num_denom_keys++] = dk; - - /* Update "last_denom_issue_date" */ - TALER_LOG_DEBUG ("Crawling DK 'valid_from': %s\n", - GNUNET_STRINGS_absolute_time_to_string (dk.valid_from)); - key_data->last_denom_issue_date - = GNUNET_TIME_absolute_max (key_data->last_denom_issue_date, - dk.valid_from); - }; - } - /* parse the auditor information */ - { - json_t *auditors_array; - json_t *auditor_info; - unsigned int index; - - EXITIF (NULL == (auditors_array = - json_object_get (resp_obj, - "auditors"))); - EXITIF (JSON_ARRAY != json_typeof (auditors_array)); - - /* Merge with the existing auditor information we have (/keys cherry picking) */ - index = 0; - json_array_foreach (auditors_array, index, auditor_info) { - struct TALER_EXCHANGE_AuditorInformation ai; - bool found = false; - - memset (&ai, - 0, - sizeof (ai)); - EXITIF (GNUNET_SYSERR == - parse_json_auditor (&ai, - check_sig, - auditor_info, - key_data)); - for (unsigned int j=0;j<key_data->num_auditors;j++) - { - struct TALER_EXCHANGE_AuditorInformation *aix = &key_data->auditors[j]; - - if (0 == memcmp (&ai.auditor_pub, - &aix->auditor_pub, - sizeof (struct TALER_AuditorPublicKeyP))) - { - found = true; - /* Merge denomination key signatures of downloaded /keys into existing - auditor information 'aix'. */ - GNUNET_array_grow (aix->denom_keys, - aix->num_denom_keys, - aix->num_denom_keys + ai.num_denom_keys); - memcpy (&aix->denom_keys[aix->num_denom_keys - ai.num_denom_keys], - ai.denom_keys, - ai.num_denom_keys * sizeof (struct TALER_EXCHANGE_AuditorDenominationInfo)); - break; - } - } - if (found) - continue; /* we are done */ - if (key_data->auditors_size == key_data->num_auditors) - GNUNET_array_grow (key_data->auditors, - key_data->auditors_size, - key_data->auditors_size * 2 + 2); - key_data->auditors[key_data->num_auditors++] = ai; - }; - } - - if (check_sig) - { - struct TALER_ExchangeKeySetPS ks; - - /* Validate signature... */ - ks.purpose.size = htonl (sizeof (ks)); - ks.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_KEY_SET); - ks.list_issue_date = GNUNET_TIME_absolute_hton (key_data->list_issue_date); - GNUNET_CRYPTO_hash_context_finish (hash_context, - &ks.hc); - hash_context = NULL; - EXITIF (GNUNET_OK != - TALER_EXCHANGE_test_signing_key (key_data, - &pub)); - EXITIF (GNUNET_OK != - GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_KEY_SET, - &ks.purpose, - &sig.eddsa_signature, - &pub.eddsa_pub)); - } - return GNUNET_OK; - EXITIF_exit: - - if (NULL != hash_context) - GNUNET_CRYPTO_hash_context_abort (hash_context); - return GNUNET_SYSERR; -} - - -/** - * Free key data object. - * - * @param key_data data to free (pointer itself excluded) - */ -static void -free_key_data (struct TALER_EXCHANGE_Keys *key_data) -{ - GNUNET_array_grow (key_data->sign_keys, - key_data->num_sign_keys, - 0); - for (unsigned int i=0;i<key_data->num_denom_keys;i++) - GNUNET_CRYPTO_rsa_public_key_free (key_data->denom_keys[i].key.rsa_public_key); - - GNUNET_array_grow (key_data->denom_keys, - key_data->denom_keys_size, - 0); - for (unsigned int i=0;i<key_data->num_auditors;i++) - { - GNUNET_array_grow (key_data->auditors[i].denom_keys, - key_data->auditors[i].num_denom_keys, - 0); - GNUNET_free (key_data->auditors[i].auditor_url); - } - GNUNET_array_grow (key_data->auditors, - key_data->auditors_size, - 0); - GNUNET_free_non_null (key_data->version); - key_data->version = NULL; -} - - -/** - * Initiate download of /keys from the exchange. - * - * @param cls exchange where to download /keys from - */ -static void -request_keys (void *cls); - - -/** - * Check if our current response for /keys is valid, and if - * not trigger download. - * - * @param exchange exchange to check keys for - * @param force_download #GNUNET_YES to force download even if /keys is still valid - * @return until when the response is current, 0 if we are re-downloading - */ -struct GNUNET_TIME_Absolute -TALER_EXCHANGE_check_keys_current (struct TALER_EXCHANGE_Handle *exchange, - int force_download) -{ - if (NULL != exchange->kr) - return GNUNET_TIME_UNIT_ZERO_ABS; - if ( (GNUNET_NO == force_download) && - (0 < GNUNET_TIME_absolute_get_remaining (exchange->key_data_expiration).rel_value_us) ) - return exchange->key_data_expiration; - if (NULL == exchange->retry_task) - exchange->retry_task = GNUNET_SCHEDULER_add_now (&request_keys, - exchange); - return GNUNET_TIME_UNIT_ZERO_ABS; -} - - -/** - * Callback used when downloading the reply to a /keys request - * is complete. - * - * @param cls the `struct KeysRequest` - * @param response_code HTTP response code, 0 on error - * @param resp_obj parsed JSON result, NULL on error - */ -static void -keys_completed_cb (void *cls, - long response_code, - const void *resp_obj) -{ - struct KeysRequest *kr = cls; - struct TALER_EXCHANGE_Handle *exchange = kr->exchange; - struct TALER_EXCHANGE_Keys kd; - struct TALER_EXCHANGE_Keys kd_old; - enum TALER_EXCHANGE_VersionCompatibility vc; - const json_t *j = resp_obj; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Received keys from URL `%s' with status %ld.\n", - kr->url, - response_code); - kd_old = exchange->key_data; - memset (&kd, - 0, - sizeof (struct TALER_EXCHANGE_Keys)); - vc = TALER_EXCHANGE_VC_PROTOCOL_ERROR; - switch (response_code) - { - case 0: - free_keys_request (kr); - exchange->kr = NULL; - GNUNET_assert (NULL == exchange->retry_task); - exchange->retry_delay = EXCHANGE_LIB_BACKOFF (exchange->retry_delay); - exchange->retry_task = GNUNET_SCHEDULER_add_delayed (exchange->retry_delay, - &request_keys, - exchange); - return; - case MHD_HTTP_OK: - if (NULL == j) - { - response_code = 0; - break; - } - /* We keep the denomination keys and auditor signatures from the - previous iteration (/keys cherry picking) */ - kd.num_denom_keys = kd_old.num_denom_keys; - kd.last_denom_issue_date = kd_old.last_denom_issue_date; - GNUNET_array_grow (kd.denom_keys, - kd.denom_keys_size, - kd.num_denom_keys); - - /* First make a shallow copy, we then need another pass for the RSA key... */ - memcpy (kd.denom_keys, - kd_old.denom_keys, - kd_old.num_denom_keys * sizeof (struct TALER_EXCHANGE_DenomPublicKey)); - for (unsigned int i=0;i<kd_old.num_denom_keys;i++) - kd.denom_keys[i].key.rsa_public_key - = GNUNET_CRYPTO_rsa_public_key_dup (kd_old.denom_keys[i].key.rsa_public_key); - - kd.num_auditors = kd_old.num_auditors; - kd.auditors = GNUNET_new_array (kd.num_auditors, - struct TALER_EXCHANGE_AuditorInformation); - /* Now the necessary deep copy... */ - for (unsigned int i=0;i<kd_old.num_auditors;i++) - { - const struct TALER_EXCHANGE_AuditorInformation *aold = &kd_old.auditors[i]; - struct TALER_EXCHANGE_AuditorInformation *anew = &kd.auditors[i]; - - anew->auditor_pub = aold->auditor_pub; - anew->auditor_url = GNUNET_strdup (aold->auditor_url); - GNUNET_array_grow (anew->denom_keys, - anew->num_denom_keys, - aold->num_denom_keys); - memcpy (anew->denom_keys, - aold->denom_keys, - aold->num_denom_keys * sizeof (struct TALER_EXCHANGE_AuditorDenominationInfo)); - } - - if (GNUNET_OK != - decode_keys_json (j, - GNUNET_YES, - &kd, - &vc)) - { - TALER_LOG_ERROR ("Could not decode /keys response\n"); - response_code = 0; - for (unsigned int i=0;i<kd.num_auditors;i++) - { - struct TALER_EXCHANGE_AuditorInformation *anew = &kd.auditors[i]; - - GNUNET_array_grow (anew->denom_keys, - anew->num_denom_keys, - 0); - GNUNET_free (anew->auditor_url); - } - GNUNET_free (kd.auditors); - kd.auditors = NULL; - kd.num_auditors = 0; - for (unsigned int i=0;i<kd_old.num_denom_keys;i++) - GNUNET_CRYPTO_rsa_public_key_free (kd.denom_keys[i].key.rsa_public_key); - GNUNET_array_grow (kd.denom_keys, - kd.denom_keys_size, - 0); - kd.num_denom_keys = 0; - break; - } - json_decref (exchange->key_data_raw); - exchange->key_data_raw = json_deep_copy (j); - exchange->retry_delay = GNUNET_TIME_UNIT_ZERO; - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u\n", - (unsigned int) response_code); - break; - } - exchange->key_data = kd; - TALER_LOG_DEBUG ("Last DK issue date update to: %s\n", - GNUNET_STRINGS_absolute_time_to_string - (exchange->key_data.last_denom_issue_date)); - - - if (MHD_HTTP_OK != response_code) - { - exchange->kr = NULL; - free_keys_request (kr); - exchange->state = MHS_FAILED; - if (NULL != exchange->key_data_raw) - { - json_decref (exchange->key_data_raw); - exchange->key_data_raw = NULL; - } - free_key_data (&kd_old); - /* notify application that we failed */ - exchange->cert_cb (exchange->cert_cb_cls, - NULL, - vc); - return; - } - - exchange->kr = NULL; - exchange->key_data_expiration = kr->expire; - free_keys_request (kr); - exchange->state = MHS_CERT; - /* notify application about the key information */ - exchange->cert_cb (exchange->cert_cb_cls, - &exchange->key_data, - vc); - free_key_data (&kd_old); -} - - -/* ********************* library internal API ********* */ - - -/** - * Get the context of a exchange. - * - * @param h the exchange handle to query - * @return ctx context to execute jobs in - */ -struct GNUNET_CURL_Context * -TEAH_handle_to_context (struct TALER_EXCHANGE_Handle *h) -{ - return h->ctx; -} - - -/** - * Check if the handle is ready to process requests. - * - * @param h the exchange handle to query - * @return #GNUNET_YES if we are ready, #GNUNET_NO if not - */ -int -TEAH_handle_is_ready (struct TALER_EXCHANGE_Handle *h) -{ - return (MHS_CERT == h->state) ? GNUNET_YES : GNUNET_NO; -} - - -/** - * Obtain the URL to use for an API request. - * - * @param h handle for the exchange - * @param path Taler API path (i.e. "/reserve/withdraw") - * @return the full URL to use with cURL - */ -char * -TEAH_path_to_url (struct TALER_EXCHANGE_Handle *h, - const char *path) -{ - return TEAH_path_to_url2 (h->url, - path); -} - - -/** - * Obtain the URL to use for an API request. - * - * @param base_url base URL of the exchange (i.e. "http://exchange/") - * @param path Taler API path (i.e. "/reserve/withdraw") - * @return the full URL to use with cURL - */ -char * -TEAH_path_to_url2 (const char *base_url, - const char *path) -{ - char *url; - - if ( ('/' == path[0]) && - (0 < strlen (base_url)) && - ('/' == base_url[strlen (base_url) - 1]) ) - path++; /* avoid generating URL with "//" from concat */ - GNUNET_asprintf (&url, - "%s%s", - base_url, - path); - return url; -} - - -/** - * Parse HTTP timestamp. - * - * @param date header to parse header - * @param at where to write the result - * @return #GNUNET_OK on success - */ -static int -parse_date_string (const char *date, - struct GNUNET_TIME_Absolute *at) -{ - struct tm now; - time_t t; - const char *end; - - memset (&now, - 0, - sizeof (now)); - end = strptime (date, - "%a, %d %b %Y %H:%M:%S %Z", /* RFC-1123 standard spec */ - &now); - if ( (NULL == end) || - ( (*end != '\n') && - (*end != '\r') ) ) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - t = mktime (&now); - if (((time_t) -1) == t) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, - "mktime"); - return GNUNET_SYSERR; - } - if (t < 0) - t = 0; /* can happen due to timezone issues if date was 1.1.1970 */ - at->abs_value_us = 1000LL * 1000LL * t; - return GNUNET_OK; -} - - -/** - * Function called for each header in the HTTP /keys response. - * Finds the "Expire:" header and parses it, storing the result - * in the "expire" field fo the keys request. - * - * @param buffer header data received - * @param size size of an item in @a buffer - * @param nitems number of items in @a buffer - * @param userdata the `struct KeysRequest` - * @return `size * nitems` on success (everything else aborts) - */ -static size_t -header_cb (char *buffer, - size_t size, - size_t nitems, - void *userdata) -{ - struct KeysRequest *kr = userdata; - size_t total = size * nitems; - char *val; - - if (total < strlen (MHD_HTTP_HEADER_EXPIRES ": ")) - return total; - if (0 != strncasecmp (MHD_HTTP_HEADER_EXPIRES ": ", - buffer, - strlen (MHD_HTTP_HEADER_EXPIRES ": "))) - return total; - val = GNUNET_strndup (&buffer[strlen (MHD_HTTP_HEADER_EXPIRES ": ")], - total - strlen (MHD_HTTP_HEADER_EXPIRES ": ")); - if (GNUNET_OK != - parse_date_string (val, - &kr->expire)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to parse %s-header `%s'\n", - MHD_HTTP_HEADER_EXPIRES, - val); - kr->expire = GNUNET_TIME_UNIT_ZERO_ABS; - } - GNUNET_free (val); - return total; -} - - -/* ********************* public API ******************* */ - - -/** - * Deserialize the key data and use it to bootstrap @a exchange to - * more efficiently recover the state. Errors in @a data must be - * tolerated (i.e. by re-downloading instead). - * - * @param exchange which exchange's key and wire data should be deserialized - * @return data the data to deserialize - */ -static void -deserialize_data (struct TALER_EXCHANGE_Handle *exchange, - const json_t *data) -{ - enum TALER_EXCHANGE_VersionCompatibility vc; - json_t *keys; - const char *url; - uint32_t version; - struct GNUNET_TIME_Absolute expire; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_uint32 ("version", - &version), - GNUNET_JSON_spec_json ("keys", - &keys), - GNUNET_JSON_spec_string ("url", - &url), - GNUNET_JSON_spec_absolute_time ("expire", - &expire), - GNUNET_JSON_spec_end() - }; - struct TALER_EXCHANGE_Keys key_data; - - if (NULL == data) - return; - if (GNUNET_OK != - GNUNET_JSON_parse (data, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return; - } - if (0 != version) - return; /* unsupported version */ - if (0 != strcmp (url, - exchange->url)) - { - GNUNET_break (0); - return; - } - memset (&key_data, - 0, - sizeof (struct TALER_EXCHANGE_Keys)); - if (GNUNET_OK != - decode_keys_json (keys, - GNUNET_NO, - &key_data, - &vc)) - { - GNUNET_break (0); - return; - } - /* decode successful, initialize with the result */ - GNUNET_assert (NULL == exchange->key_data_raw); - exchange->key_data_raw = json_deep_copy (keys); - exchange->key_data = key_data; - exchange->key_data_expiration = expire; - exchange->state = MHS_CERT; - /* notify application about the key information */ - exchange->cert_cb (exchange->cert_cb_cls, - &exchange->key_data, - vc); -} - - -/** - * Serialize the latest key data from @a exchange to be persisted on - * disk (to be used with #TALER_EXCHANGE_OPTION_DATA to more - * efficiently recover the state). - * - * @param exchange which exchange's key and wire data should be - * serialized - * @return NULL on error (i.e. no current data available); - * otherwise JSON object owned by the caller - */ -json_t * -TALER_EXCHANGE_serialize_data (struct TALER_EXCHANGE_Handle *exchange) -{ - const struct TALER_EXCHANGE_Keys *kd = &exchange->key_data; - struct GNUNET_TIME_Absolute now; - json_t *keys; - json_t *signkeys; - json_t *denoms; - json_t *auditors; - - now = GNUNET_TIME_absolute_get (); - signkeys = json_array (); - for (unsigned int i=0;i<kd->num_sign_keys;i++) - { - const struct TALER_EXCHANGE_SigningPublicKey *sk = &kd->sign_keys[i]; - json_t *signkey; - - if (now.abs_value_us > sk->valid_until.abs_value_us) - continue; /* skip keys that have expired */ - signkey = json_pack ("{s:o, s:o, s:o, s:o, s:o}", - "key", - GNUNET_JSON_from_data_auto (&sk->key), - "master_sig", - GNUNET_JSON_from_data_auto (&sk->master_sig), - "stamp_start", - GNUNET_JSON_from_time_abs (sk->valid_from), - "stamp_expire", - GNUNET_JSON_from_time_abs (sk->valid_until), - "stamp_end", - GNUNET_JSON_from_time_abs (sk->valid_legal)); - if (NULL == signkey) - { - GNUNET_break (0); - continue; - } - json_array_append_new (signkeys, - signkey); - } - denoms = json_array (); - for (unsigned int i=0;i<kd->num_denom_keys;i++) - { - const struct TALER_EXCHANGE_DenomPublicKey *dk = &kd->denom_keys[i]; - json_t *denom; - - if (now.abs_value_us > dk->expire_deposit.abs_value_us) - continue; /* skip keys that have expired */ - denom = json_pack ("{s:o, s:o, s:o, s:o, s:o " - ",s:o, s:o, s:o, s:o, s:o " - ",s:o}", - "stamp_expire_deposit", - GNUNET_JSON_from_time_abs (dk->expire_deposit), - "stamp_expire_withdraw", - GNUNET_JSON_from_time_abs (dk->withdraw_valid_until), - "stamp_start", - GNUNET_JSON_from_time_abs (dk->valid_from), - "stamp_expire_legal", - GNUNET_JSON_from_time_abs (dk->expire_legal), - "value", - TALER_JSON_from_amount (&dk->value), - "fee_withdraw", - /* #6 */ - TALER_JSON_from_amount (&dk->fee_withdraw), - "fee_deposit", - TALER_JSON_from_amount (&dk->fee_deposit), - "fee_refresh", - TALER_JSON_from_amount (&dk->fee_refresh), - "fee_refund", - TALER_JSON_from_amount (&dk->fee_refund), - "master_sig", - GNUNET_JSON_from_data_auto (&dk->master_sig), - /* #10 */ - "denom_pub", - GNUNET_JSON_from_rsa_public_key (dk->key.rsa_public_key)); - if (NULL == denom) - { - GNUNET_break (0); - continue; - } - json_array_append_new (denoms, - denom); - } - auditors = json_array (); - for (unsigned int i=0;i<kd->num_auditors;i++) - { - const struct TALER_EXCHANGE_AuditorInformation *ai = &kd->auditors[i]; - json_t *a; - json_t *adenoms; - - adenoms = json_array (); - for (unsigned int j=0;j<ai->num_denom_keys;j++) - { - const struct TALER_EXCHANGE_AuditorDenominationInfo *adi = &ai->denom_keys[j]; - const struct TALER_EXCHANGE_DenomPublicKey *dk = &kd->denom_keys[adi->denom_key_offset]; - json_t *k; - - if (now.abs_value_us > dk->expire_deposit.abs_value_us) - continue; /* skip auditor signatures for denomination keys that have expired */ - GNUNET_assert (adi->denom_key_offset < kd->num_denom_keys); - k = json_pack ("{s:o, s:o}", - "denom_pub_h", - GNUNET_JSON_from_data_auto (&dk->h_key), - "auditor_sig", - GNUNET_JSON_from_data_auto (&adi->auditor_sig)); - if (NULL == k) - { - GNUNET_break (0); - continue; - } - json_array_append_new (adenoms, - k); - } - - a = json_pack ("{s:o, s:s, s:o}", - "auditor_pub", - GNUNET_JSON_from_data_auto (&ai->auditor_pub), - "auditor_url", - ai->auditor_url, - "denomination_keys", - adenoms); - if (NULL == a) - { - GNUNET_break (0); - continue; - } - json_array_append_new (auditors, - a); - } - keys = json_pack ("{s:s, s:o, s:o, s:o, s:o" - ",s:o, s:o}", - /* 1 */ - "version", - kd->version, - "master_public_key", - GNUNET_JSON_from_data_auto (&kd->master_pub), - "reserve_closing_delay", - GNUNET_JSON_from_time_rel (kd->reserve_closing_delay), - "list_issue_date", - GNUNET_JSON_from_time_abs (kd->list_issue_date), - "signkeys", - signkeys, - /* #6 */ - "denoms", - denoms, - "auditors", - auditors); - if (NULL == keys) - { - GNUNET_break (0); - return NULL; - } - return json_pack ("{s:I, s:o, s:s, s:o}", - "version", - (json_int_t) TALER_SERIALIZATION_FORMAT_VERSION, - "expire", - GNUNET_JSON_from_time_abs (exchange->key_data_expiration), - "url", - exchange->url, - "keys", - keys); -} - - -/** - * Initialise a connection to the exchange. Will connect to the - * exchange and obtain information about the exchange's master - * public key and the exchange's auditor. - * The respective information will be passed to the @a cert_cb - * once available, and all future interactions with the exchange - * will be checked to be signed (where appropriate) by the - * respective master key. - * - * @param ctx the context - * @param url HTTP base URL for the exchange - * @param cert_cb function to call with the exchange's - * certification information - * @param cert_cb_cls closure for @a cert_cb - * @param ... list of additional arguments, - * terminated by #TALER_EXCHANGE_OPTION_END. - * @return the exchange handle; NULL upon error - */ -struct TALER_EXCHANGE_Handle * -TALER_EXCHANGE_connect - (struct GNUNET_CURL_Context *ctx, - const char *url, - TALER_EXCHANGE_CertificationCallback cert_cb, - void *cert_cb_cls, - ...) -{ - struct TALER_EXCHANGE_Handle *exchange; - va_list ap; - enum TALER_EXCHANGE_Option opt; - - exchange = GNUNET_new (struct TALER_EXCHANGE_Handle); - exchange->ctx = ctx; - exchange->url = GNUNET_strdup (url); - exchange->cert_cb = cert_cb; - exchange->cert_cb_cls = cert_cb_cls; - exchange->retry_task = GNUNET_SCHEDULER_add_now (&request_keys, - exchange); - va_start (ap, cert_cb_cls); - while (TALER_EXCHANGE_OPTION_END != - (opt = va_arg (ap, int))) - { - switch (opt) { - case TALER_EXCHANGE_OPTION_END: - GNUNET_assert (0); - break; - case TALER_EXCHANGE_OPTION_DATA: - { - const json_t *data = va_arg (ap, const json_t *); - - deserialize_data (exchange, - data); - break; - } - default: - GNUNET_assert (0); - break; - } - } - va_end (ap); - return exchange; -} - - -/** - * Initiate download of /keys from the exchange. - * - * @param cls exchange where to download /keys from - */ -static void -request_keys (void *cls) -{ - struct TALER_EXCHANGE_Handle *exchange = cls; - struct KeysRequest *kr; - CURL *eh; - - exchange->retry_task = NULL; - GNUNET_assert (NULL == exchange->kr); - kr = GNUNET_new (struct KeysRequest); - kr->exchange = exchange; - if (GNUNET_YES == - TEAH_handle_is_ready (exchange)) - { - char *arg; - - TALER_LOG_DEBUG ("Last DK issue date (before GETting /keys): %s\n", - GNUNET_STRINGS_absolute_time_to_string (exchange->key_data.last_denom_issue_date)); - GNUNET_asprintf (&arg, - "/keys?last_issue_date=%llu", - (unsigned long long) exchange->key_data.last_denom_issue_date.abs_value_us / 1000000LLU); - kr->url = TEAH_path_to_url (exchange, - arg); - GNUNET_free (arg); - } - else - { - kr->url = TEAH_path_to_url (exchange, - "/keys"); - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Requesting keys with URL `%s'.\n", - kr->url); - eh = TEL_curl_easy_get (kr->url); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_VERBOSE, - 0)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_TIMEOUT, - (long) 300)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_HEADERFUNCTION, - &header_cb)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_HEADERDATA, - kr)); - kr->job = GNUNET_CURL_job_add (exchange->ctx, - eh, - GNUNET_YES, - &keys_completed_cb, - kr); - exchange->kr = kr; -} - - -/** - * Disconnect from the exchange - * - * @param exchange the exchange handle - */ -void -TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange) -{ - if (NULL != exchange->kr) - { - GNUNET_CURL_job_cancel (exchange->kr->job); - free_keys_request (exchange->kr); - exchange->kr = NULL; - } - free_key_data (&exchange->key_data); - if (NULL != exchange->key_data_raw) - { - json_decref (exchange->key_data_raw); - exchange->key_data_raw = NULL; - } - if (NULL != exchange->retry_task) - { - GNUNET_SCHEDULER_cancel (exchange->retry_task); - exchange->retry_task = NULL; - } - GNUNET_free (exchange->url); - GNUNET_free (exchange); -} - - -/** - * Lookup the given @a pub in @a keys. - * - * @param keys the exchange's key set - * @param pub claimed current online signing key for the exchange - * @return NULL if @a pub was not found - */ -const struct TALER_EXCHANGE_SigningPublicKey * -TALER_EXCHANGE_get_signing_key_details (const struct TALER_EXCHANGE_Keys *keys, - const struct TALER_ExchangePublicKeyP *pub) -{ - for (unsigned int i=0;i<keys->num_sign_keys;i++) - { - struct TALER_EXCHANGE_SigningPublicKey *spk = &keys->sign_keys[i]; - - if (0 == memcmp (pub, - &spk->key, - sizeof (struct TALER_ExchangePublicKeyP))) - return spk; - } - return NULL; -} - - -/** - * Test if the given @a pub is a the current signing key from the exchange - * according to @a keys. - * - * @param keys the exchange's key set - * @param pub claimed current online signing key for the exchange - * @return #GNUNET_OK if @a pub is (according to /keys) a current signing key - */ -int -TALER_EXCHANGE_test_signing_key (const struct TALER_EXCHANGE_Keys *keys, - const struct TALER_ExchangePublicKeyP *pub) -{ - struct GNUNET_TIME_Absolute now; - - /* we will check using a tolerance of 1h for the time */ - now = GNUNET_TIME_absolute_get (); - for (unsigned int i=0;i<keys->num_sign_keys;i++) - if ( (keys->sign_keys[i].valid_from.abs_value_us <= now.abs_value_us + 60 * 60 * 1000LL * 1000LL) && - (keys->sign_keys[i].valid_until.abs_value_us > now.abs_value_us - 60 * 60 * 1000LL * 1000LL) && - (0 == memcmp (pub, - &keys->sign_keys[i].key, - sizeof (struct TALER_ExchangePublicKeyP))) ) - return GNUNET_OK; - return GNUNET_SYSERR; -} - - -/** - * Get exchange's base URL. - * - * @param exchange exchange handle. - * @return the base URL from the handle. - */ -const char * -TALER_EXCHANGE_get_base_url (const struct TALER_EXCHANGE_Handle *exchange) -{ - return exchange->url; -} - - -/** - * Obtain the denomination key details from the exchange. - * - * @param keys the exchange's key set - * @param pk public key of the denomination to lookup - * @return details about the given denomination key, NULL if the key is - * not found - */ -const struct TALER_EXCHANGE_DenomPublicKey * -TALER_EXCHANGE_get_denomination_key (const struct TALER_EXCHANGE_Keys *keys, - const struct TALER_DenominationPublicKey *pk) -{ - for (unsigned int i=0;i<keys->num_denom_keys;i++) - if (0 == GNUNET_CRYPTO_rsa_public_key_cmp (pk->rsa_public_key, - keys->denom_keys[i].key.rsa_public_key)) - return &keys->denom_keys[i]; - return NULL; -} - - -/** - * Obtain the denomination key details from the exchange. - * - * @param keys the exchange's key set - * @param hc hash of the public key of the denomination to lookup - * @return details about the given denomination key - */ -const struct TALER_EXCHANGE_DenomPublicKey * -TALER_EXCHANGE_get_denomination_key_by_hash (const struct TALER_EXCHANGE_Keys *keys, - const struct GNUNET_HashCode *hc) -{ - for (unsigned int i=0;i<keys->num_denom_keys;i++) - if (0 == memcmp (hc, - &keys->denom_keys[i].h_key, - sizeof (struct GNUNET_HashCode))) - return &keys->denom_keys[i]; - return NULL; -} - - -/** - * Obtain the keys from the exchange. - * - * @param exchange the exchange handle - * @return the exchange's key set - */ -const struct TALER_EXCHANGE_Keys * -TALER_EXCHANGE_get_keys (struct TALER_EXCHANGE_Handle *exchange) -{ - (void) TALER_EXCHANGE_check_keys_current (exchange, - GNUNET_NO); - return &exchange->key_data; -} - - -/** - * Obtain the keys from the exchange in the - * raw JSON format - * - * @param exchange the exchange handle - * @return the exchange's keys in raw JSON - */ -json_t * -TALER_EXCHANGE_get_keys_raw (struct TALER_EXCHANGE_Handle *exchange) -{ - (void) TALER_EXCHANGE_check_keys_current (exchange, - GNUNET_NO); - return json_deep_copy (exchange->key_data_raw); -} - - -/* end of exchange_api_handle.c */ |