From 8bdf6ab19df70c16d335ecf82f2c3b2117eeb70e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96zg=C3=BCr=20Kesim?= Date: Wed, 16 Feb 2022 22:01:05 +0100 Subject: [age restriction] progress 14/n - withdraw and deposit Age restriction support for - withdraw is done and tested - deposit is done and tested TODOs: - melt/refresh/reveal - link ------ Added functions - TALER_age_restriction_commit - TALER_age_commitment_derive - TALER_age_commitment_hash - TALER_age_restriction_commitment_free_inside - Hash of age commitment passed around API boundaries Exchangedb adjustments for denominations - all prepared statements re: denominations now handle age_mask - signature parameters adjusted Hash and signature verification of /keys adjusted - Hashes of (normal) denominations and age-restricted denominations are calculated seperately - The hash of the age-restricted ones will then be added to the other hash - The total hash is signed/verified Tests for withdraw with age restriction added - TALER_EXCHANGE_DenomPublickey now carries age_mask - TALER_TESTING_cmd_withdraw_amount* takes age parameter - TALER_TESTING_find_pk takes boolean age_restricted - WithdrawState carries age_commitment and its hash - withdraw_run derives new age commitment, if applicable - Added age parameter to testing (13 as example) Various Fixes and changes - Fixes of post handler for /management/extensions - Fixes for offline tool extensions signing - Slight refactoring of extensions - Age restriction extension simplified - config is now global to extension - added global TEH_age_restriction_enabled and TEH_age_mask in taler-exchange-httpd - helper functions and macros introduced --- src/extensions/extension_age_restriction.c | 109 +++++++++++++++++++++++++---- src/extensions/extensions.c | 24 +++++-- 2 files changed, 116 insertions(+), 17 deletions(-) (limited to 'src/extensions') diff --git a/src/extensions/extension_age_restriction.c b/src/extensions/extension_age_restriction.c index a9ffb7f1a..28b2dbb1e 100644 --- a/src/extensions/extension_age_restriction.c +++ b/src/extensions/extension_age_restriction.c @@ -23,6 +23,19 @@ #include "taler_extensions.h" #include "stdint.h" +/** + * Carries all the information we need for age restriction + */ +struct age_restriction_config +{ + struct TALER_AgeMask mask; + size_t num_groups; +}; + +/** + * Global config for this extension + */ +static struct age_restriction_config _config = {0}; /** * @param groups String representation of the age groups. Must be of the form @@ -146,6 +159,9 @@ age_restriction_disable ( json_decref (this->config_json); this->config_json = NULL; } + + _config.mask.mask = 0; + _config.num_groups = 0; } @@ -197,7 +213,6 @@ age_restriction_load_taler_config ( mask.mask = TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_MASK; - ret = GNUNET_OK; if (groups != NULL) @@ -208,7 +223,19 @@ age_restriction_load_taler_config ( } if (GNUNET_OK == ret) - this->config = (void *) (size_t) mask.mask; + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "setting age mask to %x with #groups: %d\n", mask.mask, + __builtin_popcount (mask.mask) - 1); + _config.mask.mask = mask.mask; + _config.num_groups = __builtin_popcount (mask.mask) - 1; /* no underflow, first bit always set */ + this->config = &_config; + + /* Note: we do now have _config set, however this->config_json is NOT set, + * i.e. the extension is not yet active! For age restriction to become + * active, load_json_config must have been called. */ + } + GNUNET_free (groups); return ret; @@ -223,12 +250,12 @@ age_restriction_load_taler_config ( static enum GNUNET_GenericReturnValue age_restriction_load_json_config ( struct TALER_Extension *this, - json_t *config) + json_t *jconfig) { struct TALER_AgeMask mask = {0}; enum GNUNET_GenericReturnValue ret; - ret = TALER_JSON_parse_agemask (config, &mask); + ret = TALER_JSON_parse_age_groups (jconfig, &mask); if (GNUNET_OK != ret) return ret; @@ -239,16 +266,28 @@ age_restriction_load_json_config ( if (TALER_Extension_AgeRestriction != this->type) return GNUNET_SYSERR; - if (NULL != this->config) - GNUNET_free (this->config); + _config.mask.mask = mask.mask; + _config.num_groups = 0; + + if (mask.mask > 0) + { + /* if the mask is not zero, the first bit MUST be set */ + if (0 == (mask.mask & 1)) + return GNUNET_SYSERR; + + _config.num_groups = __builtin_popcount (mask.mask) - 1; + } - this->config = GNUNET_malloc (sizeof(struct TALER_AgeMask)); - GNUNET_memcpy (this->config, &mask, sizeof(struct TALER_AgeMask)); + this->config = &_config; if (NULL != this->config_json) json_decref (this->config_json); - this->config_json = config; + this->config_json = jconfig; + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "loaded new age restriction config with age groups: %s\n", + TALER_age_mask_to_string (&mask)); return GNUNET_OK; } @@ -263,7 +302,6 @@ json_t * age_restriction_config_to_json ( const struct TALER_Extension *this) { - struct TALER_AgeMask mask; char *mask_str; json_t *conf; @@ -275,8 +313,7 @@ age_restriction_config_to_json ( return json_copy (this->config_json); } - mask.mask = (uint32_t) (size_t) this->config; - mask_str = TALER_age_mask_to_string (&mask); + mask_str = TALER_age_mask_to_string (&_config.mask); conf = GNUNET_JSON_PACK ( GNUNET_JSON_pack_string ("age_groups", mask_str) ); @@ -298,7 +335,7 @@ age_restriction_test_json_config ( { struct TALER_AgeMask mask = {0}; - return TALER_JSON_parse_agemask (config, &mask); + return TALER_JSON_parse_age_groups (config, &mask); } @@ -318,4 +355,50 @@ struct TALER_Extension _extension_age_restriction = { .load_taler_config = &age_restriction_load_taler_config, }; +bool +TALER_extensions_age_restriction_is_configured () +{ + return (0 != _config.mask.mask); +} + + +struct TALER_AgeMask +TALER_extensions_age_restriction_ageMask () +{ + return _config.mask; +} + + +size_t +TALER_extensions_age_restriction_num_groups () +{ + return _config.num_groups; +} + + +enum GNUNET_GenericReturnValue +TALER_JSON_parse_age_groups (const json_t *root, + struct TALER_AgeMask *mask) +{ + enum GNUNET_GenericReturnValue ret; + const char *str; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ("age_groups", + &str), + GNUNET_JSON_spec_end () + }; + + ret = GNUNET_JSON_parse (root, + spec, + NULL, + NULL); + if (GNUNET_OK == ret) + TALER_parse_age_group_string (str, mask); + + GNUNET_JSON_parse_free (spec); + + return ret; +} + + /* end of extension_age_restriction.c */ diff --git a/src/extensions/extensions.c b/src/extensions/extensions.c index 55d970c57..516c56a43 100644 --- a/src/extensions/extensions.c +++ b/src/extensions/extensions.c @@ -247,27 +247,31 @@ TALER_extensions_load_taler_config ( } -static enum GNUNET_GenericReturnValue -is_json_extension_config ( +enum GNUNET_GenericReturnValue +TALER_extensions_is_json_config ( json_t *obj, int *critical, const char **version, json_t **config) { enum GNUNET_GenericReturnValue ret; + json_t *cfg; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_boolean ("critical", critical), GNUNET_JSON_spec_string ("version", version), GNUNET_JSON_spec_json ("config", - config), + &cfg), GNUNET_JSON_spec_end () }; ret = GNUNET_JSON_parse (obj, spec, NULL, NULL); if (GNUNET_OK == ret) + { + *config = json_copy (cfg); GNUNET_JSON_parse_free (spec); + } return ret; } @@ -300,7 +304,7 @@ TALER_extensions_load_json_config ( /* load and verify criticality, version, etc. */ if (GNUNET_OK != - is_json_extension_config ( + TALER_extensions_is_json_config ( blob, &critical, &version, &config)) return GNUNET_SYSERR; @@ -330,4 +334,16 @@ TALER_extensions_load_json_config ( } +bool +TALER_extensions_age_restriction_is_enabled () +{ + const struct TALER_Extension *age = + TALER_extensions_get_by_type (TALER_Extension_AgeRestriction); + + return (NULL != age && + NULL != age->config_json && + TALER_extensions_age_restriction_is_configured ()); +} + + /* end of extensions.c */ -- cgit v1.2.3