summaryrefslogtreecommitdiff
path: root/src/exchange
diff options
context:
space:
mode:
Diffstat (limited to 'src/exchange')
-rw-r--r--src/exchange/taler-exchange-httpd.c12
-rw-r--r--src/exchange/taler-exchange-httpd.h6
-rw-r--r--src/exchange/taler-exchange-httpd_db.c2
-rw-r--r--src/exchange/taler-exchange-httpd_deposit.c4
-rw-r--r--src/exchange/taler-exchange-httpd_extensions.c16
-rw-r--r--src/exchange/taler-exchange-httpd_keys.c100
-rw-r--r--src/exchange/taler-exchange-httpd_management_extensions.c110
-rw-r--r--src/exchange/taler-exchange-httpd_management_post_keys.c2
-rw-r--r--src/exchange/taler-exchange-httpd_melt.c8
-rw-r--r--src/exchange/taler-exchange-httpd_recoup-refresh.c2
-rw-r--r--src/exchange/taler-exchange-httpd_recoup.c2
-rw-r--r--src/exchange/taler-exchange-httpd_refreshes_reveal.c38
-rw-r--r--src/exchange/taler-exchange-httpd_responses.c12
13 files changed, 227 insertions, 87 deletions
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
index 06ad7ca9d..a0d0aa3b6 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -128,6 +128,12 @@ char *TEH_currency;
char *TEH_base_url;
/**
+ * Age restriction flags and mask
+ */
+bool TEH_age_restriction_enabled = false;
+struct TALER_AgeMask TEH_age_mask = {0};
+
+/**
* Default timeout in seconds for HTTP requests.
*/
static unsigned int connection_timeout = 30;
@@ -737,6 +743,12 @@ handle_post_management (struct TEH_RequestContext *rc,
return TEH_handler_management_post_wire_fees (rc->connection,
root);
}
+ if (0 == strcmp (args[0],
+ "extensions"))
+ {
+ return TEH_handler_management_post_extensions (rc->connection,
+ root);
+ }
GNUNET_break_op (0);
return r404 (rc->connection,
"/management/*");
diff --git a/src/exchange/taler-exchange-httpd.h b/src/exchange/taler-exchange-httpd.h
index d3b1ba84a..ffbce0e9b 100644
--- a/src/exchange/taler-exchange-httpd.h
+++ b/src/exchange/taler-exchange-httpd.h
@@ -186,6 +186,12 @@ extern struct TALER_EXCHANGEDB_Plugin *TEH_plugin;
*/
extern char *TEH_currency;
+/*
+ * Age restriction extension state
+ */
+extern bool TEH_age_restriction_enabled;
+extern struct TALER_AgeMask TEH_age_mask;
+
/**
* Our (externally visible) base URL.
*/
diff --git a/src/exchange/taler-exchange-httpd_db.c b/src/exchange/taler-exchange-httpd_db.c
index 3600d7931..f331e17d2 100644
--- a/src/exchange/taler-exchange-httpd_db.c
+++ b/src/exchange/taler-exchange-httpd_db.c
@@ -50,7 +50,7 @@ TEH_make_coin_known (const struct TALER_CoinPublicInfo *coin,
{
enum TALER_EXCHANGEDB_CoinKnownStatus cks;
struct TALER_DenominationHash h_denom_pub;
- struct TALER_AgeHash age_hash;
+ struct TALER_AgeCommitmentHash age_hash;
/* make sure coin is 'known' in database */
cks = TEH_plugin->ensure_coin_known (TEH_plugin->cls,
diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c
index 053552f2a..d750ec70e 100644
--- a/src/exchange/taler-exchange-httpd_deposit.c
+++ b/src/exchange/taler-exchange-httpd_deposit.c
@@ -240,6 +240,9 @@ TEH_handler_deposit (struct MHD_Connection *connection,
&deposit.merchant_pub),
GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
&deposit.h_contract_terms),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
+ &deposit.coin.age_commitment_hash)),
GNUNET_JSON_spec_fixed_auto ("coin_sig",
&deposit.csig),
GNUNET_JSON_spec_timestamp ("timestamp",
@@ -397,6 +400,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
&deposit.deposit_fee,
&h_wire,
&deposit.h_contract_terms,
+ &deposit.coin.age_commitment_hash,
NULL /* h_extensions! */,
&deposit.coin.denom_pub_hash,
deposit.timestamp,
diff --git a/src/exchange/taler-exchange-httpd_extensions.c b/src/exchange/taler-exchange-httpd_extensions.c
index 8edb24d40..6894a0762 100644
--- a/src/exchange/taler-exchange-httpd_extensions.c
+++ b/src/exchange/taler-exchange-httpd_extensions.c
@@ -127,6 +127,16 @@ extension_update_event_cb (void *cls,
GNUNET_break (0);
}
}
+
+ /* Special case age restriction: Update global flag and mask */
+ if (TALER_Extension_AgeRestriction == type)
+ {
+ TEH_age_mask.mask = 0;
+ TEH_age_restriction_enabled =
+ TALER_extensions_age_restriction_is_enabled ();
+ if (TEH_age_restriction_enabled)
+ TEH_age_mask = TALER_extensions_age_restriction_ageMask ();
+ }
}
@@ -151,6 +161,12 @@ TEH_extensions_init ()
return GNUNET_SYSERR;
}
+ /* FIXME: shall we load the extensions from the config right away?
+ * We do have to for now, as otherwise denominations with age restriction
+ * will not have the age mask set right upon initial generation.
+ */
+ TALER_extensions_load_taler_config (TEH_cfg);
+
/* Trigger the initial load of configuration from the db */
for (const struct TALER_Extension *it = TALER_extensions_get_head ();
NULL != it->next;
diff --git a/src/exchange/taler-exchange-httpd_keys.c b/src/exchange/taler-exchange-httpd_keys.c
index 4b1a6213c..d1dfb28b9 100644
--- a/src/exchange/taler-exchange-httpd_keys.c
+++ b/src/exchange/taler-exchange-httpd_keys.c
@@ -795,27 +795,17 @@ static struct TALER_AgeMask
load_age_mask (const char*section_name)
{
static const struct TALER_AgeMask null_mask = {0};
- struct TALER_AgeMask age_mask = {0};
- /* TODO: optimize by putting this into global? */
- const struct TALER_Extension *age_ext =
- TALER_extensions_get_by_type (TALER_Extension_AgeRestriction);
-
- // Get the age mask from the extension, if configured
- /* TODO: optimize by putting this into global? */
- if (TALER_extensions_is_enabled (age_ext))
- age_mask = *(struct TALER_AgeMask *) age_ext->config;
- if (0 == age_mask.mask)
- {
- /* Age restriction support is not enabled. Ignore the AGE_RESTRICTED field
- * for the particular denomination and simply return the null_mask
- */
+ struct TALER_AgeMask age_mask = TALER_extensions_age_restriction_ageMask ();
+
+ if (age_mask.mask == 0)
return null_mask;
- }
- if (GNUNET_OK == (GNUNET_CONFIGURATION_have_value (
+ if (GNUNET_OK != (GNUNET_CONFIGURATION_have_value (
TEH_cfg,
section_name,
"AGE_RESTRICTED")))
+ return null_mask;
+
{
enum GNUNET_GenericReturnValue ret;
@@ -1331,6 +1321,8 @@ denomination_info_cb (
dk->meta = *meta;
dk->master_sig = *master_sig;
dk->recoup_possible = recoup_possible;
+ dk->denom_pub.age_mask = meta->age_mask;
+
GNUNET_assert (
GNUNET_OK ==
GNUNET_CONTAINER_multihashmap_put (ksh->denomkey_map,
@@ -1745,7 +1737,7 @@ setup_general_response_headers (struct TEH_KeyStateHandle *ksh,
* @a recoup and @a denoms.
*
* @param[in,out] ksh key state handle we build @a krd for
- * @param[in] denom_keys_hash hash over all the denominatoin keys in @a denoms
+ * @param[in] denom_keys_hash hash over all the denominatoin keys in @a denoms and age_restricted_denoms
* @param last_cpd timestamp to use
* @param signkeys list of sign keys to return
* @param recoup list of revoked keys to return
@@ -1863,7 +1855,8 @@ create_krd (struct TEH_KeyStateHandle *ksh,
int r;
/* skip if not configured == disabled */
- if (NULL == extension->config)
+ if (NULL == extension->config ||
+ NULL == extension->config_json)
continue;
/* flag our findings so far */
@@ -1899,7 +1892,7 @@ create_krd (struct TEH_KeyStateHandle *ksh,
json_t *sig;
int r;
- r = json_object_set_new (
+ r = json_object_set (
keys,
"extensions",
extensions);
@@ -1919,14 +1912,14 @@ create_krd (struct TEH_KeyStateHandle *ksh,
json_decref (extensions);
}
- // Special case for age restrictions: if enabled, provide the lits of
+ // Special case for age restrictions: if enabled, provide the list of
// age-restricted denominations.
if (age_restriction_enabled &&
NULL != age_restricted_denoms)
{
GNUNET_assert (
0 ==
- json_object_set_new (
+ json_object_set (
keys,
"age_restricted_denoms",
age_restricted_denoms));
@@ -2005,7 +1998,9 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
json_t *age_restricted_denoms = NULL;
struct GNUNET_TIME_Timestamp last_cpd;
struct GNUNET_CONTAINER_Heap *heap;
- struct GNUNET_HashContext *hash_context;
+ struct GNUNET_HashContext *hash_context = NULL;
+ struct GNUNET_HashContext *hash_context_restricted = NULL;
+ bool have_age_restricted_denoms = false;
sctx.signkeys = json_array ();
GNUNET_assert (NULL != sctx.signkeys);
@@ -2030,19 +2025,23 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
= GNUNET_TIME_relative_min (dkc.min_dk_frequency,
sctx.min_sk_frequency);
}
+
denoms = json_array ();
GNUNET_assert (NULL != denoms);
+ hash_context = GNUNET_CRYPTO_hash_context_start ();
- // If age restriction is enabled, initialize the array of age restricted denoms.
- /* TODO: optimize by putting this into global? */
- if (TALER_extensions_is_enabled_type (TALER_Extension_AgeRestriction))
+ /* If age restriction is enabled, initialize the array of age restricted
+ denoms and prepare a hash for them, separate from the others. We will join
+ those hashes afterwards.*/
+ if (TEH_age_restriction_enabled)
{
age_restricted_denoms = json_array ();
GNUNET_assert (NULL != age_restricted_denoms);
+ hash_context_restricted = GNUNET_CRYPTO_hash_context_start ();
}
last_cpd = GNUNET_TIME_UNIT_ZERO_TS;
- hash_context = GNUNET_CRYPTO_hash_context_start ();
+
{
struct TEH_DenominationKey *dk;
@@ -2056,6 +2055,11 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
{
struct GNUNET_HashCode hc;
+ /* FIXME-oec: Do we need to take hash_context_restricted into account
+ * in this if-branch!? Current tests suggests: no, (they don't fail).
+ * But something seems to be odd about only finishing hash_context.
+ */
+
GNUNET_CRYPTO_hash_context_finish (
GNUNET_CRYPTO_hash_context_copy (hash_context),
&hc);
@@ -2084,14 +2088,14 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
return GNUNET_SYSERR;
}
}
+
last_cpd = dk->meta.start;
- GNUNET_CRYPTO_hash_context_read (hash_context,
- &dk->h_denom_pub,
- sizeof (struct GNUNET_HashCode));
{
json_t *denom;
json_t *array;
+ struct GNUNET_HashContext *hc;
+
denom =
GNUNET_JSON_PACK (
@@ -2118,18 +2122,26 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
TALER_JSON_pack_amount ("fee_refund",
&dk->meta.fee_refund));
- /* Put the denom into the correct array - denoms or age_restricted_denoms -
- * depending on the settings and the properties of the denomination */
- if (NULL != age_restricted_denoms &&
- 0 != dk->meta.age_restrictions.mask)
+ /* Put the denom into the correct array depending on the settings and
+ * the properties of the denomination. Also, we build up the right
+ * hash for the corresponding array. */
+ if (TEH_age_restriction_enabled &&
+ (0 != dk->denom_pub.age_mask.mask))
{
+ have_age_restricted_denoms = true;
array = age_restricted_denoms;
+ hc = hash_context_restricted;
}
else
{
array = denoms;
+ hc = hash_context;
}
+ GNUNET_CRYPTO_hash_context_read (hc,
+ &dk->h_denom_pub,
+ sizeof (struct GNUNET_HashCode));
+
GNUNET_assert (
0 ==
json_array_append_new (
@@ -2138,13 +2150,27 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
}
}
}
+
GNUNET_CONTAINER_heap_destroy (heap);
if (! GNUNET_TIME_absolute_is_zero (last_cpd.abs_time))
{
struct GNUNET_HashCode hc;
+ /* If age restriction is active and we had at least one denomination of
+ * that sort, we simply add the hash of all age restricted denominations at
+ * the end of the others. */
+ if (TEH_age_restriction_enabled && have_age_restricted_denoms)
+ {
+ struct GNUNET_HashCode hcr;
+ GNUNET_CRYPTO_hash_context_finish (hash_context_restricted, &hcr);
+ GNUNET_CRYPTO_hash_context_read (hash_context,
+ &hcr,
+ sizeof (struct GNUNET_HashCode));
+ }
+
GNUNET_CRYPTO_hash_context_finish (hash_context,
&hc);
+
if (GNUNET_OK !=
create_krd (ksh,
&hc,
@@ -2158,7 +2184,7 @@ finish_keys_response (struct TEH_KeyStateHandle *ksh)
"Failed to generate key response data for %s\n",
GNUNET_TIME_timestamp2s (last_cpd));
json_decref (denoms);
- if (NULL != age_restricted_denoms)
+ if (TEH_age_restriction_enabled && NULL != age_restricted_denoms)
json_decref (age_restricted_denoms);
json_decref (sctx.signkeys);
json_decref (recoup);
@@ -2849,7 +2875,9 @@ load_extension_data (const char *section_name,
TEH_currency);
return GNUNET_SYSERR;
}
- meta->age_restrictions = load_age_mask (section_name);
+
+ meta->age_mask = load_age_mask (section_name);
+
return GNUNET_OK;
}
@@ -2976,7 +3004,7 @@ add_future_denomkey_cb (void *cls,
struct FutureBuilderContext *fbc = cls;
struct HelperDenomination *hd = value;
struct TEH_DenominationKey *dk;
- struct TALER_EXCHANGEDB_DenominationKeyMetaData meta;
+ struct TALER_EXCHANGEDB_DenominationKeyMetaData meta = {0};
dk = GNUNET_CONTAINER_multihashmap_get (fbc->ksh->denomkey_map,
h_denom_pub);
diff --git a/src/exchange/taler-exchange-httpd_management_extensions.c b/src/exchange/taler-exchange-httpd_management_extensions.c
index 17b000067..ab0287e33 100644
--- a/src/exchange/taler-exchange-httpd_management_extensions.c
+++ b/src/exchange/taler-exchange-httpd_management_extensions.c
@@ -31,7 +31,6 @@
#include "taler_extensions.h"
#include "taler_dbevents.h"
-
/**
* Extension carries the necessary data for a particular extension.
*
@@ -91,6 +90,8 @@ set_extensions (void *cls,
return GNUNET_DB_STATUS_HARD_ERROR;
}
+ GNUNET_assert (NULL != ext->config);
+
config = json_dumps (ext->config, JSON_COMPACT | JSON_SORT_KEYS);
if (NULL == config)
{
@@ -140,6 +141,57 @@ set_extensions (void *cls,
}
+static enum GNUNET_GenericReturnValue
+verify_extensions_from_json (
+ json_t *extensions,
+ struct SetExtensionsContext *sec)
+{
+ const char*name;
+ const struct TALER_Extension *extension;
+ size_t i = 0;
+ json_t *blob;
+
+ GNUNET_assert (NULL != extensions);
+ GNUNET_assert (json_is_object (extensions));
+
+ sec->num_extensions = json_object_size (extensions);
+ sec->extensions = GNUNET_new_array (sec->num_extensions,
+ struct Extension);
+
+ json_object_foreach (extensions, name, blob)
+ {
+ int critical = 0;
+ json_t *config;
+ const char *version = NULL;
+
+ /* load and verify criticality, version, etc. */
+ extension = TALER_extensions_get_by_name (name);
+ if (NULL == extension)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "no such extension: %s\n", name);
+ return GNUNET_SYSERR;
+ }
+
+ if (GNUNET_OK !=
+ TALER_extensions_is_json_config (
+ blob, &critical, &version, &config))
+ return GNUNET_SYSERR;
+
+ if (critical != extension->critical
+ || 0 != strcmp (version, extension->version) // TODO: libtool compare?
+ || NULL == config
+ || GNUNET_OK != extension->test_json_config (config))
+ return GNUNET_SYSERR;
+
+ sec->extensions[i].type = extension->type;
+ sec->extensions[i].config = config;
+ }
+
+ return GNUNET_OK;
+}
+
+
MHD_RESULT
TEH_handler_management_post_extensions (
struct MHD_Connection *connection,
@@ -204,57 +256,18 @@ TEH_handler_management_post_extensions (
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Received /management/extensions\n");
- sec.num_extensions = json_object_size (extensions);
- sec.extensions = GNUNET_new_array (sec.num_extensions,
- struct Extension);
-
/* Now parse individual extensions and signatures from those objects. */
+ if (GNUNET_OK !=
+ verify_extensions_from_json (extensions, &sec))
{
- const struct TALER_Extension *extension = NULL;
- const char *name;
- json_t *config;
- int idx = 0;
-
- json_object_foreach (extensions, name, config){
-
- /* 1. Make sure name refers to a supported extension */
- extension = TALER_extensions_get_by_name (name);
- if (NULL == extension)
- {
- ret = TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- "invalid extension type");
- goto CLEANUP;
- }
-
- sec.extensions[idx].config = config;
- sec.extensions[idx].type = extension->type;
-
- /* 2. Make sure the config is sound */
- if (GNUNET_OK !=
- extension->test_json_config (
- sec.extensions[idx].config))
- {
- ret = TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MALFORMED,
- "invalid configuration for extension");
- goto CLEANUP;
- }
-
- /* We have a validly signed JSON object for the extension. Increment its
- * refcount.
- */
- json_incref (sec.extensions[idx].config);
- idx++;
-
- } /* json_object_foreach */
+ GNUNET_JSON_parse_free (top_spec);
+ return TALER_MHD_reply_with_error (
+ connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "invalid object");
}
-
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Received %u extensions\n",
sec.num_extensions);
@@ -281,6 +294,7 @@ TEH_handler_management_post_extensions (
NULL,
0);
+
CLEANUP:
for (unsigned int i = 0; i < sec.num_extensions; i++)
{
diff --git a/src/exchange/taler-exchange-httpd_management_post_keys.c b/src/exchange/taler-exchange-httpd_management_post_keys.c
index f0c3f1f39..c353a9959 100644
--- a/src/exchange/taler-exchange-httpd_management_post_keys.c
+++ b/src/exchange/taler-exchange-httpd_management_post_keys.c
@@ -204,6 +204,7 @@ add_keys (void *cls,
TALER_denom_pub_free (&denom_pub);
return GNUNET_DB_STATUS_HARD_ERROR;
}
+
if (is_active)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -211,6 +212,7 @@ add_keys (void *cls,
GNUNET_h2s (&d->h_denom_pub.hash));
continue; /* skip, already known */
}
+
qs = TEH_plugin->add_denomination_key (
TEH_plugin->cls,
&d->h_denom_pub,
diff --git a/src/exchange/taler-exchange-httpd_melt.c b/src/exchange/taler-exchange-httpd_melt.c
index 021b629b3..8bfdf8cef 100644
--- a/src/exchange/taler-exchange-httpd_melt.c
+++ b/src/exchange/taler-exchange-httpd_melt.c
@@ -279,6 +279,7 @@ check_melt_valid (struct MHD_Connection *connection,
&mret);
if (NULL == dk)
return mret;
+
if (GNUNET_TIME_absolute_is_past (dk->meta.expire_legal.abs_time))
{
/* Way too late now, even zombies have expired */
@@ -288,6 +289,7 @@ check_melt_valid (struct MHD_Connection *connection,
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
"MELT");
}
+
if (GNUNET_TIME_absolute_is_future (dk->meta.start.abs_time))
{
/* This denomination is not yet valid */
@@ -300,9 +302,11 @@ check_melt_valid (struct MHD_Connection *connection,
rmc->coin_refresh_fee = dk->meta.fee_refresh;
rmc->coin_value = dk->meta.value;
+
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Melted coin's denomination is worth %s\n",
TALER_amount2s (&dk->meta.value));
+
/* sanity-check that "total melt amount > melt fee" */
if (0 <
TALER_amount_cmp (&rmc->coin_refresh_fee,
@@ -332,6 +336,7 @@ check_melt_valid (struct MHD_Connection *connection,
&rmc->coin_refresh_fee,
&rmc->refresh_session.rc,
&rmc->refresh_session.coin.denom_pub_hash,
+ &rmc->refresh_session.coin.age_commitment_hash,
&rmc->refresh_session.coin.coin_pub,
&rmc->refresh_session.coin_sig))
{
@@ -407,6 +412,9 @@ TEH_handler_melt (struct MHD_Connection *connection,
&rmc.refresh_session.coin.denom_sig),
GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
&rmc.refresh_session.coin.denom_pub_hash),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_fixed_auto ("age_commitment_hash",
+ &rmc.refresh_session.coin.age_commitment_hash)),
GNUNET_JSON_spec_fixed_auto ("confirm_sig",
&rmc.refresh_session.coin_sig),
TALER_JSON_spec_amount ("value_with_fee",
diff --git a/src/exchange/taler-exchange-httpd_recoup-refresh.c b/src/exchange/taler-exchange-httpd_recoup-refresh.c
index 829e2cbd7..bbf6defee 100644
--- a/src/exchange/taler-exchange-httpd_recoup-refresh.c
+++ b/src/exchange/taler-exchange-httpd_recoup-refresh.c
@@ -251,7 +251,7 @@ verify_and_execute_recoup_refresh (
if (GNUNET_OK !=
TALER_denom_blind (&dk->denom_pub,
coin_bks,
- NULL, /* FIXME-Oec: TALER_AgeHash * */
+ NULL, /* FIXME-Oec: TALER_AgeCommitmentHash * */
&coin->coin_pub,
exchange_vals,
&c_hash,
diff --git a/src/exchange/taler-exchange-httpd_recoup.c b/src/exchange/taler-exchange-httpd_recoup.c
index ea319d11c..4ac997e9c 100644
--- a/src/exchange/taler-exchange-httpd_recoup.c
+++ b/src/exchange/taler-exchange-httpd_recoup.c
@@ -256,7 +256,7 @@ verify_and_execute_recoup (
if (GNUNET_OK !=
TALER_denom_blind (&dk->denom_pub,
coin_bks,
- NULL, /* FIXME-Oec: TALER_AgeHash * */
+ NULL, /* FIXME-Oec: TALER_AgeCommitmentHash * */
&coin->coin_pub,
exchange_vals,
&c_hash,
diff --git a/src/exchange/taler-exchange-httpd_refreshes_reveal.c b/src/exchange/taler-exchange-httpd_refreshes_reveal.c
index 0d8f7bf9b..1f0782aaa 100644
--- a/src/exchange/taler-exchange-httpd_refreshes_reveal.c
+++ b/src/exchange/taler-exchange-httpd_refreshes_reveal.c
@@ -281,6 +281,7 @@ check_commitment (struct RevealContext *rctx,
alg_value,
&bks,
&coin_priv,
+ NULL, /* FIXME-Oec, struct TALER_AgeCommitmentHash * */
&c_hash,
&pd));
if (TALER_DENOMINATION_CS == dk->cipher)
@@ -380,6 +381,7 @@ check_commitment (struct RevealContext *rctx,
* @param rctx context for the operation, partially built at this time
* @param link_sigs_json link signatures in JSON format
* @param new_denoms_h_json requests for fresh coins to be created
+ * @param old_age_commitment_json age commitment that went into the withdrawal, maybe NULL
* @param coin_evs envelopes of gamma-selected coins to be signed
* @return MHD result code
*/
@@ -388,6 +390,7 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,
struct RevealContext *rctx,
const json_t *link_sigs_json,
const json_t *new_denoms_h_json,
+ const json_t *old_age_commitment_json,
const json_t *coin_evs)
{
unsigned int num_fresh_coins = json_array_size (new_denoms_h_json);
@@ -412,6 +415,7 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,
TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
NULL);
}
+
/* Parse denomination key hashes */
for (unsigned int i = 0; i<num_fresh_coins; i++)
{
@@ -537,6 +541,7 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,
goto cleanup;
}
}
+
/* Parse link signatures array */
for (unsigned int i = 0; i<num_fresh_coins; i++)
{
@@ -554,6 +559,7 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,
-1);
if (GNUNET_OK != res)
return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
+
/* Check signature */
if (GNUNET_OK !=
TALER_wallet_link_verify (
@@ -561,6 +567,7 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,
&rctx->gamma_tp,
&rrcs[i].coin_envelope_hash,
&rctx->melt.session.coin.coin_pub,
+ NULL, // TODO-oec: calculate the correct h_age_commitment
&rrcs[i].orig_coin_link_sig))
{
GNUNET_break_op (0);
@@ -592,6 +599,7 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,
goto cleanup;
}
}
+
rctx->dks = dks;
rctx->rcds = rcds;
rctx->rrcs = rrcs;
@@ -604,6 +612,7 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Creating %u signatures\n",
(unsigned int) rctx->num_fresh_coins);
+
/* create fresh coin signatures */
for (unsigned int i = 0; i<rctx->num_fresh_coins; i++)
{
@@ -622,8 +631,10 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,
goto cleanup;
}
}
+
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Signatures ready, starting DB interaction\n");
+
/* Persist operation result in DB */
{
enum GNUNET_DB_QueryStatus qs;
@@ -678,11 +689,18 @@ cleanup:
* revealed information is valid then returns the signed refreshed
* coins.
*
+ * If the denomination has age restriction support, the array of EDDSA public
+ * keys, one for each age group that was activated during the withdrawal
+ * by the parent/ward, must be provided in old_age_commitment. The hash of
+ * this array must be the same as the h_age_commitment of the persisted reveal
+ * request.
+ *
* @param connection the MHD connection to handle
* @param rctx context for the operation, partially built at this time
* @param tp_json private transfer keys in JSON format
* @param link_sigs_json link signatures in JSON format
* @param new_denoms_h_json requests for fresh coins to be created
+ * @param old_age_commitment_json array of EDDSA public keys in JSON, used for age restriction, maybe NULL
* @param coin_evs envelopes of gamma-selected coins to be signed
* @return MHD result code
*/
@@ -692,6 +710,7 @@ handle_refreshes_reveal_json (struct MHD_Connection *connection,
const json_t *tp_json,
const json_t *link_sigs_json,
const json_t *new_denoms_h_json,
+ const json_t *old_age_commitment_json,
const json_t *coin_evs)
{
unsigned int num_fresh_coins = json_array_size (new_denoms_h_json);
@@ -727,6 +746,19 @@ handle_refreshes_reveal_json (struct MHD_Connection *connection,
"new_denoms/link_sigs");
}
+ /* Sanity check of age commitment: If it was provided, it _must_ be an array
+ * of the size the # of age groups */
+ if (NULL != old_age_commitment_json
+ && TALER_extensions_age_restriction_num_groups () !=
+ json_array_size (old_age_commitment_json))
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_EXCHANGE_REFRESHES_REVEAL_AGE_RESTRICTION_COMMITMENT_INVALID,
+ "old_age_commitment");
+ }
+
/* Parse transfer private keys array */
for (unsigned int i = 0; i<num_tprivs; i++)
{
@@ -750,6 +782,7 @@ handle_refreshes_reveal_json (struct MHD_Connection *connection,
rctx,
link_sigs_json,
new_denoms_h_json,
+ old_age_commitment_json,
coin_evs);
}
@@ -763,6 +796,7 @@ TEH_handler_reveal (struct TEH_RequestContext *rc,
json_t *transfer_privs;
json_t *link_sigs;
json_t *new_denoms_h;
+ json_t *old_age_commitment = NULL;
struct RevealContext rctx;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("transfer_pub",
@@ -775,6 +809,9 @@ TEH_handler_reveal (struct TEH_RequestContext *rc,
&coin_evs),
GNUNET_JSON_spec_json ("new_denoms_h",
&new_denoms_h),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_json ("old_age_commitment",
+ &old_age_commitment)),
GNUNET_JSON_spec_end ()
};
@@ -836,6 +873,7 @@ TEH_handler_reveal (struct TEH_RequestContext *rc,
transfer_privs,
link_sigs,
new_denoms_h,
+ old_age_commitment,
coin_evs);
GNUNET_JSON_parse_free (spec);
return res;
diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c
index 55b230444..00f047172 100644
--- a/src/exchange/taler-exchange-httpd_responses.c
+++ b/src/exchange/taler-exchange-httpd_responses.c
@@ -73,6 +73,7 @@ TEH_RESPONSE_compile_transaction_history (
&deposit->deposit_fee,
&h_wire,
&deposit->h_contract_terms,
+ NULL, /* h_age_commitment, FIXME-oec */
NULL /* h_extensions! */,
&deposit->h_denom_pub,
deposit->timestamp,
@@ -122,6 +123,7 @@ TEH_RESPONSE_compile_transaction_history (
{
const struct TALER_EXCHANGEDB_MeltListEntry *melt =
pos->details.melt;
+ const struct TALER_AgeCommitmentHash *phac = NULL;
#if ENABLE_SANITY_CHECKS
if (GNUNET_OK !=
@@ -129,6 +131,7 @@ TEH_RESPONSE_compile_transaction_history (
&melt->melt_fee,
&melt->rc,
&melt->h_denom_pub,
+ &melt->h_age_commitment,
coin_pub,
&melt->coin_sig))
{
@@ -137,6 +140,12 @@ TEH_RESPONSE_compile_transaction_history (
return NULL;
}
#endif
+
+ /* Age restriction is optional. We communicate a NULL value to
+ * JSON_PACK below */
+ if (! TALER_AgeCommitmentHash_isNullOrZero (&melt->h_age_commitment))
+ phac = &melt->h_age_commitment;
+
if (0 !=
json_array_append_new (
history,
@@ -151,6 +160,9 @@ TEH_RESPONSE_compile_transaction_history (
&melt->rc),
GNUNET_JSON_pack_data_auto ("h_denom_pub",
&melt->h_denom_pub),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_data_auto ("h_age_commitment",
+ phac)),
GNUNET_JSON_pack_data_auto ("coin_sig",
&melt->coin_sig))))
{