aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/include/taler_exchange_service.h10
-rw-r--r--src/include/taler_extensions.h2
-rw-r--r--src/lib/exchange_api_handle.c178
-rw-r--r--src/util/extension_age_restriction.c2
4 files changed, 142 insertions, 50 deletions
diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h
index 04b731b32..6976293cb 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -159,6 +159,11 @@ struct TALER_EXCHANGE_DenomPublicKey
* revoked by the exchange.
*/
bool revoked;
+
+ /**
+ * Is the denomination age-restricted?
+ */
+ bool age_restricted;
};
@@ -283,6 +288,11 @@ struct TALER_EXCHANGE_Keys
struct GNUNET_TIME_Timestamp last_denom_issue_date;
/**
+ * If age restriction is enabled on the exchange, we get an non-zero age_mask
+ */
+ struct TALER_AgeMask age_mask;
+
+ /**
* Length of the @e sign_keys array (number of valid entries).
*/
unsigned int num_sign_keys;
diff --git a/src/include/taler_extensions.h b/src/include/taler_extensions.h
index 199776eb7..243811eb5 100644
--- a/src/include/taler_extensions.h
+++ b/src/include/taler_extensions.h
@@ -110,7 +110,7 @@ TALER_extension_get_by_name (const char *name,
* @return Error, if age groups were invalid, OK otherwise.
*/
enum TALER_Extension_ReturnValue
-TALER_parse_age_group_string (char *groups,
+TALER_parse_age_group_string (const char *groups,
struct TALER_AgeMask *mask);
/**
diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c
index df501f0b7..ac0e0584f 100644
--- a/src/lib/exchange_api_handle.c
+++ b/src/lib/exchange_api_handle.c
@@ -30,6 +30,7 @@
#include "taler_exchange_service.h"
#include "taler_auditor_service.h"
#include "taler_signatures.h"
+#include "taler_extensions.h"
#include "exchange_api_handle.h"
#include "exchange_api_curl_defaults.h"
#include "backoff.h"
@@ -345,6 +346,7 @@ parse_json_denomkey (struct TALER_EXCHANGE_DenomPublicKey *denom_key,
GNUNET_JSON_spec_end ()
};
+
if (GNUNET_OK !=
GNUNET_JSON_parse (denom_key_obj,
spec,
@@ -761,6 +763,7 @@ decode_keys_json (const json_t *resp_obj,
return GNUNET_SYSERR;
}
}
+
/* parse the master public key and issue date of the response */
if (check_sig)
hash_context = GNUNET_CRYPTO_hash_context_start ();
@@ -791,63 +794,142 @@ decode_keys_json (const json_t *resp_obj,
}
}
- /* parse the denomination keys, merging with the
- possibly EXISTING array as required (/keys cherry picking) */
+ /* Parse the supported extension(s): age-restriction. */
+ /* TODO: maybe lift this into a FP in TALER_Extension ? */
{
- json_t *denom_keys_array;
- json_t *denom_key_obj;
- unsigned int index;
+ json_t *age_restriction = json_object_get (resp_obj,
+ "age_restriction");
- EXITIF (NULL == (denom_keys_array =
- json_object_get (resp_obj,
- "denoms")));
- EXITIF (JSON_ARRAY != json_typeof (denom_keys_array));
+ if (NULL != age_restriction)
+ {
+ bool critical;
+ const char *version;
+ const char *age_groups;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_bool ("critical",
+ &critical),
+ GNUNET_JSON_spec_string ("version",
+ &version),
+ GNUNET_JSON_spec_string ("age_groups",
+ &age_groups),
+ GNUNET_JSON_spec_end ()
+ };
- json_array_foreach (denom_keys_array, index, denom_key_obj) {
- struct TALER_EXCHANGE_DenomPublicKey dk;
- bool found = false;
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (age_restriction,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
- memset (&dk,
- 0,
- sizeof (dk));
- 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 (critical || // do we care?
+ 0 != strncmp (version, "1", 1) ) /* TODO: better compatibility check */
{
- if (0 == denoms_cmp (&dk,
- &key_data->denom_keys[j]))
- {
- found = true;
- break;
- }
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
}
- if (found)
+
+ if (TALER_Extension_OK !=
+ TALER_parse_age_group_string (age_groups,
+ &key_data->age_mask))
{
- /* 0:0:0 did not support /keys cherry picking */
- TALER_LOG_DEBUG ("Skipping denomination key: already know it\n");
- TALER_denom_pub_free (&dk.key);
- continue;
+ // TODO: print more specific error?
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
}
- 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 ("Adding denomination key that is valid_until %s\n",
- GNUNET_TIME_timestamp2s (dk.valid_from));
- key_data->last_denom_issue_date
- = GNUNET_TIME_timestamp_max (key_data->last_denom_issue_date,
- dk.valid_from);
+ }
+ }
+
+ /* parse the denomination keys, merging with the
+ possibly EXISTING array as required (/keys cherry picking) */
+ {
+ /* The denominations can be in "denoms" and (optionally) in
+ * "age_restricted_denoms"
+ */
+ struct
+ { char *name;
+ bool is_optional_age_restriction;} hive[2] = {
+ { "denoms", false },
+ { "age_restricted_denoms", true },
};
+
+ for (size_t s = 0; s < sizeof(hive) / sizeof(hive[0]); s++)
+ {
+ json_t *denom_keys_array;
+ json_t *denom_key_obj;
+ unsigned int index;
+
+ denom_keys_array = json_object_get (resp_obj,
+ hive[s].name);
+
+ EXITIF (NULL == denom_keys_array &&
+ ! hive[s].is_optional_age_restriction);
+
+ if (NULL == denom_keys_array &&
+ hive[s].is_optional_age_restriction)
+ continue;
+
+ /* if "age_restricted_denoms" exists, age-restriction better be enabled
+ * (that is: mask non-zero) */
+ EXITIF (NULL != denom_keys_array &&
+ hive[s].is_optional_age_restriction &&
+ 0 == key_data->age_mask.mask);
+
+ EXITIF (JSON_ARRAY != json_typeof (denom_keys_array));
+
+ json_array_foreach (denom_keys_array, index, denom_key_obj) {
+ struct TALER_EXCHANGE_DenomPublicKey dk;
+ bool found = false;
+
+ memset (&dk,
+ 0,
+ sizeof (dk));
+ EXITIF (GNUNET_SYSERR ==
+ parse_json_denomkey (&dk,
+ check_sig,
+ denom_key_obj,
+ &key_data->master_pub,
+ hash_context));
+
+ /* Mark age restriction according where we got this denomination from,
+ * "denoms" or "age_restricted_denoms" */
+ if (hive[s].is_optional_age_restriction)
+ dk.age_restricted = true;
+
+ for (unsigned int j = 0;
+ j<key_data->num_denom_keys;
+ j++)
+ {
+ if (0 == denoms_cmp (&dk,
+ &key_data->denom_keys[j]))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ {
+ /* 0:0:0 did not support /keys cherry picking */
+ TALER_LOG_DEBUG ("Skipping denomination key: already know it\n");
+ TALER_denom_pub_free (&dk.key);
+ 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 ("Adding denomination key that is valid_until %s\n",
+ GNUNET_TIME_timestamp2s (dk.valid_from));
+ key_data->last_denom_issue_date
+ = GNUNET_TIME_timestamp_max (key_data->last_denom_issue_date,
+ dk.valid_from);
+ };
+ }
}
/* parse the auditor information */
diff --git a/src/util/extension_age_restriction.c b/src/util/extension_age_restriction.c
index 42a58b2e9..b29a8ca88 100644
--- a/src/util/extension_age_restriction.c
+++ b/src/util/extension_age_restriction.c
@@ -80,7 +80,7 @@ TALER_get_age_mask (const struct GNUNET_CONFIGURATION_Handle *cfg,
* @return Error if string was invalid, OK otherwise.
*/
enum TALER_Extension_ReturnValue
-TALER_parse_age_group_string (char *groups,
+TALER_parse_age_group_string (const char *groups,
struct TALER_AgeMask *mask)
{
enum TALER_Extension_ReturnValue ret = TALER_Extension_ERROR_SYS;