summaryrefslogtreecommitdiff
path: root/src/lib/exchange_api_handle.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2023-07-04 15:37:34 +0200
committerChristian Grothoff <christian@grothoff.org>2023-07-04 15:37:46 +0200
commitff8349e6e7b7a898f3a9b0f69c44fa4a2a6a3fb1 (patch)
tree403cdc1e3a772a3415e14bcc6e9c6a4a78a4beba /src/lib/exchange_api_handle.c
parent47620fa81b74a090767443445048ec9e3c15456e (diff)
downloadexchange-ff8349e6e7b7a898f3a9b0f69c44fa4a2a6a3fb1.tar.gz
exchange-ff8349e6e7b7a898f3a9b0f69c44fa4a2a6a3fb1.tar.bz2
exchange-ff8349e6e7b7a898f3a9b0f69c44fa4a2a6a3fb1.zip
more exchange API refactoring
Diffstat (limited to 'src/lib/exchange_api_handle.c')
-rw-r--r--src/lib/exchange_api_handle.c1588
1 files changed, 537 insertions, 1051 deletions
diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c
index 0bb3c2085..7fcb590a3 100644
--- a/src/lib/exchange_api_handle.c
+++ b/src/lib/exchange_api_handle.c
@@ -48,6 +48,11 @@
#define EXCHANGE_PROTOCOL_AGE 0
/**
+ * Set to 1 for extra debug logging.
+ */
+#define DEBUG 0
+
+/**
* Current version for (local) JSON serialization of persisted
* /keys data.
*/
@@ -64,103 +69,58 @@
*/
#define DEFAULT_EXPIRATION GNUNET_TIME_UNIT_HOURS
-/**
- * Set to 1 for extra debug logging.
- */
-#define DEBUG 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
+ * Handle for a GET /keys request.
*/
-#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));
-
-
-/**
- * Data for the request to get the /keys of a exchange.
- */
-struct KeysRequest;
-
-
-/**
- * Entry in DLL of auditors used by an exchange.
- */
-struct TEAH_AuditorListEntry
+struct TALER_EXCHANGE_GetKeysHandle
{
- /**
- * Next pointer of DLL.
- */
- struct TEAH_AuditorListEntry *next;
-
- /**
- * Prev pointer of DLL.
- */
- struct TEAH_AuditorListEntry *prev;
/**
- * Base URL of the auditor.
+ * The exchange base URL (i.e. "http://exchange.taler.net/")
*/
- char *auditor_url;
+ char *exchange_url;
/**
- * Handle to the auditor.
+ * The url for the /keys request.
*/
- struct TALER_AUDITOR_GetConfigHandle *ah;
+ char *url;
/**
- * Public key of the auditor.
+ * Previous /keys response, NULL for none.
*/
- struct TALER_AuditorPublicKeyP auditor_pub;
+ struct TALER_EXCHANGE_Keys *prev_keys;
/**
- * Flag indicating that the auditor is available and that protocol
- * version compatibility is given.
+ * Entry for this request with the `struct GNUNET_CURL_Context`.
*/
- bool is_up;
-
-};
-
-
-/* ***************** Internal /keys fetching ************* */
+ struct GNUNET_CURL_Job *job;
-/**
- * Data for the request to get the /keys of a exchange.
- */
-struct KeysRequest
-{
/**
- * The connection to exchange this request handle will use
+ * Expiration time according to "Expire:" header.
+ * 0 if not provided by the server.
*/
- struct TALER_EXCHANGE_Handle *exchange;
+ struct GNUNET_TIME_Timestamp expire;
/**
- * The url for this handle
+ * Function to call with the exchange's certification data,
+ * NULL if this has already been done.
*/
- char *url;
+ TALER_EXCHANGE_GetKeysCallback cert_cb;
/**
- * Entry for this request with the `struct GNUNET_CURL_Context`.
+ * Closure to pass to @e cert_cb.
*/
- struct GNUNET_CURL_Job *job;
-
- /**
- * Expiration time according to "Expire:" header.
- * 0 if not provided by the server.
- */
- struct GNUNET_TIME_Timestamp expire;
+ void *cert_cb_cls;
};
void
-TEAH_get_auditors_for_dc (struct TALER_EXCHANGE_Keys *keys,
- TEAH_AuditorCallback ac,
- void *ac_cls)
+TEAH_get_auditors_for_dc (
+ struct TALER_EXCHANGE_Keys *keys,
+ TEAH_AuditorCallback ac,
+ void *ac_cls)
{
if (0 == keys->num_auditors)
{
@@ -180,20 +140,6 @@ TEAH_get_auditors_for_dc (struct TALER_EXCHANGE_Keys *keys,
}
-/**
- * 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; } \
@@ -205,21 +151,20 @@ free_keys_request (struct KeysRequest *kr)
*
* @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 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.
+ * invalid or the @a sign_key_obj is malformed.
*/
static enum GNUNET_GenericReturnValue
parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key,
bool check_sigs,
- json_t *sign_key_obj,
+ const json_t *sign_key_obj,
const struct TALER_MasterPublicKeyP *master_key)
{
- struct TALER_MasterSignatureP sign_key_issue_sig;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("master_sig",
- &sign_key_issue_sig),
+ &sign_key->master_sig),
GNUNET_JSON_spec_fixed_auto ("key",
&sign_key->key),
GNUNET_JSON_spec_timestamp ("stamp_start",
@@ -239,7 +184,6 @@ parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
-
if (! check_sigs)
return GNUNET_OK;
if (GNUNET_OK !=
@@ -249,12 +193,11 @@ parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key,
sign_key->valid_until,
sign_key->valid_legal,
master_key,
- &sign_key_issue_sig))
+ &sign_key->master_sig))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- sign_key->master_sig = sign_key_issue_sig;
return GNUNET_OK;
}
@@ -270,9 +213,9 @@ parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key,
* @param[out] denom_key where to return the result
* @param cipher cipher type to parse
* @param check_sigs should we check signatures?
- * @param[in] denom_key_obj json to parse
+ * @param denom_key_obj json to parse
* @param master_key master key to use to verify signature
- * @param hash_xor where to accumulate data for signature verification via XOR
+ * @param[in,out] hash_xor where to accumulate data for signature verification via XOR
* @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
* invalid or the json malformed.
*/
@@ -281,7 +224,7 @@ parse_json_denomkey_partially (
struct TALER_EXCHANGE_DenomPublicKey *denom_key,
enum TALER_DenominationCipher cipher,
bool check_sigs,
- json_t *denom_key_obj,
+ const json_t *denom_key_obj,
struct TALER_MasterPublicKeyP *master_key,
struct GNUNET_HashCode *hash_xor)
{
@@ -316,7 +259,6 @@ parse_json_denomkey_partially (
GNUNET_CRYPTO_hash_xor (&denom_key->h_key.hash,
hash_xor,
hash_xor);
-
if (! check_sigs)
return GNUNET_OK;
EXITIF (GNUNET_SYSERR ==
@@ -346,7 +288,7 @@ EXITIF_exit:
*
* @param[out] auditor where to return the result
* @param check_sigs should we check signatures
- * @param[in] auditor_obj json to parse
+ * @param 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.
@@ -354,14 +296,12 @@ EXITIF_exit:
static enum GNUNET_GenericReturnValue
parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,
bool check_sigs,
- json_t *auditor_obj,
+ const json_t *auditor_obj,
const struct TALER_EXCHANGE_Keys *key_data)
{
const json_t *keys;
json_t *key;
- unsigned int len;
unsigned int off;
- unsigned int i;
const char *auditor_url;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("auditor_pub",
@@ -387,16 +327,15 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,
return GNUNET_SYSERR;
}
auditor->auditor_url = GNUNET_strdup (auditor_url);
- len = json_array_size (keys);
- auditor->denom_keys = GNUNET_new_array (len,
- struct
- TALER_EXCHANGE_AuditorDenominationInfo);
- off = 0;
- json_array_foreach (keys, i, key) {
+ auditor->denom_keys
+ = GNUNET_new_array (json_array_size (keys),
+ struct TALER_EXCHANGE_AuditorDenominationInfo);
+
+ json_array_foreach (keys, off, key) {
struct TALER_AuditorSignatureP auditor_sig;
struct TALER_DenominationHashP denom_h;
- const struct TALER_EXCHANGE_DenomPublicKey *dk;
- unsigned int dk_off;
+ const struct TALER_EXCHANGE_DenomPublicKey *dk = NULL;
+ unsigned int dk_off = UINT_MAX;
struct GNUNET_JSON_Specification kspec[] = {
GNUNET_JSON_spec_fixed_auto ("auditor_sig",
&auditor_sig),
@@ -413,8 +352,6 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,
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 == GNUNET_memcmp (&denom_h,
@@ -454,7 +391,6 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,
}
auditor->denom_keys[off].denom_key_offset = dk_off;
auditor->denom_keys[off].auditor_sig = auditor_sig;
- off++;
}
auditor->num_denom_keys = off;
return GNUNET_OK;
@@ -466,7 +402,7 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,
*
* @param[out] gf where to return the result
* @param check_sigs should we check signatures
- * @param[in] fee_obj json to parse
+ * @param fee_obj json to parse
* @param key_data already parsed information about the exchange
* @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
* invalid or the json malformed.
@@ -474,7 +410,7 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,
static enum GNUNET_GenericReturnValue
parse_global_fee (struct TALER_EXCHANGE_GlobalFee *gf,
bool check_sigs,
- json_t *fee_obj,
+ const json_t *fee_obj,
const struct TALER_EXCHANGE_Keys *key_data)
{
struct GNUNET_JSON_Specification spec[] = {
@@ -532,104 +468,6 @@ parse_global_fee (struct TALER_EXCHANGE_GlobalFee *gf,
/**
- * Function called with information about the auditor. Marks an
- * auditor as 'up'.
- *
- * @param cls closure, a `struct TEAH_AuditorListEntry *`
- * @param vr response from the auditor
- */
-static void
-auditor_config_cb (
- void *cls,
- const struct TALER_AUDITOR_ConfigResponse *vr)
-{
- struct TEAH_AuditorListEntry *ale = cls;
- enum TALER_AUDITOR_VersionCompatibility compat;
-
- ale->ah = NULL;
- if (MHD_HTTP_OK != vr->hr.http_status)
- {
- /* In this case, we don't mark the auditor as 'up' */
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Auditor `%s' gave unexpected version response.\n",
- ale->auditor_url);
- return;
- }
- compat = vr->details.ok.compat;
- if (0 != (TALER_AUDITOR_VC_INCOMPATIBLE & compat))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Auditor `%s' runs incompatible protocol version!\n",
- ale->auditor_url);
- if (0 != (TALER_AUDITOR_VC_OLDER & compat))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Auditor `%s' runs outdated protocol version!\n",
- ale->auditor_url);
- }
- if (0 != (TALER_AUDITOR_VC_NEWER & compat))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Auditor `%s' runs more recent incompatible version. We should upgrade!\n",
- ale->auditor_url);
- }
- return;
- }
- ale->is_up = true;
-}
-
-
-/**
- * Recalculate our auditor list, we got /keys and it may have
- * changed.
- *
- * @param exchange exchange for which to update the list.
- */
-static void
-update_auditors (struct TALER_EXCHANGE_Handle *exchange)
-{
- struct TALER_EXCHANGE_Keys *kd = &exchange->key_data;
-
- TALER_LOG_DEBUG ("Updating auditors\n");
- for (unsigned int i = 0; i<kd->num_auditors; i++)
- {
- /* Compare auditor data from /keys with auditor data
- * from owned exchange structures. */
- struct TALER_EXCHANGE_AuditorInformation *auditor = &kd->auditors[i];
- struct TEAH_AuditorListEntry *ale = NULL;
-
- for (struct TEAH_AuditorListEntry *a = exchange->auditors_head;
- NULL != a;
- a = a->next)
- {
- if (0 == GNUNET_memcmp (&auditor->auditor_pub,
- &a->auditor_pub))
- {
- ale = a;
- break;
- }
- }
- if (NULL != ale)
- continue; /* found, no need to add */
-
- /* new auditor, add */
- TALER_LOG_DEBUG ("Found new auditor %s!\n",
- auditor->auditor_url);
- ale = GNUNET_new (struct TEAH_AuditorListEntry);
- ale->auditor_pub = auditor->auditor_pub;
- ale->auditor_url = GNUNET_strdup (auditor->auditor_url);
- GNUNET_CONTAINER_DLL_insert (exchange->auditors_head,
- exchange->auditors_tail,
- ale);
- ale->ah = TALER_AUDITOR_get_config (exchange->ctx,
- ale->auditor_url,
- &auditor_config_cb,
- ale);
- }
-}
-
-
-/**
* Compare two denomination keys. Ignores revocation data.
*
* @param denom1 first denomination key
@@ -683,35 +521,16 @@ decode_keys_json (const json_t *resp_obj,
struct TALER_ExchangeSignatureP denominations_sig;
struct GNUNET_HashCode hash_xor = {0};
struct TALER_ExchangePublicKeyP pub;
- const char *currency;
- const char *asset_type;
- bool tipping_allowed = true;
const json_t *wblwk = NULL;
- struct GNUNET_JSON_Specification mspec[] = {
- GNUNET_JSON_spec_fixed_auto ("denominations_sig",
- &denominations_sig),
- GNUNET_JSON_spec_fixed_auto ("eddsa_pub",
- &pub),
- GNUNET_JSON_spec_fixed_auto ("master_public_key",
- &key_data->master_pub),
- GNUNET_JSON_spec_timestamp ("list_issue_date",
- &key_data->list_issue_date),
- GNUNET_JSON_spec_relative_time ("reserve_closing_delay",
- &key_data->reserve_closing_delay),
- GNUNET_JSON_spec_string ("currency",
- &currency),
- GNUNET_JSON_spec_string ("asset_type",
- &asset_type),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_bool ("tipping_allowed",
- &tipping_allowed),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_array_const ("wallet_balance_limit_without_kyc",
- &wblwk),
- NULL),
- GNUNET_JSON_spec_end ()
- };
+ const json_t *global_fees;
+ const json_t *sign_keys_array;
+ const json_t *denominations_by_group;
+ const json_t *auditors_array;
+ const json_t *recoup_array = NULL;
+ struct TALER_MasterSignatureP extensions_sig = {0};
+ const json_t *manifests = NULL;
+ bool no_extensions = false;
+ bool no_signature = false;
if (JSON_OBJECT != json_typeof (resp_obj))
{
@@ -770,63 +589,116 @@ decode_keys_json (const json_t *resp_obj,
key_data->version = GNUNET_strdup (ver);
}
- EXITIF (GNUNET_OK !=
- GNUNET_JSON_parse (resp_obj,
- (check_sig) ? mspec : &mspec[2],
- NULL, NULL));
- key_data->currency = GNUNET_strdup (currency);
- key_data->asset_type = GNUNET_strdup (asset_type);
- key_data->tipping_allowed = tipping_allowed;
+ {
+ const char *currency;
+ const char *asset_type;
+ struct GNUNET_JSON_Specification mspec[] = {
+ GNUNET_JSON_spec_fixed_auto (
+ "denominations_sig",
+ &denominations_sig),
+ GNUNET_JSON_spec_fixed_auto (
+ "eddsa_pub",
+ &pub),
+ GNUNET_JSON_spec_fixed_auto (
+ "master_public_key",
+ &key_data->master_pub),
+ GNUNET_JSON_spec_timestamp (
+ "list_issue_date",
+ &key_data->list_issue_date),
+ GNUNET_JSON_spec_relative_time (
+ "reserve_closing_delay",
+ &key_data->reserve_closing_delay),
+ GNUNET_JSON_spec_string (
+ "currency",
+ &currency),
+ GNUNET_JSON_spec_string (
+ "asset_type",
+ &asset_type),
+ GNUNET_JSON_spec_array_const (
+ "global_fees",
+ &global_fees),
+ GNUNET_JSON_spec_array_const (
+ "signkeys",
+ &sign_keys_array),
+ GNUNET_JSON_spec_array_const (
+ "denominations",
+ &denominations_by_group),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_array_const (
+ "recoup",
+ &recoup_array),
+ NULL),
+ GNUNET_JSON_spec_array_const (
+ "auditors",
+ &auditors_array),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_bool (
+ "tipping_allowed",
+ &key_data->tipping_allowed),
+ NULL),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_object_const ("extensions",
+ &manifests),
+ &no_extensions),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_fixed_auto (
+ "extensions_sig",
+ &extensions_sig),
+ &no_signature),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_array_const (
+ "wallet_balance_limit_without_kyc",
+ &wblwk),
+ NULL),
+ GNUNET_JSON_spec_end ()
+ };
+
+ EXITIF (GNUNET_OK !=
+ GNUNET_JSON_parse (resp_obj,
+ (check_sig) ? mspec : &mspec[2],
+ NULL, NULL));
+ key_data->currency = GNUNET_strdup (currency);
+ key_data->asset_type = GNUNET_strdup (asset_type);
+ }
/* parse the global fees */
+ key_data->num_global_fees
+ = json_array_size (global_fees);
+ if (0 != key_data->num_global_fees)
{
- json_t *global_fees;
json_t *global_fee;
unsigned int index;
- EXITIF (NULL == (global_fees =
- json_object_get (resp_obj,
- "global_fees")));
- EXITIF (! json_is_array (global_fees));
- if (0 != (key_data->num_global_fees =
- json_array_size (global_fees)))
+ key_data->global_fees
+ = GNUNET_new_array (key_data->num_global_fees,
+ struct TALER_EXCHANGE_GlobalFee);
+ json_array_foreach (global_fees, index, global_fee)
{
- key_data->global_fees
- = GNUNET_new_array (key_data->num_global_fees,
- struct TALER_EXCHANGE_GlobalFee);
- json_array_foreach (global_fees, index, global_fee) {
- EXITIF (GNUNET_SYSERR ==
- parse_global_fee (&key_data->global_fees[index],
- check_sig,
- global_fee,
- key_data));
- }
+ EXITIF (GNUNET_SYSERR ==
+ parse_global_fee (&key_data->global_fees[index],
+ check_sig,
+ global_fee,
+ key_data));
}
}
/* parse the signing keys */
+ key_data->num_sign_keys
+ = json_array_size (sign_keys_array);
+ if (0 != key_data->num_sign_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_is_array (sign_keys_array));
- if (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);
- 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));
- }
+ key_data->sign_keys
+ = GNUNET_new_array (key_data->num_sign_keys,
+ struct TALER_EXCHANGE_SigningPublicKey);
+ 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));
}
}
@@ -844,7 +716,7 @@ decode_keys_json (const json_t *resp_obj,
i);
struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_amount (NULL,
- currency,
+ key_data->currency,
a),
GNUNET_JSON_spec_end ()
};
@@ -858,51 +730,28 @@ decode_keys_json (const json_t *resp_obj,
/* Parse the supported extension(s): age-restriction. */
/* TODO: maybe lift all this into a FP in TALER_Extension ? */
+ if (! no_extensions)
{
- struct TALER_MasterSignatureP extensions_sig = {0};
- const json_t *manifests = NULL;
- bool no_extensions = false;
- bool no_signature = false;
-
- struct GNUNET_JSON_Specification ext_spec[] = {
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_object_const ("extensions",
- &manifests),
- &no_extensions),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_fixed_auto (
- "extensions_sig",
- &extensions_sig),
- &no_signature),
- GNUNET_JSON_spec_end ()
- };
-
- /* 1. Search for extensions in the response to /keys */
- EXITIF (GNUNET_OK !=
- GNUNET_JSON_parse (resp_obj,
- ext_spec,
- NULL, NULL));
-
-
- if (! no_extensions && no_signature)
+ if (no_signature)
+ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"found extensions without signature\n");
-
- if (! no_extensions && ! no_signature)
+ }
+ else
{
- /* 2. We have an extensions object. Verify its signature. */
+ /* We have an extensions object. Verify its signature. */
EXITIF (GNUNET_OK !=
TALER_extensions_verify_manifests_signature (
manifests,
&extensions_sig,
&key_data->master_pub));
- /* 3. Parse and set the the configuration of the extensions accordingly */
+ /* Parse and set the the configuration of the extensions accordingly */
EXITIF (GNUNET_OK !=
TALER_extensions_load_manifests (manifests));
}
- /* 4. assuming we might have now a new value for age_mask, set it in key_data */
+ /* Assuming we might have now a new value for age_mask, set it in key_data */
key_data->age_mask = TALER_extensions_get_age_restriction_mask ();
}
@@ -912,21 +761,13 @@ decode_keys_json (const json_t *resp_obj,
*
* The denominations are grouped by common values of
* {cipher, value, fee, age_mask}.
- **/
+ */
{
- json_t *denominations_by_group;
json_t *group_obj;
unsigned int group_idx;
- denominations_by_group =
- json_object_get (
- resp_obj,
- "denominations");
-
- EXITIF (JSON_ARRAY !=
- json_typeof (denominations_by_group));
-
- json_array_foreach (denominations_by_group, group_idx, group_obj) {
+ json_array_foreach (denominations_by_group, group_idx, group_obj)
+ {
/* Running XOR of each SHA512 hash of the denominations' public key in
this group. Used to compare against group.hash after all keys have
been parsed. */
@@ -935,9 +776,13 @@ decode_keys_json (const json_t *resp_obj,
/* First, parse { cipher, fees, value, age_mask, hash } of the current
group. */
struct TALER_DenominationGroup group = {0};
+ const json_t *denom_keys_array;
struct GNUNET_JSON_Specification group_spec[] = {
TALER_JSON_spec_denomination_group (NULL,
- currency, &group),
+ key_data->currency,
+ &group),
+ GNUNET_JSON_spec_array_const ("denoms",
+ &denom_keys_array),
GNUNET_JSON_spec_end ()
};
EXITIF (GNUNET_SYSERR ==
@@ -948,25 +793,21 @@ decode_keys_json (const json_t *resp_obj,
/* Now, parse the individual denominations */
{
- json_t *denom_keys_array;
json_t *denom_key_obj;
unsigned int index;
- denom_keys_array = json_object_get (group_obj, "denoms");
- EXITIF (JSON_ARRAY != json_typeof (denom_keys_array));
-
- json_array_foreach (denom_keys_array, index, denom_key_obj) {
- struct TALER_EXCHANGE_DenomPublicKey dk = {0};
- bool found = false;
-
- memset (&dk, 0, sizeof (dk));
+ json_array_foreach (denom_keys_array, index, denom_key_obj)
+ {
/* Set the common fields from the group for this particular
denomination. Required to make the validity check inside
parse_json_denomkey_partially pass */
- dk.key.cipher = group.cipher;
- dk.value = group.value;
- dk.fees = group.fees;
- dk.key.age_mask = group.age_mask;
+ struct TALER_EXCHANGE_DenomPublicKey dk = {
+ .key.cipher = group.cipher,
+ .value = group.value,
+ .fees = group.fees,
+ .key.age_mask = group.age_mask
+ };
+ bool found = false;
EXITIF (GNUNET_SYSERR ==
parse_json_denomkey_partially (&dk,
@@ -979,7 +820,9 @@ decode_keys_json (const json_t *resp_obj,
/* Build the running xor of the SHA512-hash of the public keys */
{
struct TALER_DenominationHashP hc = {0};
- TALER_denom_pub_hash (&dk.key, &hc);
+
+ TALER_denom_pub_hash (&dk.key,
+ &hc);
GNUNET_CRYPTO_hash_xor (&hc.hash,
&group_hash_xor,
&group_hash_xor);
@@ -1017,30 +860,26 @@ decode_keys_json (const json_t *resp_obj,
key_data->last_denom_issue_date
= GNUNET_TIME_timestamp_max (key_data->last_denom_issue_date,
dk.valid_from);
- }; // json_array_foreach over denominations
+ }; /* end of json_array_foreach over denominations */
- // The calculated group_hash_xor must be the same as group.hash from
- // the json.
+ /* The calculated group_hash_xor must be the same as group.hash from
+ the JSON. */
EXITIF (0 !=
- GNUNET_CRYPTO_hash_cmp (&group_hash_xor, &group.hash));
+ GNUNET_CRYPTO_hash_cmp (&group_hash_xor,
+ &group.hash));
- } // block for parsing individual denominations
- }; // json_array_foreach over groups of denominations
+ } /* end of block for parsing individual denominations */
+ } /* end of json_array_foreach over groups of denominations */
}
/* 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) */
- json_array_foreach (auditors_array, index, auditor_info) {
+ json_array_foreach (auditors_array, index, auditor_info)
+ {
struct TALER_EXCHANGE_AuditorInformation ai;
bool found = false;
@@ -1105,41 +944,35 @@ decode_keys_json (const json_t *resp_obj,
}
/* parse the revocation/recoup information */
+ if (NULL != recoup_array)
{
- json_t *recoup_array;
json_t *recoup_info;
unsigned int index;
- if (NULL != (recoup_array =
- json_object_get (resp_obj,
- "recoup")))
+ json_array_foreach (recoup_array, index, recoup_info)
{
- EXITIF (JSON_ARRAY != json_typeof (recoup_array));
-
- json_array_foreach (recoup_array, index, recoup_info) {
- struct TALER_DenominationHashP h_denom_pub;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
- &h_denom_pub),
- GNUNET_JSON_spec_end ()
- };
-
- EXITIF (GNUNET_OK !=
- GNUNET_JSON_parse (recoup_info,
- spec,
- NULL, NULL));
- for (unsigned int j = 0;
- j<key_data->num_denom_keys;
- j++)
+ struct TALER_DenominationHashP h_denom_pub;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
+ &h_denom_pub),
+ GNUNET_JSON_spec_end ()
+ };
+
+ EXITIF (GNUNET_OK !=
+ GNUNET_JSON_parse (recoup_info,
+ spec,
+ NULL, NULL));
+ for (unsigned int j = 0;
+ j<key_data->num_denom_keys;
+ j++)
+ {
+ if (0 == GNUNET_memcmp (&h_denom_pub,
+ &key_data->denom_keys[j].h_key))
{
- if (0 == GNUNET_memcmp (&h_denom_pub,
- &key_data->denom_keys[j].h_key))
- {
- key_data->denom_keys[j].revoked = GNUNET_YES;
- break;
- }
+ key_data->denom_keys[j].revoked = true;
+ break;
}
- };
+ }
}
}
@@ -1148,7 +981,6 @@ decode_keys_json (const json_t *resp_obj,
EXITIF (GNUNET_OK !=
TALER_EXCHANGE_test_signing_key (key_data,
&pub));
-
EXITIF (GNUNET_OK !=
TALER_exchange_online_key_set_verify (
key_data->list_issue_date,
@@ -1156,7 +988,6 @@ decode_keys_json (const json_t *resp_obj,
&pub,
&denominations_sig));
}
-
return GNUNET_OK;
EXITIF_exit:
@@ -1166,101 +997,6 @@ EXITIF_exit:
/**
- * 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++)
- TALER_denom_pub_free (&key_data->denom_keys[i].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 (key_data->wallet_balance_limit_without_kyc);
- GNUNET_free (key_data->version);
- GNUNET_free (key_data->currency);
- GNUNET_free (key_data->asset_type);
- GNUNET_free (key_data->global_fees);
-}
-
-
-/**
- * Initiate download of /keys from the exchange.
- *
- * @param cls exchange where to download /keys from
- */
-static void
-request_keys (void *cls);
-
-
-void
-TALER_EXCHANGE_set_last_denom (struct TALER_EXCHANGE_Handle *exchange,
- struct GNUNET_TIME_Timestamp last_denom_new)
-{
- TALER_LOG_DEBUG (
- "Application explicitly set last denomination validity to %s\n",
- GNUNET_TIME_timestamp2s (last_denom_new));
- exchange->key_data.last_denom_issue_date = last_denom_new;
-}
-
-
-struct GNUNET_TIME_Timestamp
-TALER_EXCHANGE_check_keys_current (struct TALER_EXCHANGE_Handle *exchange,
- enum TALER_EXCHANGE_CheckKeysFlags flags,
- TALER_EXCHANGE_CertificationCallback cb,
- void *cb_cls)
-{
- bool force_download = 0 != (flags & TALER_EXCHANGE_CKF_FORCE_DOWNLOAD);
- bool pull_all_keys = 0 != (flags & TALER_EXCHANGE_CKF_PULL_ALL_KEYS);
-
- GNUNET_assert (NULL != exchange);
-
- if ( (NULL != cb) &&
- ( (exchange->cert_cb != cb) ||
- (exchange->cert_cb_cls != cb_cls) ) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Changing target of exchange certification callback\n");
- exchange->cert_cb = cb;
- exchange->cert_cb_cls = cb_cls;
- }
- if (NULL != exchange->kr)
- return GNUNET_TIME_UNIT_ZERO_TS;
- if (pull_all_keys)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Forcing re-download of all exchange keys\n");
- GNUNET_break (force_download);
- exchange->state = MHS_INIT;
- }
- if ( (! force_download) &&
- (GNUNET_TIME_absolute_is_future (
- exchange->key_data_expiration.abs_time)) )
- 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_TS;
-}
-
-
-/**
* Callback used when downloading the reply to a /keys request
* is complete.
*
@@ -1273,133 +1009,107 @@ 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_old;
+ struct TALER_EXCHANGE_GetKeysHandle *gkh = cls;
const json_t *j = resp_obj;
- struct TALER_EXCHANGE_Keys kd;
+ struct TALER_EXCHANGE_Keys *kd = NULL;
struct TALER_EXCHANGE_KeysResponse kresp = {
.hr.reply = j,
.hr.http_status = (unsigned int) response_code,
.details.ok.compat = TALER_EXCHANGE_VC_PROTOCOL_ERROR,
};
- memset (&kd,
- 0,
- sizeof (kd));
+ gkh->job = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Received keys from URL `%s' with status %ld and expiration %s.\n",
- kr->url,
+ gkh->url,
response_code,
- GNUNET_TIME_timestamp2s (kr->expire));
- if (GNUNET_TIME_absolute_is_past (kr->expire.abs_time))
+ GNUNET_TIME_timestamp2s (gkh->expire));
+ if (GNUNET_TIME_absolute_is_past (gkh->expire.abs_time))
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Exchange failed to give expiration time, assuming in %s\n",
GNUNET_TIME_relative2s (DEFAULT_EXPIRATION,
true));
- kr->expire
+ gkh->expire
= GNUNET_TIME_absolute_to_timestamp (
GNUNET_TIME_relative_to_absolute (DEFAULT_EXPIRATION));
}
- kd_old = exchange->key_data;
switch (response_code)
{
case 0:
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to receive /keys response from exchange %s\n",
- exchange->url);
- free_keys_request (kr);
- exchange->keys_error_count++;
- 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;
+ gkh->exchange_url);
+ break;
case MHD_HTTP_OK:
- exchange->keys_error_count = 0;
if (NULL == j)
{
+ GNUNET_break (0);
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... */
- GNUNET_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++)
- TALER_denom_pub_deep_copy (&kd.denom_keys[i].key,
- &kd_old.denom_keys[i].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++)
+ kd = GNUNET_new (struct TALER_EXCHANGE_Keys);
+ kd->exchange_url = GNUNET_strdup (gkh->exchange_url);
+ if (NULL != gkh->prev_keys)
{
- const struct TALER_EXCHANGE_AuditorInformation *aold =
- &kd_old.auditors[i];
- struct TALER_EXCHANGE_AuditorInformation *anew = &kd.auditors[i];
-
- anew->auditor_pub = aold->auditor_pub;
- GNUNET_assert (NULL != aold->auditor_url);
- anew->auditor_url = GNUNET_strdup (aold->auditor_url);
- GNUNET_array_grow (anew->denom_keys,
- anew->num_denom_keys,
- aold->num_denom_keys);
- GNUNET_memcpy (anew->denom_keys,
- aold->denom_keys,
- aold->num_denom_keys
- * sizeof (struct TALER_EXCHANGE_AuditorDenominationInfo));
- }
+ const struct TALER_EXCHANGE_Keys *kd_old = gkh->prev_keys;
+
+ /* 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... */
+ GNUNET_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++)
+ TALER_denom_pub_deep_copy (&kd->denom_keys[i].key,
+ &kd_old->denom_keys[i].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];
- /* Old auditors got just copied into new ones. */
+ 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);
+ GNUNET_memcpy (
+ anew->denom_keys,
+ aold->denom_keys,
+ aold->num_denom_keys
+ * sizeof (struct TALER_EXCHANGE_AuditorDenominationInfo));
+ }
+ }
+ /* Now decode fresh /keys response */
if (GNUNET_OK !=
decode_keys_json (j,
true,
- &kd,
+ kd,
&kresp.details.ok.compat))
{
TALER_LOG_ERROR ("Could not decode /keys response\n");
+ kd->rc = 1;
+ TALER_EXCHANGE_keys_decref (kd);
+ kd = NULL;
kresp.hr.http_status = 0;
kresp.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
- 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++)
- TALER_denom_pub_free (&kd.denom_keys[i].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;
+ kd->rc = 1;
+ kresp.details.ok.keys = kd;
break;
case MHD_HTTP_BAD_REQUEST:
case MHD_HTTP_UNAUTHORIZED:
@@ -1417,8 +1127,6 @@ keys_completed_cb (void *cls,
}
break;
default:
- if (MHD_HTTP_GATEWAY_TIMEOUT == response_code)
- exchange->keys_error_count++;
if (NULL == j)
{
kresp.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
@@ -1435,78 +1143,10 @@ keys_completed_cb (void *cls,
(int) kresp.hr.ec);
break;
}
- exchange->key_data = kd;
- if (GNUNET_TIME_absolute_is_past (
- exchange->key_data.last_denom_issue_date.abs_time))
- TALER_LOG_WARNING ("Last DK issue date from exchange is in the past: %s\n",
- GNUNET_TIME_timestamp2s (
- exchange->key_data.last_denom_issue_date));
- else
- TALER_LOG_DEBUG ("Last DK issue date updated to: %s\n",
- GNUNET_TIME_timestamp2s (
- exchange->key_data.last_denom_issue_date));
-
-
- if (MHD_HTTP_OK != response_code)
- {
- exchange->kr = NULL;
- free_keys_request (kr);
- exchange->state = MHS_FAILED;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Exchange keys download failed\n");
- 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,
- &kresp);
- return;
- }
-
- exchange->kr = NULL;
- exchange->key_data_expiration = kr->expire;
- free_keys_request (kr);
- exchange->state = MHS_CERT;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Successfully downloaded exchange's keys\n");
- update_auditors (exchange);
- kresp.details.ok.keys = &exchange->key_data;
-
- /* notify application about the key information */
- exchange->cert_cb (exchange->cert_cb_cls,
- &kresp);
- free_key_data (&kd_old);
-}
-
-
-/* ********************* library internal API ********* */
-
-
-struct GNUNET_CURL_Context *
-TEAH_handle_to_context (struct TALER_EXCHANGE_Handle *h)
-{
- return h->ctx;
-}
-
-
-enum GNUNET_GenericReturnValue
-TEAH_handle_is_ready (struct TALER_EXCHANGE_Handle *h)
-{
- return (MHS_CERT == h->state) ? GNUNET_YES : GNUNET_NO;
-}
-
-
-char *
-TEAH_path_to_url (struct TALER_EXCHANGE_Handle *h,
- const char *path)
-{
- GNUNET_assert ('/' == path[0]);
- return TALER_url_join (h->url,
- path + 1,
- NULL);
+ gkh->cert_cb (gkh->cert_cb_cls,
+ &kresp,
+ kd);
+ TALER_EXCHANGE_get_keys_cancel (gkh);
}
@@ -1520,7 +1160,7 @@ TEAH_path_to_url (struct TALER_EXCHANGE_Handle *h,
* Parse HTTP timestamp.
*
* @param dateline header to parse header
- * @param at where to write the result
+ * @param[out] at where to write the result
* @return #GNUNET_OK on success
*/
static enum GNUNET_GenericReturnValue
@@ -1620,7 +1260,7 @@ parse_date_string (const char *dateline,
* @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`
+ * @param userdata the `struct TALER_EXCHANGE_GetKeysHandle`
* @return `size * nitems` on success (everything else aborts)
*/
static size_t
@@ -1629,7 +1269,7 @@ header_cb (char *buffer,
size_t nitems,
void *userdata)
{
- struct KeysRequest *kr = userdata;
+ struct TALER_EXCHANGE_GetKeysHandle *kr = userdata;
size_t total = size * nitems;
char *val;
@@ -1656,22 +1296,249 @@ header_cb (char *buffer,
}
-/* ********************* public API ******************* */
+struct TALER_EXCHANGE_GetKeysHandle *
+TALER_EXCHANGE_get_keys (
+ struct GNUNET_CURL_Context *ctx,
+ const char *url,
+ struct TALER_EXCHANGE_Keys *last_keys,
+ TALER_EXCHANGE_GetKeysCallback cert_cb,
+ void *cert_cb_cls)
+{
+ struct TALER_EXCHANGE_GetKeysHandle *gkh;
+ CURL *eh;
+ char last_date[80] = { 0 };
+ TALER_LOG_DEBUG ("Connecting to the exchange (%s)\n",
+ url);
+ gkh = GNUNET_new (struct TALER_EXCHANGE_GetKeysHandle);
+ gkh->exchange_url = GNUNET_strdup (url);
+ gkh->cert_cb = cert_cb;
+ gkh->cert_cb_cls = cert_cb_cls;
+ if (NULL != last_keys)
+ {
+ TALER_LOG_DEBUG ("Last DK issue date (before GETting /keys): %s\n",
+ GNUNET_TIME_timestamp2s (
+ last_keys->last_denom_issue_date));
+ GNUNET_snprintf (last_date,
+ sizeof (last_date),
+ "%llu",
+ (unsigned long long)
+ last_keys->last_denom_issue_date.abs_time.abs_value_us
+ / 1000000LLU);
+ }
+ gkh->url = TALER_url_join (url,
+ "keys",
+ (NULL != last_keys)
+ ? "last_issue_date"
+ : NULL,
+ (NULL != last_keys)
+ ? last_date
+ : NULL,
+ NULL);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Requesting keys with URL `%s'.\n",
+ gkh->url);
+ eh = TALER_EXCHANGE_curl_easy_get_ (gkh->url);
+ if (NULL == eh)
+ {
+ GNUNET_break (0);
+ GNUNET_free (gkh->exchange_url);
+ GNUNET_free (gkh->url);
+ GNUNET_free (gkh);
+ return NULL;
+ }
+ GNUNET_break (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_VERBOSE,
+ 0));
+ GNUNET_break (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_TIMEOUT,
+ 120 /* seconds */));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_HEADERFUNCTION,
+ &header_cb));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_HEADERDATA,
+ gkh));
+ gkh->job = GNUNET_CURL_job_add_with_ct_json (ctx,
+ eh,
+ &keys_completed_cb,
+ gkh);
+ return gkh;
+}
-/**
- * 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
- * @param data the data to deserialize
- */
-static void
-deserialize_data (struct TALER_EXCHANGE_Handle *exchange,
- const json_t *data)
+
+void
+TALER_EXCHANGE_get_keys_cancel (
+ struct TALER_EXCHANGE_GetKeysHandle *gkh)
{
- const json_t *keys;
+ if (NULL != gkh->job)
+ {
+ GNUNET_CURL_job_cancel (gkh->job);
+ gkh->job = NULL;
+ }
+ TALER_EXCHANGE_keys_decref (gkh->prev_keys);
+ GNUNET_free (gkh->exchange_url);
+ GNUNET_free (gkh->url);
+ GNUNET_free (gkh);
+}
+
+
+enum GNUNET_GenericReturnValue
+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 ( (GNUNET_TIME_absolute_cmp (
+ keys->sign_keys[i].valid_from.abs_time,
+ <=,
+ GNUNET_TIME_absolute_add (now,
+ LIFETIME_TOLERANCE))) &&
+ (GNUNET_TIME_absolute_cmp (
+ keys->sign_keys[i].valid_until.abs_time,
+ >,
+ GNUNET_TIME_absolute_subtract (now,
+ LIFETIME_TOLERANCE))) &&
+ (0 == GNUNET_memcmp (pub,
+ &keys->sign_keys[i].key)) )
+ return GNUNET_OK;
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Signing key not valid at time %s\n",
+ GNUNET_TIME_absolute2s (now));
+ return GNUNET_SYSERR;
+}
+
+
+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 ==
+ TALER_denom_pub_cmp (pk,
+ &keys->denom_keys[i].key))
+ return &keys->denom_keys[i];
+ return NULL;
+}
+
+
+const struct TALER_EXCHANGE_GlobalFee *
+TALER_EXCHANGE_get_global_fee (
+ const struct TALER_EXCHANGE_Keys *keys,
+ struct GNUNET_TIME_Timestamp ts)
+{
+ for (unsigned int i = 0; i<keys->num_global_fees; i++)
+ {
+ const struct TALER_EXCHANGE_GlobalFee *gf = &keys->global_fees[i];
+
+ if (GNUNET_TIME_timestamp_cmp (ts,
+ >=,
+ gf->start_date) &&
+ GNUNET_TIME_timestamp_cmp (ts,
+ <,
+ gf->end_date))
+ return gf;
+ }
+ return NULL;
+}
+
+
+struct TALER_EXCHANGE_DenomPublicKey *
+TALER_EXCHANGE_copy_denomination_key (
+ const struct TALER_EXCHANGE_DenomPublicKey *key)
+{
+ struct TALER_EXCHANGE_DenomPublicKey *copy;
+
+ copy = GNUNET_new (struct TALER_EXCHANGE_DenomPublicKey);
+ *copy = *key;
+ TALER_denom_pub_deep_copy (&copy->key,
+ &key->key);
+ return copy;
+}
+
+
+void
+TALER_EXCHANGE_destroy_denomination_key (
+ struct TALER_EXCHANGE_DenomPublicKey *key)
+{
+ TALER_denom_pub_free (&key->key);
+ GNUNET_free (key);
+}
+
+
+const struct TALER_EXCHANGE_DenomPublicKey *
+TALER_EXCHANGE_get_denomination_key_by_hash (
+ const struct TALER_EXCHANGE_Keys *keys,
+ const struct TALER_DenominationHashP *hc)
+{
+ for (unsigned int i = 0; i<keys->num_denom_keys; i++)
+ if (0 == GNUNET_memcmp (hc,
+ &keys->denom_keys[i].h_key))
+ return &keys->denom_keys[i];
+ return NULL;
+}
+
+
+struct TALER_EXCHANGE_Keys *
+TALER_EXCHANGE_keys_incref (struct TALER_EXCHANGE_Keys *keys)
+{
+ GNUNET_assert (keys->rc < UINT_MAX);
+ keys->rc++;
+ return keys;
+}
+
+
+void
+TALER_EXCHANGE_keys_decref (struct TALER_EXCHANGE_Keys *keys)
+{
+ if (NULL == keys)
+ return;
+ GNUNET_assert (0 < keys->rc);
+ keys->rc--;
+ if (0 != keys->rc)
+ return;
+ GNUNET_array_grow (keys->sign_keys,
+ keys->num_sign_keys,
+ 0);
+ for (unsigned int i = 0; i<keys->num_denom_keys; i++)
+ TALER_denom_pub_free (&keys->denom_keys[i].key);
+
+ GNUNET_array_grow (keys->denom_keys,
+ keys->denom_keys_size,
+ 0);
+ for (unsigned int i = 0; i<keys->num_auditors; i++)
+ {
+ GNUNET_array_grow (keys->auditors[i].denom_keys,
+ keys->auditors[i].num_denom_keys,
+ 0);
+ GNUNET_free (keys->auditors[i].auditor_url);
+ }
+ GNUNET_array_grow (keys->auditors,
+ keys->auditors_size,
+ 0);
+ GNUNET_free (keys->wallet_balance_limit_without_kyc);
+ GNUNET_free (keys->version);
+ GNUNET_free (keys->currency);
+ GNUNET_free (keys->asset_type);
+ GNUNET_free (keys->global_fees);
+ GNUNET_free (keys->exchange_url);
+ GNUNET_free (keys);
+}
+
+
+struct TALER_EXCHANGE_Keys *
+TALER_EXCHANGE_keys_from_json (const json_t *j)
+{
+ const json_t *jkeys;
const char *url;
uint32_t version;
struct GNUNET_TIME_Timestamp expire;
@@ -1679,72 +1546,50 @@ deserialize_data (struct TALER_EXCHANGE_Handle *exchange,
GNUNET_JSON_spec_uint32 ("version",
&version),
GNUNET_JSON_spec_array_const ("keys",
- &keys),
+ &jkeys),
GNUNET_JSON_spec_string ("exchange_url",
&url),
GNUNET_JSON_spec_timestamp ("expire",
&expire),
GNUNET_JSON_spec_end ()
};
- struct TALER_EXCHANGE_Keys key_data;
- struct TALER_EXCHANGE_KeysResponse kresp = {
- .hr.ec = TALER_EC_NONE,
- .hr.http_status = MHD_HTTP_OK,
- .hr.reply = data,
- .details.ok.keys = &exchange->key_data
- };
+ struct TALER_EXCHANGE_Keys *keys;
+ enum TALER_EXCHANGE_VersionCompatibility compat;
- if (NULL == data)
- return;
+ if (NULL == j)
+ return NULL;
if (GNUNET_OK !=
- GNUNET_JSON_parse (data,
+ GNUNET_JSON_parse (j,
spec,
NULL, NULL))
{
GNUNET_break_op (0);
- return;
+ return NULL;
}
if (0 != version)
{
- return; /* unsupported version */
+ return NULL; /* unsupported version */
}
- if (0 != strcmp (url,
- exchange->url))
- {
- GNUNET_break (0);
- return;
- }
- memset (&key_data,
- 0,
- sizeof (struct TALER_EXCHANGE_Keys));
+ keys = GNUNET_new (struct TALER_EXCHANGE_Keys);
if (GNUNET_OK !=
- decode_keys_json (keys,
+ decode_keys_json (jkeys,
false,
- &key_data,
- &kresp.details.ok.compat))
+ keys,
+ &compat))
{
GNUNET_break (0);
- return;
+ return NULL;
}
- /* 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;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Successfully loaded exchange's keys via deserialization\n");
- update_auditors (exchange);
- /* notify application about the key information */
- exchange->cert_cb (exchange->cert_cb_cls,
- &kresp);
+ keys->rc = 1;
+ keys->key_data_expiration = expire;
+ keys->exchange_url = GNUNET_strdup (url);
+ return keys;
}
json_t *
-TALER_EXCHANGE_serialize_data (struct TALER_EXCHANGE_Handle *exchange)
+TALER_EXCHANGE_keys_to_json (const struct TALER_EXCHANGE_Keys *kd)
{
- const struct TALER_EXCHANGE_Keys *kd = &exchange->key_data;
struct GNUNET_TIME_Timestamp now;
json_t *keys;
json_t *signkeys;
@@ -1903,371 +1748,12 @@ TALER_EXCHANGE_serialize_data (struct TALER_EXCHANGE_Handle *exchange)
GNUNET_JSON_pack_uint64 ("version",
EXCHANGE_SERIALIZATION_FORMAT_VERSION),
GNUNET_JSON_pack_timestamp ("expire",
- exchange->key_data_expiration),
+ kd->key_data_expiration),
GNUNET_JSON_pack_string ("exchange_url",
- exchange->url),
+ kd->exchange_url),
GNUNET_JSON_pack_object_steal ("keys",
keys));
}
-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;
-
- TALER_LOG_DEBUG ("Connecting to the exchange (%s)\n",
- url);
- /* Disable 100 continue processing */
- GNUNET_break (GNUNET_OK ==
- GNUNET_CURL_append_header (ctx,
- MHD_HTTP_HEADER_EXPECT ":"));
- 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;
-}
-
-
-/**
- * Compute the network timeout for the next request to /keys.
- *
- * @param exchange the exchange handle
- * @returns the timeout in seconds (for use by CURL)
- */
-static long
-get_keys_timeout_seconds (struct TALER_EXCHANGE_Handle *exchange)
-{
- unsigned int kec;
-
- /* if retry counter >= 8, do not bother to go further, we
- stop the exponential back-off at 128 anyway. */
- kec = GNUNET_MIN (7,
- exchange->keys_error_count);
- return GNUNET_MIN (120,
- 5 + (1L << kec));
-}
-
-
-/**
- * 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;
- char url[200] = "/keys?";
-
- 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))
- {
- TALER_LOG_DEBUG ("Last DK issue date (before GETting /keys): %s\n",
- GNUNET_TIME_timestamp2s (
- exchange->key_data.last_denom_issue_date));
- sprintf (&url[strlen (url)],
- "last_issue_date=%llu&",
- (unsigned long long)
- exchange->key_data.last_denom_issue_date.abs_time.abs_value_us
- / 1000000LLU);
- }
-
- /* Clean the last '&'/'?' sign that we optimistically put. */
- url[strlen (url) - 1] = '\0';
- kr->url = TEAH_path_to_url (exchange,
- url);
- if (NULL == kr->url)
- {
- struct TALER_EXCHANGE_KeysResponse kresp = {
- .hr.ec = TALER_EC_GENERIC_CONFIGURATION_INVALID,
- /* Next line is technically unnecessary, as the
- http status we set is 0 */
- .details.ok.compat = TALER_EXCHANGE_VC_PROTOCOL_ERROR
- };
-
- GNUNET_free (kr);
- exchange->keys_error_count++;
- exchange->state = MHS_FAILED;
- exchange->cert_cb (exchange->cert_cb_cls,
- &kresp);
- return;
- }
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Requesting keys with URL `%s'.\n",
- kr->url);
- eh = TALER_EXCHANGE_curl_easy_get_ (kr->url);
- if (NULL == eh)
- {
- GNUNET_free (kr->url);
- GNUNET_free (kr);
- exchange->retry_delay = EXCHANGE_LIB_BACKOFF (exchange->retry_delay);
- exchange->retry_task = GNUNET_SCHEDULER_add_delayed (exchange->retry_delay,
- &request_keys,
- exchange);
- return;
- }
- GNUNET_break (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_VERBOSE,
- 0));
- GNUNET_break (CURLE_OK ==
- curl_easy_setopt (eh,
- CURLOPT_TIMEOUT,
- get_keys_timeout_seconds (exchange)));
- 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_with_ct_json (exchange->ctx,
- eh,
- &keys_completed_cb,
- kr);
- exchange->kr = kr;
-}
-
-
-void
-TALER_EXCHANGE_disconnect (struct TALER_EXCHANGE_Handle *exchange)
-{
- struct TEAH_AuditorListEntry *ale;
-
- while (NULL != (ale = exchange->auditors_head))
- {
- GNUNET_CONTAINER_DLL_remove (exchange->auditors_head,
- exchange->auditors_tail,
- ale);
- if (NULL != ale->ah)
- {
- TALER_AUDITOR_get_config_cancel (ale->ah);
- ale->ah = NULL;
- }
- GNUNET_free (ale->auditor_url);
- GNUNET_free (ale);
- }
- 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);
-}
-
-
-enum GNUNET_GenericReturnValue
-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 ( (GNUNET_TIME_absolute_cmp (
- keys->sign_keys[i].valid_from.abs_time,
- <=,
- GNUNET_TIME_absolute_add (now,
- LIFETIME_TOLERANCE))) &&
- (GNUNET_TIME_absolute_cmp (
- keys->sign_keys[i].valid_until.abs_time,
- >,
- GNUNET_TIME_absolute_subtract (now,
- LIFETIME_TOLERANCE))) &&
- (0 == GNUNET_memcmp (pub,
- &keys->sign_keys[i].key)) )
- return GNUNET_OK;
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Signing key not valid at time %s\n",
- GNUNET_TIME_absolute2s (now));
- return GNUNET_SYSERR;
-}
-
-
-const char *
-TALER_EXCHANGE_get_base_url (const struct TALER_EXCHANGE_Handle *exchange)
-{
- return exchange->url;
-}
-
-
-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 ==
- TALER_denom_pub_cmp (pk,
- &keys->denom_keys[i].key))
- return &keys->denom_keys[i];
- return NULL;
-}
-
-
-const struct TALER_EXCHANGE_GlobalFee *
-TALER_EXCHANGE_get_global_fee (
- const struct TALER_EXCHANGE_Keys *keys,
- struct GNUNET_TIME_Timestamp ts)
-{
- for (unsigned int i = 0; i<keys->num_global_fees; i++)
- {
- const struct TALER_EXCHANGE_GlobalFee *gf = &keys->global_fees[i];
-
- if (GNUNET_TIME_timestamp_cmp (ts,
- >=,
- gf->start_date) &&
- GNUNET_TIME_timestamp_cmp (ts,
- <,
- gf->end_date))
- return gf;
- }
- return NULL;
-}
-
-
-struct TALER_EXCHANGE_DenomPublicKey *
-TALER_EXCHANGE_copy_denomination_key (
- const struct TALER_EXCHANGE_DenomPublicKey *key)
-{
- struct TALER_EXCHANGE_DenomPublicKey *copy;
-
- copy = GNUNET_new (struct TALER_EXCHANGE_DenomPublicKey);
- *copy = *key;
- TALER_denom_pub_deep_copy (&copy->key,
- &key->key);
- return copy;
-}
-
-
-void
-TALER_EXCHANGE_destroy_denomination_key (
- struct TALER_EXCHANGE_DenomPublicKey *key)
-{
- TALER_denom_pub_free (&key->key);
- GNUNET_free (key);
-}
-
-
-const struct TALER_EXCHANGE_DenomPublicKey *
-TALER_EXCHANGE_get_denomination_key_by_hash (
- const struct TALER_EXCHANGE_Keys *keys,
- const struct TALER_DenominationHashP *hc)
-{
- for (unsigned int i = 0; i<keys->num_denom_keys; i++)
- if (0 == GNUNET_memcmp (hc,
- &keys->denom_keys[i].h_key))
- return &keys->denom_keys[i];
- return NULL;
-}
-
-
-struct TALER_EXCHANGE_Keys *
-TALER_EXCHANGE_get_keys (struct TALER_EXCHANGE_Handle *exchange)
-{
- (void) TALER_EXCHANGE_check_keys_current (exchange,
- TALER_EXCHANGE_CKF_NONE,
- NULL,
- NULL);
- return &exchange->key_data;
-}
-
-
-json_t *
-TALER_EXCHANGE_get_keys_raw (struct TALER_EXCHANGE_Handle *exchange)
-{
- (void) TALER_EXCHANGE_check_keys_current (exchange,
- TALER_EXCHANGE_CKF_NONE,
- NULL,
- NULL);
- return json_deep_copy (exchange->key_data_raw);
-}
-
-
-/**
- * Obtain the keys from the exchange in the raw JSON format.
- *
- * @param keys the keys structure
- * @return the keys in raw JSON
- */
-json_t *
-TALER_EXCHANGE_keys_to_json (struct TALER_EXCHANGE_Keys *keys)
-{
- // FIXME!
- return NULL;
-}
-
-
-struct TALER_EXCHANGE_Keys *
-TALER_EXCHANGE_keys_incref (struct TALER_EXCHANGE_Keys *keys)
-{
- // FIXME
- return keys;
-}
-
-
-void
-TALER_EXCHANGE_keys_decref (struct TALER_EXCHANGE_Keys *keys)
-{
- // FIXME
-}
-
-
/* end of exchange_api_handle.c */