[age restriction] progress 14/n - withdraw and deposit
Age restriction support for - withdraw is done and tested - deposit is done and tested - melt is done, untested - reveal started - link started Added functions - TALER_age_commitment_hash - TALER_age_restriction_commit - TALER_age_commitment_derive - 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 - WithdrawState carries age_commitment and its hash - withdraw_run derives new age commitment, if applicable - Added age parameter to testing (13 as example) - TALER_TESTING_find_pk takes boolean age_restricted - struct RefreshMeltState carries age commitment of melted coin - melt_run calls TALER_age_commitment_derive, if necessary 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
This commit is contained in:
parent
8684a9bfea
commit
327361adda
@ -1 +1 @@
|
||||
Subproject commit b0dd85e8187f33a1f92dd5eb31082050d333e168
|
||||
Subproject commit 94b3d826de2aa442a985d03a52eaf526ef950d83
|
@ -1227,6 +1227,7 @@ static int
|
||||
refresh_session_cb (void *cls,
|
||||
uint64_t rowid,
|
||||
const struct TALER_DenominationPublicKey *denom_pub,
|
||||
const struct TALER_AgeCommitmentHash *h_age_commitment,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_CoinSpendSignatureP *coin_sig,
|
||||
const struct TALER_Amount *amount_with_fee,
|
||||
@ -1289,6 +1290,7 @@ refresh_session_cb (void *cls,
|
||||
&fee_refresh,
|
||||
rc,
|
||||
&h_denom_pub,
|
||||
h_age_commitment,
|
||||
coin_pub,
|
||||
coin_sig))
|
||||
{
|
||||
@ -1615,6 +1617,7 @@ deposit_cb (void *cls,
|
||||
struct TALER_MerchantWireHash h_wire;
|
||||
struct TALER_DenominationHash h_denom_pub;
|
||||
struct TALER_Amount deposit_fee;
|
||||
struct TALER_AgeCommitmentHash *h_age_commitment = NULL; /* FIXME-oec */
|
||||
|
||||
TALER_denom_pub_hash (denom_pub,
|
||||
&h_denom_pub);
|
||||
@ -1631,6 +1634,7 @@ deposit_cb (void *cls,
|
||||
&deposit_fee,
|
||||
&h_wire,
|
||||
&deposit->h_contract_terms,
|
||||
h_age_commitment, /* FIXME-oec */
|
||||
NULL /* h_extensions! */,
|
||||
&h_denom_pub,
|
||||
deposit->timestamp,
|
||||
|
@ -300,7 +300,7 @@ add_deposit (const struct Merchant *m)
|
||||
struct TALER_EXCHANGEDB_Deposit deposit;
|
||||
uint64_t known_coin_id;
|
||||
struct TALER_DenominationHash dph;
|
||||
struct TALER_AgeHash agh;
|
||||
struct TALER_AgeCommitmentHash agh;
|
||||
|
||||
RANDOMIZE (&d.coin.coin_pub);
|
||||
d.coin.denom_pub_hash = h_denom_pub;
|
||||
|
@ -366,6 +366,7 @@ run (void *cls,
|
||||
(TALER_TESTING_cmd_withdraw_amount (wl,
|
||||
create_reserve_label,
|
||||
amount_5,
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK));
|
||||
unit[1] =
|
||||
TALER_TESTING_cmd_deposit_with_retry
|
||||
|
@ -152,6 +152,10 @@ static char *currency;
|
||||
*/
|
||||
static char *CFG_exchange_url;
|
||||
|
||||
/**
|
||||
* If age restriction is enabled, the age mask to be used
|
||||
*/
|
||||
static struct TALER_AgeMask age_mask = {0};
|
||||
|
||||
/**
|
||||
* A subcommand supported by this program.
|
||||
@ -1924,6 +1928,7 @@ trigger_upload (const char *exchange_url)
|
||||
if (0 == strcasecmp (key,
|
||||
uhs[i].key))
|
||||
{
|
||||
|
||||
found = true;
|
||||
uhs[i].cb (exchange_url,
|
||||
index,
|
||||
@ -3036,6 +3041,7 @@ do_show (char *const *args)
|
||||
keys = parse_keys_input ("show");
|
||||
if (NULL == keys)
|
||||
return;
|
||||
|
||||
if (GNUNET_OK !=
|
||||
load_offline_key (GNUNET_NO))
|
||||
return;
|
||||
@ -3196,6 +3202,43 @@ sign_signkeys (const struct TALER_SecurityModulePublicKeyP *secm_pub,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Looks up the AGE_RESTRICTED setting for a denomination in the config and
|
||||
* returns the age restriction (mask) accordingly.
|
||||
*
|
||||
* @param section_name Section in the configuration for the particular
|
||||
* denomination.
|
||||
*/
|
||||
static struct TALER_AgeMask
|
||||
load_age_mask (const char*section_name)
|
||||
{
|
||||
static const struct TALER_AgeMask null_mask = {0};
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
|
||||
if (age_mask.mask == 0)
|
||||
return null_mask;
|
||||
|
||||
if (GNUNET_OK != (GNUNET_CONFIGURATION_have_value (
|
||||
kcfg,
|
||||
section_name,
|
||||
"AGE_RESTRICTED")))
|
||||
return null_mask;
|
||||
|
||||
ret = GNUNET_CONFIGURATION_get_value_yesno (kcfg,
|
||||
section_name,
|
||||
"AGE_RESTRICTED");
|
||||
if (GNUNET_YES == ret)
|
||||
return age_mask;
|
||||
|
||||
if (GNUNET_SYSERR == ret)
|
||||
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
|
||||
section_name,
|
||||
"AGE_RESTRICTED",
|
||||
"Value must be YES or NO\n");
|
||||
return null_mask;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sign @a denomkeys with offline key.
|
||||
*
|
||||
@ -3284,7 +3327,10 @@ sign_denomkeys (const struct TALER_SecurityModulePublicKeyP *secm_pub,
|
||||
duration = GNUNET_TIME_absolute_get_difference (
|
||||
stamp_start.abs_time,
|
||||
stamp_expire_withdraw.abs_time);
|
||||
// FIXME-Oec: setup age mask here?
|
||||
|
||||
/* Load the age mask, if applicable to this denomination */
|
||||
denom_pub.age_mask = load_age_mask (section_name);
|
||||
|
||||
TALER_denom_pub_hash (&denom_pub,
|
||||
&h_denom_pub);
|
||||
switch (denom_pub.cipher)
|
||||
@ -3518,14 +3564,6 @@ do_extensions_show (char *const *args)
|
||||
json_t *exts = json_object ();
|
||||
const struct TALER_Extension *it;
|
||||
|
||||
TALER_extensions_init ();
|
||||
if (GNUNET_OK != TALER_extensions_load_taler_config (kcfg))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"error while loading taler config for extensions\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (it = TALER_extensions_get_head ();
|
||||
NULL != it;
|
||||
it = it->next)
|
||||
@ -3779,6 +3817,17 @@ run (void *cls,
|
||||
global_ret = EXIT_NOTCONFIGURED;
|
||||
return;
|
||||
}
|
||||
|
||||
/* load age mask, if age restriction is enabled */
|
||||
TALER_extensions_init ();
|
||||
if (GNUNET_OK != TALER_extensions_load_taler_config (kcfg))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"error while loading taler config for extensions\n");
|
||||
return;
|
||||
}
|
||||
age_mask = TALER_extensions_age_restriction_ageMask ();
|
||||
|
||||
ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
|
||||
&rc);
|
||||
rc = GNUNET_CURL_gnunet_rc_create (ctx);
|
||||
|
@ -126,6 +126,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.
|
||||
*/
|
||||
@ -736,6 +742,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/*");
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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,
|
||||
|
@ -239,6 +239,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",
|
||||
@ -387,6 +390,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,
|
||||
|
@ -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;
|
||||
|
@ -743,44 +743,31 @@ 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;
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
struct TALER_AgeMask age_mask = TALER_extensions_age_restriction_ageMask ();
|
||||
|
||||
if (age_mask.mask == 0)
|
||||
{
|
||||
/* Age restriction support is not enabled. Ignore the AGE_RESTRICTED field
|
||||
* for the particular denomination and simply return the null_mask
|
||||
*/
|
||||
return null_mask;
|
||||
}
|
||||
|
||||
if (GNUNET_OK == (GNUNET_CONFIGURATION_have_value (
|
||||
if (GNUNET_OK != (GNUNET_CONFIGURATION_have_value (
|
||||
TEH_cfg,
|
||||
section_name,
|
||||
"AGE_RESTRICTED")))
|
||||
{
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
if (GNUNET_SYSERR == (ret = GNUNET_CONFIGURATION_get_value_yesno (TEH_cfg,
|
||||
return null_mask;
|
||||
|
||||
ret = GNUNET_CONFIGURATION_get_value_yesno (TEH_cfg,
|
||||
section_name,
|
||||
"AGE_RESTRICTED")))
|
||||
{
|
||||
"AGE_RESTRICTED");
|
||||
if (GNUNET_YES == ret)
|
||||
return age_mask;
|
||||
|
||||
if (GNUNET_SYSERR == ret)
|
||||
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
|
||||
section_name,
|
||||
"AGE_RESTRICTED",
|
||||
"Value must be YES or NO\n");
|
||||
return null_mask;
|
||||
}
|
||||
}
|
||||
|
||||
return age_mask;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@ -1187,6 +1174,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,
|
||||
@ -1601,7 +1590,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
|
||||
@ -1719,7 +1708,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 */
|
||||
@ -1755,7 +1745,7 @@ create_krd (struct TEH_KeyStateHandle *ksh,
|
||||
json_t *sig;
|
||||
int r;
|
||||
|
||||
r = json_object_set_new (
|
||||
r = json_object_set (
|
||||
keys,
|
||||
"extensions",
|
||||
extensions);
|
||||
@ -1771,14 +1761,14 @@ create_krd (struct TEH_KeyStateHandle *ksh,
|
||||
GNUNET_assert (0 == r);
|
||||
}
|
||||
|
||||
// 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));
|
||||
@ -1857,7 +1847,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);
|
||||
@ -1882,19 +1874,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;
|
||||
|
||||
@ -1908,6 +1904,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);
|
||||
@ -1936,14 +1937,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 (
|
||||
@ -1970,18 +1971,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 (
|
||||
@ -1990,13 +1999,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,
|
||||
@ -2010,7 +2033,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);
|
||||
@ -2667,7 +2690,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;
|
||||
}
|
||||
|
||||
@ -2794,7 +2819,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);
|
||||
|
@ -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. */
|
||||
{
|
||||
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))
|
||||
verify_extensions_from_json (extensions, &sec))
|
||||
{
|
||||
ret = TALER_MHD_reply_with_error (
|
||||
GNUNET_JSON_parse_free (top_spec);
|
||||
return TALER_MHD_reply_with_error (
|
||||
connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
TALER_EC_GENERIC_PARAMETER_MALFORMED,
|
||||
"invalid configuration for extension");
|
||||
goto CLEANUP;
|
||||
"invalid object");
|
||||
}
|
||||
|
||||
/* We have a validly signed JSON object for the extension. Increment its
|
||||
* refcount.
|
||||
*/
|
||||
json_incref (sec.extensions[idx].config);
|
||||
idx++;
|
||||
|
||||
} /* json_object_foreach */
|
||||
}
|
||||
|
||||
|
||||
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++)
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -278,6 +278,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 */
|
||||
@ -287,6 +288,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 */
|
||||
@ -299,6 +301,7 @@ check_melt_valid (struct MHD_Connection *connection,
|
||||
|
||||
rmc->coin_refresh_fee = dk->meta.fee_refresh;
|
||||
rmc->coin_value = dk->meta.value;
|
||||
|
||||
/* sanity-check that "total melt amount > melt fee" */
|
||||
if (0 <
|
||||
TALER_amount_cmp (&rmc->coin_refresh_fee,
|
||||
@ -328,6 +331,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))
|
||||
{
|
||||
@ -403,6 +407,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",
|
||||
|
@ -248,7 +248,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,
|
||||
&c_hash,
|
||||
&coin_ev,
|
||||
|
@ -250,7 +250,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,
|
||||
&c_hash,
|
||||
&coin_ev,
|
||||
|
@ -191,6 +191,7 @@ check_commitment (struct RevealContext *rctx,
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_planchet_prepare (rcd->dk,
|
||||
&ps,
|
||||
NULL, /* FIXME-Oec, struct TALER_AgeCommitmentHash * */
|
||||
&c_hash,
|
||||
&pd));
|
||||
rcd->coin_ev = pd.coin_ev;
|
||||
@ -285,6 +286,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
|
||||
*/
|
||||
@ -293,6 +295,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);
|
||||
@ -317,6 +320,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++)
|
||||
{
|
||||
@ -443,6 +447,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++)
|
||||
{
|
||||
@ -460,6 +465,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 (
|
||||
@ -467,6 +473,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);
|
||||
@ -489,6 +496,7 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,
|
||||
rcd->coin_ev_size = rrc->coin_ev_size;
|
||||
rcd->dk = &dks[i]->denom_pub;
|
||||
}
|
||||
|
||||
rctx->dks = dks;
|
||||
rctx->rcds = rcds;
|
||||
if (GNUNET_OK !=
|
||||
@ -500,6 +508,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++)
|
||||
{
|
||||
@ -520,8 +529,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;
|
||||
@ -577,11 +588,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
|
||||
*/
|
||||
@ -591,6 +609,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);
|
||||
@ -626,6 +645,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++)
|
||||
{
|
||||
@ -649,6 +681,7 @@ handle_refreshes_reveal_json (struct MHD_Connection *connection,
|
||||
rctx,
|
||||
link_sigs_json,
|
||||
new_denoms_h_json,
|
||||
old_age_commitment_json,
|
||||
coin_evs);
|
||||
}
|
||||
|
||||
@ -662,6 +695,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",
|
||||
@ -674,6 +708,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 ()
|
||||
};
|
||||
|
||||
@ -735,6 +772,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;
|
||||
|
@ -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))))
|
||||
{
|
||||
|
@ -25,7 +25,7 @@ CREATE TABLE IF NOT EXISTS denominations
|
||||
(denominations_serial BIGSERIAL UNIQUE
|
||||
,denom_pub_hash BYTEA PRIMARY KEY CHECK (LENGTH(denom_pub_hash)=64)
|
||||
,denom_type INT4 NOT NULL DEFAULT (1) -- 1 == RSA (for now, remove default later!)
|
||||
,age_restrictions INT4 NOT NULL DEFAULT (0)
|
||||
,age_mask INT4 NOT NULL DEFAULT (0)
|
||||
,denom_pub BYTEA NOT NULL
|
||||
,master_sig BYTEA NOT NULL CHECK (LENGTH(master_sig)=64)
|
||||
,valid_from INT8 NOT NULL
|
||||
@ -47,7 +47,7 @@ COMMENT ON TABLE denominations
|
||||
IS 'Main denominations table. All the valid denominations the exchange knows about.';
|
||||
COMMENT ON COLUMN denominations.denom_type
|
||||
IS 'determines cipher type for blind signatures used with this denomination; 0 is for RSA';
|
||||
COMMENT ON COLUMN denominations.age_restrictions
|
||||
COMMENT ON COLUMN denominations.age_mask
|
||||
IS 'bitmask with the age restrictions that are being used for this denomination; 0 if denomination does not support the use of age restrictions';
|
||||
COMMENT ON COLUMN denominations.denominations_serial
|
||||
IS 'needed for exchange-auditor replication logic';
|
||||
@ -342,6 +342,7 @@ CREATE TABLE IF NOT EXISTS refresh_commitments
|
||||
(melt_serial_id BIGSERIAL -- UNIQUE
|
||||
,rc BYTEA PRIMARY KEY CHECK (LENGTH(rc)=64)
|
||||
,old_coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) ON DELETE CASCADE
|
||||
,h_age_commitment BYTEA CHECK(LENGTH(h_age_commitment)=32)
|
||||
,old_coin_sig BYTEA NOT NULL CHECK(LENGTH(old_coin_sig)=64)
|
||||
,amount_with_fee_val INT8 NOT NULL
|
||||
,amount_with_fee_frac INT4 NOT NULL
|
||||
@ -356,6 +357,8 @@ COMMENT ON COLUMN refresh_commitments.rc
|
||||
IS 'Commitment made by the client, hash over the various client inputs in the cut-and-choose protocol';
|
||||
COMMENT ON COLUMN refresh_commitments.old_coin_pub
|
||||
IS 'Coin being melted in the refresh process.';
|
||||
COMMENT ON COLUMN refresh_commitments.h_age_commitment
|
||||
IS '(optional) age commitment that was involved in the minting process of the coin, may be NULL.';
|
||||
CREATE TABLE IF NOT EXISTS refresh_commitments_default
|
||||
PARTITION OF refresh_commitments
|
||||
FOR VALUES WITH (MODULUS 1, REMAINDER 0);
|
||||
|
@ -231,10 +231,11 @@ prepare_statements (struct PostgresClosure *pg)
|
||||
",fee_refresh_frac"
|
||||
",fee_refund_val"
|
||||
",fee_refund_frac"
|
||||
",age_mask"
|
||||
") VALUES "
|
||||
"($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
|
||||
" $11, $12, $13, $14, $15, $16, $17);",
|
||||
17),
|
||||
" $11, $12, $13, $14, $15, $16, $17, $18);",
|
||||
18),
|
||||
/* Used in #postgres_iterate_denomination_info() */
|
||||
GNUNET_PQ_make_prepare (
|
||||
"denomination_iterate",
|
||||
@ -255,6 +256,7 @@ prepare_statements (struct PostgresClosure *pg)
|
||||
",fee_refund_val"
|
||||
",fee_refund_frac"
|
||||
",denom_pub"
|
||||
",age_mask"
|
||||
" FROM denominations;",
|
||||
0),
|
||||
/* Used in #postgres_iterate_denominations() */
|
||||
@ -278,6 +280,7 @@ prepare_statements (struct PostgresClosure *pg)
|
||||
",fee_refund_val"
|
||||
",fee_refund_frac"
|
||||
",denom_pub"
|
||||
",age_mask"
|
||||
" FROM denominations"
|
||||
" LEFT JOIN "
|
||||
" denomination_revocations USING (denominations_serial);",
|
||||
@ -341,6 +344,7 @@ prepare_statements (struct PostgresClosure *pg)
|
||||
",fee_refresh_frac"
|
||||
",fee_refund_val"
|
||||
",fee_refund_frac"
|
||||
",age_mask"
|
||||
" FROM denominations"
|
||||
" WHERE denom_pub_hash=$1;",
|
||||
1),
|
||||
@ -830,6 +834,7 @@ prepare_statements (struct PostgresClosure *pg)
|
||||
",denoms.fee_refresh_frac"
|
||||
",old_coin_pub"
|
||||
",old_coin_sig"
|
||||
",h_age_commitment"
|
||||
",amount_with_fee_val"
|
||||
",amount_with_fee_frac"
|
||||
",noreveal_index"
|
||||
@ -848,6 +853,7 @@ prepare_statements (struct PostgresClosure *pg)
|
||||
"SELECT"
|
||||
" denom.denom_pub"
|
||||
",kc.coin_pub AS old_coin_pub"
|
||||
",h_age_commitment"
|
||||
",old_coin_sig"
|
||||
",amount_with_fee_val"
|
||||
",amount_with_fee_frac"
|
||||
@ -1842,6 +1848,7 @@ prepare_statements (struct PostgresClosure *pg)
|
||||
",fee_refresh_frac"
|
||||
",fee_refund_val"
|
||||
",fee_refund_frac"
|
||||
",age_mask"
|
||||
" FROM denominations"
|
||||
" WHERE denom_pub_hash=$1;",
|
||||
1),
|
||||
@ -2069,7 +2076,6 @@ prepare_statements (struct PostgresClosure *pg)
|
||||
"SELECT"
|
||||
" denominations_serial AS serial"
|
||||
",denom_type"
|
||||
",age_restrictions"
|
||||
",denom_pub"
|
||||
",master_sig"
|
||||
",valid_from"
|
||||
@ -2086,6 +2092,7 @@ prepare_statements (struct PostgresClosure *pg)
|
||||
",fee_refresh_frac"
|
||||
",fee_refund_val"
|
||||
",fee_refund_frac"
|
||||
",age_mask"
|
||||
" FROM denominations"
|
||||
" WHERE denominations_serial > $1"
|
||||
" ORDER BY denominations_serial ASC;",
|
||||
@ -2388,10 +2395,11 @@ prepare_statements (struct PostgresClosure *pg)
|
||||
",fee_refresh_frac"
|
||||
",fee_refund_val"
|
||||
",fee_refund_frac"
|
||||
",age_mask"
|
||||
") VALUES "
|
||||
"($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
|
||||
" $11, $12, $13, $14, $15, $16, $17, $18);",
|
||||
18),
|
||||
" $11, $12, $13, $14, $15, $16, $17, $18, $19);",
|
||||
19),
|
||||
GNUNET_PQ_make_prepare (
|
||||
"insert_into_table_denomination_revocations",
|
||||
"INSERT INTO denomination_revocations"
|
||||
@ -3094,9 +3102,12 @@ postgres_insert_denomination_info (
|
||||
TALER_PQ_query_param_amount_nbo (&issue->properties.fee_deposit),
|
||||
TALER_PQ_query_param_amount_nbo (&issue->properties.fee_refresh),
|
||||
TALER_PQ_query_param_amount_nbo (&issue->properties.fee_refund),
|
||||
GNUNET_PQ_query_param_uint32 (&denom_pub->age_mask.mask),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
|
||||
GNUNET_assert (denom_pub->age_mask.mask == issue->age_mask.mask);
|
||||
|
||||
GNUNET_assert (! GNUNET_TIME_absolute_is_zero (
|
||||
GNUNET_TIME_timestamp_ntoh (
|
||||
issue->properties.start).abs_time));
|
||||
@ -3170,6 +3181,8 @@ postgres_get_denomination_info (
|
||||
&issue->properties.fee_refresh),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT_NBO ("fee_refund",
|
||||
&issue->properties.fee_refund),
|
||||
GNUNET_PQ_result_spec_uint32 ("age_mask",
|
||||
&issue->age_mask.mask),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
@ -3256,12 +3269,15 @@ domination_cb_helper (void *cls,
|
||||
&issue.properties.fee_refund),
|
||||
TALER_PQ_result_spec_denom_pub ("denom_pub",
|
||||
&denom_pub),
|
||||
GNUNET_PQ_result_spec_uint32 ("age_mask",
|
||||
&issue.age_mask.mask),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
memset (&issue.properties.master,
|
||||
0,
|
||||
sizeof (issue.properties.master));
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PQ_extract_result (result,
|
||||
rs,
|
||||
@ -3270,6 +3286,13 @@ domination_cb_helper (void *cls,
|
||||
GNUNET_break (0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Unfortunately we have to carry the age mask in both, the
|
||||
* TALER_DenominationPublicKey and
|
||||
* TALER_EXCHANGEDB_DenominationKeyInformationP at different times.
|
||||
* Here we use _both_ so let's make sure the values are the same. */
|
||||
denom_pub.age_mask = issue.age_mask;
|
||||
|
||||
issue.properties.purpose.size
|
||||
= htonl (sizeof (struct TALER_DenominationKeyValidityPS));
|
||||
issue.properties.purpose.purpose
|
||||
@ -3355,10 +3378,10 @@ dominations_cb_helper (void *cls,
|
||||
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
struct TALER_EXCHANGEDB_DenominationKeyMetaData meta;
|
||||
struct TALER_DenominationPublicKey denom_pub;
|
||||
struct TALER_MasterSignatureP master_sig;
|
||||
struct TALER_DenominationHash h_denom_pub;
|
||||
struct TALER_EXCHANGEDB_DenominationKeyMetaData meta = {0};
|
||||
struct TALER_DenominationPublicKey denom_pub = {0};
|
||||
struct TALER_MasterSignatureP master_sig = {0};
|
||||
struct TALER_DenominationHash h_denom_pub = {0};
|
||||
bool revoked;
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_auto_from_type ("master_sig",
|
||||
@ -3385,6 +3408,8 @@ dominations_cb_helper (void *cls,
|
||||
&meta.fee_refund),
|
||||
TALER_PQ_result_spec_denom_pub ("denom_pub",
|
||||
&denom_pub),
|
||||
GNUNET_PQ_result_spec_uint32 ("age_mask",
|
||||
&meta.age_mask.mask),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
@ -3396,6 +3421,10 @@ dominations_cb_helper (void *cls,
|
||||
GNUNET_break (0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* make sure the mask information is the same */
|
||||
denom_pub.age_mask = meta.age_mask;
|
||||
|
||||
TALER_denom_pub_hash (&denom_pub,
|
||||
&h_denom_pub);
|
||||
dic->cb (dic->cb_cls,
|
||||
@ -5730,11 +5759,13 @@ postgres_ensure_coin_known (void *cls,
|
||||
const struct TALER_CoinPublicInfo *coin,
|
||||
uint64_t *known_coin_id,
|
||||
struct TALER_DenominationHash *denom_hash,
|
||||
struct TALER_AgeHash *age_hash)
|
||||
struct TALER_AgeCommitmentHash *age_hash)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
bool existed;
|
||||
bool is_denom_pub_hash_null = false;
|
||||
bool is_age_hash_null = false;
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_auto_from_type (&coin->coin_pub),
|
||||
GNUNET_PQ_query_param_auto_from_type (&coin->denom_pub_hash),
|
||||
@ -5742,24 +5773,22 @@ postgres_ensure_coin_known (void *cls,
|
||||
TALER_PQ_query_param_denom_sig (&coin->denom_sig),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
bool is_null = false;
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
GNUNET_PQ_result_spec_bool ("existed",
|
||||
&existed),
|
||||
GNUNET_PQ_result_spec_uint64 ("known_coin_id",
|
||||
known_coin_id),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_auto_from_type ("age_hash",
|
||||
age_hash),
|
||||
&is_null),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_auto_from_type ("denom_pub_hash",
|
||||
denom_hash),
|
||||
&is_null),
|
||||
&is_denom_pub_hash_null),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_auto_from_type ("age_hash",
|
||||
age_hash),
|
||||
&is_age_hash_null),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
GNUNET_break (GNUNET_is_zero (&coin->age_commitment_hash)); // FIXME-OEC
|
||||
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
|
||||
"insert_known_coin",
|
||||
params,
|
||||
@ -5779,21 +5808,24 @@ postgres_ensure_coin_known (void *cls,
|
||||
return TALER_EXCHANGEDB_CKS_ADDED;
|
||||
break; /* continued below */
|
||||
}
|
||||
if ( (! is_null) &&
|
||||
(0 != GNUNET_memcmp (age_hash,
|
||||
&coin->age_commitment_hash)) )
|
||||
{
|
||||
GNUNET_break (GNUNET_is_zero (age_hash)); // FIXME-OEC
|
||||
GNUNET_break_op (0);
|
||||
return TALER_EXCHANGEDB_CKS_AGE_CONFLICT;
|
||||
}
|
||||
if ( (! is_null) &&
|
||||
(0 != GNUNET_memcmp (denom_hash,
|
||||
&coin->denom_pub_hash)) )
|
||||
|
||||
if ( (! is_denom_pub_hash_null) &&
|
||||
(0 != GNUNET_memcmp (&denom_hash->hash,
|
||||
&coin->denom_pub_hash.hash)) )
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return TALER_EXCHANGEDB_CKS_DENOM_CONFLICT;
|
||||
}
|
||||
|
||||
if ( (! is_age_hash_null) &&
|
||||
(0 != GNUNET_memcmp (age_hash,
|
||||
&coin->age_commitment_hash)) )
|
||||
{
|
||||
GNUNET_break (GNUNET_is_zero (age_hash));
|
||||
GNUNET_break_op (0);
|
||||
return TALER_EXCHANGEDB_CKS_AGE_CONFLICT;
|
||||
}
|
||||
|
||||
return TALER_EXCHANGEDB_CKS_PRESENT;
|
||||
}
|
||||
|
||||
@ -6019,6 +6051,7 @@ postgres_get_melt (void *cls,
|
||||
uint64_t *melt_serial_id)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
bool h_age_commitment_is_null;
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
GNUNET_PQ_query_param_auto_from_type (rc),
|
||||
GNUNET_PQ_query_param_end
|
||||
@ -6035,6 +6068,10 @@ postgres_get_melt (void *cls,
|
||||
&melt->session.coin.coin_pub),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("old_coin_sig",
|
||||
&melt->session.coin_sig),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_auto_from_type ("h_age_commitment",
|
||||
&melt->session.h_age_commitment),
|
||||
&h_age_commitment_is_null),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
|
||||
&melt->session.amount_with_fee),
|
||||
GNUNET_PQ_result_spec_uint64 ("melt_serial_id",
|
||||
@ -6050,6 +6087,11 @@ postgres_get_melt (void *cls,
|
||||
"get_melt",
|
||||
params,
|
||||
rs);
|
||||
if (h_age_commitment_is_null)
|
||||
memset (&melt->session.h_age_commitment,
|
||||
0,
|
||||
sizeof(melt->session.h_age_commitment));
|
||||
|
||||
melt->session.rc = *rc;
|
||||
return qs;
|
||||
}
|
||||
@ -8202,6 +8244,8 @@ refreshs_serial_helper_cb (void *cls,
|
||||
struct TALER_DenominationPublicKey denom_pub;
|
||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||
struct TALER_CoinSpendSignatureP coin_sig;
|
||||
struct TALER_AgeCommitmentHash h_age_commitment;
|
||||
bool ac_isnull;
|
||||
struct TALER_Amount amount_with_fee;
|
||||
uint32_t noreveal_index;
|
||||
uint64_t rowid;
|
||||
@ -8209,6 +8253,10 @@ refreshs_serial_helper_cb (void *cls,
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
TALER_PQ_result_spec_denom_pub ("denom_pub",
|
||||
&denom_pub),
|
||||
GNUNET_PQ_result_spec_allow_null (
|
||||
GNUNET_PQ_result_spec_auto_from_type ("h_age_commitment",
|
||||
&h_age_commitment),
|
||||
&ac_isnull),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("old_coin_pub",
|
||||
&coin_pub),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("old_coin_sig",
|
||||
@ -8234,9 +8282,11 @@ refreshs_serial_helper_cb (void *cls,
|
||||
rsc->status = GNUNET_SYSERR;
|
||||
return;
|
||||
}
|
||||
|
||||
ret = rsc->cb (rsc->cb_cls,
|
||||
rowid,
|
||||
&denom_pub,
|
||||
ac_isnull ? NULL : &h_age_commitment,
|
||||
&coin_pub,
|
||||
&coin_sig,
|
||||
&amount_with_fee,
|
||||
@ -10173,6 +10223,8 @@ postgres_lookup_denomination_key (
|
||||
&meta->fee_refresh),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_refund",
|
||||
&meta->fee_refund),
|
||||
GNUNET_PQ_result_spec_uint32 ("age_mask",
|
||||
&meta->age_mask.mask),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
|
||||
@ -10216,6 +10268,7 @@ postgres_add_denomination_key (
|
||||
TALER_PQ_query_param_amount (&meta->fee_deposit),
|
||||
TALER_PQ_query_param_amount (&meta->fee_refresh),
|
||||
TALER_PQ_query_param_amount (&meta->fee_refund),
|
||||
GNUNET_PQ_query_param_uint32 (&meta->age_mask.mask),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
|
||||
|
@ -459,6 +459,7 @@ static unsigned int auditor_row_cnt;
|
||||
* @param cls closure
|
||||
* @param rowid unique serial ID for the refresh session in our DB
|
||||
* @param denom_pub denomination of the @a coin_pub
|
||||
* @param h_age_commitment hash of age commitment that went into the minting, may be NULL
|
||||
* @param coin_pub public key of the coin
|
||||
* @param coin_sig signature from the coin
|
||||
* @param amount_with_fee amount that was deposited including fee
|
||||
@ -471,6 +472,8 @@ static enum GNUNET_GenericReturnValue
|
||||
audit_refresh_session_cb (void *cls,
|
||||
uint64_t rowid,
|
||||
const struct TALER_DenominationPublicKey *denom_pub,
|
||||
const struct
|
||||
TALER_AgeCommitmentHash *h_age_commitment,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_CoinSpendSignatureP *coin_sig,
|
||||
const struct TALER_Amount *amount_with_fee,
|
||||
@ -1467,8 +1470,8 @@ run (void *cls)
|
||||
{
|
||||
struct TALER_PlanchetDetail pd;
|
||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||
struct TALER_AgeHash age_hash;
|
||||
struct TALER_AgeHash *p_ah[2] = {NULL, &age_hash};
|
||||
struct TALER_AgeCommitmentHash age_hash;
|
||||
struct TALER_AgeCommitmentHash *p_ah[2] = {NULL, &age_hash};
|
||||
|
||||
/* Call TALER_denom_blind()/TALER_denom_sign_blinded() twice, once without
|
||||
* age_hash, once with age_hash */
|
||||
@ -1576,7 +1579,7 @@ run (void *cls)
|
||||
deadline = GNUNET_TIME_timestamp_get ();
|
||||
{
|
||||
struct TALER_DenominationHash dph;
|
||||
struct TALER_AgeHash agh;
|
||||
struct TALER_AgeCommitmentHash agh;
|
||||
|
||||
FAILIF (TALER_EXCHANGEDB_CKS_ADDED !=
|
||||
plugin->ensure_coin_known (plugin->cls,
|
||||
@ -1819,7 +1822,7 @@ run (void *cls)
|
||||
uint64_t new_known_coin_id;
|
||||
struct TALER_CoinPublicInfo new_coin;
|
||||
struct TALER_DenominationHash dph;
|
||||
struct TALER_AgeHash agh;
|
||||
struct TALER_AgeCommitmentHash agh;
|
||||
bool recoup_ok;
|
||||
bool internal_failure;
|
||||
|
||||
@ -2171,7 +2174,7 @@ run (void *cls)
|
||||
{
|
||||
uint64_t known_coin_id;
|
||||
struct TALER_DenominationHash dph;
|
||||
struct TALER_AgeHash agh;
|
||||
struct TALER_AgeCommitmentHash agh;
|
||||
|
||||
FAILIF (TALER_EXCHANGEDB_CKS_ADDED !=
|
||||
plugin->ensure_coin_known (plugin->cls,
|
||||
|
@ -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;
|
||||
|
||||
this->config = GNUNET_malloc (sizeof(struct TALER_AgeMask));
|
||||
GNUNET_memcpy (this->config, &mask, sizeof(struct TALER_AgeMask));
|
||||
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 = &_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 */
|
||||
|
@ -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 */
|
||||
|
@ -280,37 +280,6 @@ struct TALER_MasterSignatureP
|
||||
struct GNUNET_CRYPTO_EddsaSignature eddsa_signature;
|
||||
};
|
||||
|
||||
/*
|
||||
* @brief Type of a list of age groups, represented as bit mask.
|
||||
*
|
||||
* The bits set in the mask mark the edges at the beginning of a next age
|
||||
* group. F.e. for the age groups
|
||||
* 0-7, 8-9, 10-11, 12-14, 14-15, 16-17, 18-21, 21-*
|
||||
* the following bits are set:
|
||||
*
|
||||
* 31 24 16 8 0
|
||||
* | | | | |
|
||||
* oooooooo oo1oo1o1 o1o1o1o1 ooooooo1
|
||||
*
|
||||
* A value of 0 means that the exchange does not support the extension for
|
||||
* age-restriction.
|
||||
*/
|
||||
struct TALER_AgeMask
|
||||
{
|
||||
uint32_t mask;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Age restriction commitment of a coin.
|
||||
*/
|
||||
struct TALER_AgeHash
|
||||
{
|
||||
/**
|
||||
* The commitment is a SHA-256 hash code.
|
||||
*/
|
||||
struct GNUNET_ShortHashCode shash;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Type of public keys for Taler coins. The same key material is used
|
||||
@ -338,6 +307,29 @@ struct TALER_CoinSpendPrivateKeyP
|
||||
struct GNUNET_CRYPTO_EddsaPrivateKey eddsa_priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Type of private keys for age commitment in coins.
|
||||
*/
|
||||
struct TALER_AgeCommitmentPrivateKeyP
|
||||
{
|
||||
/**
|
||||
* Taler uses EdDSA for coins when signing age verification attestation.
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EddsaPrivateKey eddsa_priv;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Type of public keys for age commitment in coins.
|
||||
*/
|
||||
struct TALER_AgeCommitmentPublicKeyP
|
||||
{
|
||||
/**
|
||||
* Taler uses EdDSA for coins when signing age verification attestation.
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey eddsa_pub;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Type of signatures made with Taler coins.
|
||||
@ -635,6 +627,46 @@ struct TALER_BlindedDenominationSignature
|
||||
|
||||
};
|
||||
|
||||
/* *************** Age Restriction *********************************** */
|
||||
|
||||
/*
|
||||
* @brief Type of a list of age groups, represented as bit mask.
|
||||
*
|
||||
* The bits set in the mask mark the edges at the beginning of a next age
|
||||
* group. F.e. for the age groups
|
||||
* 0-7, 8-9, 10-11, 12-14, 14-15, 16-17, 18-21, 21-*
|
||||
* the following bits are set:
|
||||
*
|
||||
* 31 24 16 8 0
|
||||
* | | | | |
|
||||
* oooooooo oo1oo1o1 o1o1o1o1 ooooooo1
|
||||
*
|
||||
* A value of 0 means that the exchange does not support the extension for
|
||||
* age-restriction.
|
||||
*/
|
||||
struct TALER_AgeMask
|
||||
{
|
||||
uint32_t mask;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Age commitment of a coin.
|
||||
*/
|
||||
struct TALER_AgeCommitmentHash
|
||||
{
|
||||
/**
|
||||
* The commitment is a SHA-256 hash code.
|
||||
*/
|
||||
struct GNUNET_ShortHashCode shash;
|
||||
};
|
||||
|
||||
extern const struct TALER_AgeCommitmentHash TALER_ZeroAgeCommitmentHash;
|
||||
#define TALER_AgeCommitmentHash_isNullOrZero(ph) ((NULL == ph) || \
|
||||
(0 == memcmp (ph, \
|
||||
& \
|
||||
TALER_ZeroAgeCommitmentHash, \
|
||||
sizeof(struct \
|
||||
TALER_AgeCommitmentHash))))
|
||||
|
||||
/**
|
||||
* @brief Type of public signing keys for verifying blindly signed coins.
|
||||
@ -712,9 +744,10 @@ struct TALER_CoinPublicInfo
|
||||
struct TALER_DenominationHash denom_pub_hash;
|
||||
|
||||
/**
|
||||
* Hash of the age commitment.
|
||||
* Hash of the age commitment. If no age commitment was provided, it must be
|
||||
* set to all zeroes.
|
||||
*/
|
||||
struct TALER_AgeHash age_commitment_hash;
|
||||
struct TALER_AgeCommitmentHash age_commitment_hash;
|
||||
|
||||
/**
|
||||
* (Unblinded) signature over @e coin_pub with @e denom_pub,
|
||||
@ -824,7 +857,7 @@ TALER_denom_sig_free (struct TALER_DenominationSignature *denom_sig);
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_denom_blind (const struct TALER_DenominationPublicKey *dk,
|
||||
const union TALER_DenominationBlindingKeyP *coin_bks,
|
||||
const struct TALER_AgeHash *age_commitment_hash,
|
||||
const struct TALER_AgeCommitmentHash *age_commitment_hash,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
struct TALER_CoinPubHash *c_hash,
|
||||
void **coin_ev,
|
||||
@ -1024,7 +1057,7 @@ TALER_coin_ev_hash (const void *coin_ev,
|
||||
*/
|
||||
void
|
||||
TALER_coin_pub_hash (const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_AgeHash *age_commitment_hash,
|
||||
const struct TALER_AgeCommitmentHash *age_commitment_hash,
|
||||
struct TALER_CoinPubHash *coin_h);
|
||||
|
||||
|
||||
@ -1110,8 +1143,9 @@ struct TALER_FreshCoin
|
||||
struct TALER_CoinSpendPrivateKeyP coin_priv;
|
||||
|
||||
/**
|
||||
* FIXME-Oec: Age-verification vector, as pointer: Dyn alloc!
|
||||
* Optional hash of an age commitment bound to this coin, maybe NULL.
|
||||
*/
|
||||
const struct TALER_AgeCommitmentHash *h_age_commitment;
|
||||
};
|
||||
|
||||
|
||||
@ -1232,6 +1266,7 @@ TALER_planchet_setup_random (struct TALER_PlanchetSecretsP *ps);
|
||||
*
|
||||
* @param dk denomination key for the coin to be created
|
||||
* @param ps secret planchet internals (for #TALER_planchet_to_coin)
|
||||
* @param ach (optional) hash of age commitment to bind to this coin, maybe NULL
|
||||
* @param[out] c_hash set to the hash of the public key of the coin (needed later)
|
||||
* @param[out] pd set to the planchet detail for TALER_MERCHANT_tip_pickup() and
|
||||
* other withdraw operations
|
||||
@ -1240,6 +1275,7 @@ TALER_planchet_setup_random (struct TALER_PlanchetSecretsP *ps);
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_planchet_prepare (const struct TALER_DenominationPublicKey *dk,
|
||||
const struct TALER_PlanchetSecretsP *ps,
|
||||
const struct TALER_AgeCommitmentHash *ach,
|
||||
struct TALER_CoinPubHash *c_hash,
|
||||
struct TALER_PlanchetDetail *pd);
|
||||
|
||||
@ -1251,6 +1287,7 @@ TALER_planchet_prepare (const struct TALER_DenominationPublicKey *dk,
|
||||
* @param dk denomination key, must match what was given to #TALER_planchet_prepare()
|
||||
* @param blind_sig blind signature from the exchange
|
||||
* @param ps secrets from #TALER_planchet_prepare()
|
||||
* @param ach (optional) hash of age commitment that is bound to this coin, maybe NULL
|
||||
* @param c_hash hash of the coin's public key for verification of the signature
|
||||
* @param[out] coin set to the details of the fresh coin
|
||||
* @return #GNUNET_OK on success
|
||||
@ -1260,6 +1297,7 @@ TALER_planchet_to_coin (
|
||||
const struct TALER_DenominationPublicKey *dk,
|
||||
const struct TALER_BlindedDenominationSignature *blind_sig,
|
||||
const struct TALER_PlanchetSecretsP *ps,
|
||||
const struct TALER_AgeCommitmentHash *ach,
|
||||
const struct TALER_CoinPubHash *c_hash,
|
||||
struct TALER_FreshCoin *coin);
|
||||
|
||||
@ -1682,6 +1720,7 @@ TALER_exchange_deposit_confirm_verify (
|
||||
* @param deposit_fee the deposit fee we expect to pay
|
||||
* @param h_wire hash of the merchant’s account details
|
||||
* @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the exchange)
|
||||
* @param h_age_commitment hash over the age commitment, if applicable to the denomination (maybe NULL)
|
||||
* @param h_extensions hash over the extensions
|
||||
* @param h_denom_pub hash of the coin denomination's public key
|
||||
* @param coin_priv coin’s private key
|
||||
@ -1696,6 +1735,7 @@ TALER_wallet_deposit_sign (
|
||||
const struct TALER_Amount *deposit_fee,
|
||||
const struct TALER_MerchantWireHash *h_wire,
|
||||
const struct TALER_PrivateContractHash *h_contract_terms,
|
||||
const struct TALER_AgeCommitmentHash *h_age_commitment,
|
||||
const struct TALER_ExtensionContractHash *h_extensions,
|
||||
const struct TALER_DenominationHash *h_denom_pub,
|
||||
struct GNUNET_TIME_Timestamp wallet_timestamp,
|
||||
@ -1712,6 +1752,7 @@ TALER_wallet_deposit_sign (
|
||||
* @param deposit_fee the deposit fee we expect to pay
|
||||
* @param h_wire hash of the merchant’s account details
|
||||
* @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the exchange)
|
||||
* @param h_age_commitment hash over the age commitment (maybe all zeroes, if not applicable to the denomination)
|
||||
* @param h_extensions hash over the extensions
|
||||
* @param h_denom_pub hash of the coin denomination's public key
|
||||
* @param wallet_timestamp timestamp when the contract was finalized, must not be too far in the future
|
||||
@ -1727,6 +1768,7 @@ TALER_wallet_deposit_verify (
|
||||
const struct TALER_Amount *deposit_fee,
|
||||
const struct TALER_MerchantWireHash *h_wire,
|
||||
const struct TALER_PrivateContractHash *h_contract_terms,
|
||||
const struct TALER_AgeCommitmentHash *h_commitment_hash,
|
||||
const struct TALER_ExtensionContractHash *h_extensions,
|
||||
const struct TALER_DenominationHash *h_denom_pub,
|
||||
struct GNUNET_TIME_Timestamp wallet_timestamp,
|
||||
@ -1763,6 +1805,7 @@ TALER_wallet_melt_sign (
|
||||
* @param melt_fee the melt fee we expect to pay
|
||||
* @param rc refresh session we are committed to
|
||||
* @param h_denom_pub hash of the coin denomination's public key
|
||||
* @param h_age_commitment hash of the age commitment (may be NULL)
|
||||
* @param coin_pub coin’s public key
|
||||
* @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_MELT
|
||||
* @return #GNUNET_OK if the signature is valid
|
||||
@ -1773,6 +1816,7 @@ TALER_wallet_melt_verify (
|
||||
const struct TALER_Amount *melt_fee,
|
||||
const struct TALER_RefreshCommitmentP *rc,
|
||||
const struct TALER_DenominationHash *h_denom_pub,
|
||||
const struct TALER_AgeCommitmentHash *h_age_commitment,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_CoinSpendSignatureP *coin_sig);
|
||||
|
||||
@ -1803,6 +1847,7 @@ TALER_wallet_link_sign (const struct TALER_DenominationHash *h_denom_pub,
|
||||
* @param transfer_pub transfer public key
|
||||
* @param h_coin_ev hash of the coin envelope
|
||||
* @param old_coin_pub old coin key that the link signature is for
|
||||
* @param h_age_commitment hash of age commitment. Maybe NULL, if not applicable.
|
||||
* @param coin_sig resulting signature
|
||||
* @return #GNUNET_OK if the signature is valid
|
||||
*/
|
||||
@ -1812,6 +1857,7 @@ TALER_wallet_link_verify (
|
||||
const struct TALER_TransferPublicKeyP *transfer_pub,
|
||||
const struct TALER_BlindedCoinHash *h_coin_ev,
|
||||
const struct TALER_CoinSpendPublicKeyP *old_coin_pub,
|
||||
const struct TALER_AgeCommitmentHash *h_age_commitment,
|
||||
const struct TALER_CoinSpendSignatureP *coin_sig);
|
||||
|
||||
|
||||
@ -2557,5 +2603,100 @@ TALER_exchange_offline_extension_config_hash_verify (
|
||||
const struct TALER_MasterSignatureP *master_sig
|
||||
);
|
||||
|
||||
/*
|
||||
* @brief Representation of an age commitment: one public key per age group.
|
||||
*
|
||||
* The number of keys must be be the same as the number of bits set in the
|
||||
* corresponding age mask.
|
||||
*/
|
||||
struct TALER_AgeCommitment
|
||||
{
|
||||
|
||||
/* The age mask defines the age groups that were a parameter during the
|
||||
* generation of this age commitment */
|
||||
struct TALER_AgeMask mask;
|
||||
|
||||
/* The number of public keys, which must be the same as the number of
|
||||
* groups in the mask.
|
||||
*/
|
||||
size_t num_pub;
|
||||
|
||||
/* The list of #num_pub public keys. In must have same size as the number of
|
||||
* age groups defined in the mask.
|
||||
*
|
||||
* A hash of this list is the hashed commitment that goes into FDC
|
||||
* calculation during the withdraw and refresh operations for new coins. That
|
||||
* way, the particular age commitment becomes mandatory and bound to a coin.
|
||||
*
|
||||
* The list has been allocated via GNUNET_malloc.
|
||||
*/
|
||||
struct TALER_AgeCommitmentPublicKeyP *pub;
|
||||
|
||||
/* The number of private keys, which must be at most num_pub_keys. One minus
|
||||
* this number corresponds to the largest age group that is supported with
|
||||
* this age commitment.
|
||||
*/
|
||||
size_t num_priv;
|
||||
|
||||
/* List of #num_priv private keys.
|
||||
*
|
||||
* Note that the list can be _smaller_ than the corresponding list of public
|
||||
* keys. In that case, the wallet can sign off only for a subset of the age
|
||||
* groups.
|
||||
*
|
||||
* The list has been allocated via GNUNET_malloc.
|
||||
*/
|
||||
struct TALER_AgeCommitmentPrivateKeyP *priv;
|
||||
};
|
||||
|
||||
/*
|
||||
* @brief Generates a hash of the public keys in the age commitment.
|
||||
*
|
||||
* @param commitment the age commitment - one public key per age group
|
||||
* @param[out] hash resulting hash
|
||||
*/
|
||||
void
|
||||
TALER_age_commitment_hash (
|
||||
const struct TALER_AgeCommitment *commitment,
|
||||
struct TALER_AgeCommitmentHash *hash);
|
||||
|
||||
/*
|
||||
* @brief Generates an age commitent for the given age.
|
||||
*
|
||||
* @param mask The age mask the defines the age groups
|
||||
* @param age The actual age for which an age commitment is generated
|
||||
* @param seed The seed that goes into the key generation. MUST be choosen uniformly random.
|
||||
* @param commitment[out] The generated age commitment, ->priv and ->pub allocated via GNUNET_malloc on success
|
||||
* @return GNUNET_OK on success, GNUNET_SYSERR otherwise
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_age_restriction_commit (
|
||||
const struct TALER_AgeMask *mask,
|
||||
const uint8_t age,
|
||||
const uint32_t seed,
|
||||
struct TALER_AgeCommitment *commitment);
|
||||
|
||||
/*
|
||||
* @brief Derives another, equivalent age commitment for a given one.
|
||||
*
|
||||
* @param orig Original age commitment
|
||||
* @param seed Used to move the points on the elliptic curve in order to generate another, equivalent commitment.
|
||||
* @param derived[out] The resulting age commitment, ->priv and ->pub allocated via GNUNET_malloc on success.
|
||||
* @return GNUNET_OK on success, GNUNET_SYSERR otherwise
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_age_commitment_derive (
|
||||
const struct TALER_AgeCommitment *orig,
|
||||
const uint32_t seed,
|
||||
struct TALER_AgeCommitment *derived);
|
||||
|
||||
/*
|
||||
* @brief helper function to free memory inside a struct TALER_AgeCommitment
|
||||
* @param cmt the commitment from which internal memory should be freed. Note
|
||||
* that cmt itself is NOT freed!
|
||||
*/
|
||||
void
|
||||
TALER_age_restriction_commitment_free_inside (
|
||||
struct TALER_AgeCommitment *cmt);
|
||||
|
||||
#endif
|
||||
|
@ -159,11 +159,6 @@ struct TALER_EXCHANGE_DenomPublicKey
|
||||
* revoked by the exchange.
|
||||
*/
|
||||
bool revoked;
|
||||
|
||||
/**
|
||||
* Is the denomination age-restricted?
|
||||
*/
|
||||
bool age_restricted;
|
||||
};
|
||||
|
||||
|
||||
@ -785,6 +780,7 @@ TALER_EXCHANGE_wire_cancel (struct TALER_EXCHANGE_WireHandle *wh);
|
||||
* @param h_extensions hash over the extensions
|
||||
* @param h_denom_pub hash of the coin denomination's public key
|
||||
* @param coin_priv coin’s private key
|
||||
* @param age_commitment age commitment that went into the making of the coin, might be NULL
|
||||
* @param wallet_timestamp timestamp when the contract was finalized, must not be too far in the future
|
||||
* @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests)
|
||||
* @param refund_deadline date until which the merchant can issue a refund to the customer via the exchange (can be zero if refunds are not allowed); must not be after the @a wire_deadline
|
||||
@ -799,6 +795,7 @@ TALER_EXCHANGE_deposit_permission_sign (
|
||||
const struct TALER_ExtensionContractHash *h_extensions,
|
||||
const struct TALER_DenominationHash *h_denom_pub,
|
||||
const struct TALER_CoinSpendPrivateKeyP *coin_priv,
|
||||
const struct TALER_AgeCommitment *age_commitment,
|
||||
struct GNUNET_TIME_Timestamp wallet_timestamp,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
struct GNUNET_TIME_Timestamp refund_deadline,
|
||||
@ -924,6 +921,7 @@ TALER_EXCHANGE_deposit (
|
||||
const char *merchant_payto_uri,
|
||||
const struct TALER_WireSalt *wire_salt,
|
||||
const struct TALER_PrivateContractHash *h_contract_terms,
|
||||
const struct TALER_AgeCommitmentHash *h_age_commitment,
|
||||
const json_t *extension_details,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_DenominationSignature *denom_sig,
|
||||
@ -1359,6 +1357,7 @@ typedef void
|
||||
* @param reserve_priv private key of the reserve to withdraw from
|
||||
* @param ps secrets of the planchet
|
||||
* caller must have committed this value to disk before the call (with @a pk)
|
||||
* @param ach (optional) hash of the age commitment that should be bound to this coin. Maybe NULL.
|
||||
* @param res_cb the callback to call when the final result for this request is available
|
||||
* @param res_cb_cls closure for @a res_cb
|
||||
* @return NULL
|
||||
@ -1371,6 +1370,7 @@ TALER_EXCHANGE_withdraw (
|
||||
const struct TALER_EXCHANGE_DenomPublicKey *pk,
|
||||
const struct TALER_ReservePrivateKeyP *reserve_priv,
|
||||
const struct TALER_PlanchetSecretsP *ps,
|
||||
const struct TALER_AgeCommitmentHash *ach,
|
||||
TALER_EXCHANGE_WithdrawCallback res_cb,
|
||||
void *res_cb_cls);
|
||||
|
||||
@ -1479,6 +1479,8 @@ TALER_EXCHANGE_withdraw2_cancel (struct TALER_EXCHANGE_Withdraw2Handle *wh);
|
||||
* @param melt_pk denomination key information
|
||||
* record corresponding to the @a melt_sig
|
||||
* validity of the keys
|
||||
* @param age_commitment (optional) age commitment that went into the original
|
||||
* coin. Maybe NULL, if no age commitment was provided.
|
||||
* @param fresh_pks_len length of the @a pks array
|
||||
* @param fresh_pks array of @a pks_len denominations of fresh coins to create
|
||||
* @return NULL
|
||||
@ -1493,6 +1495,7 @@ TALER_EXCHANGE_refresh_prepare (
|
||||
const struct TALER_Amount *melt_amount,
|
||||
const struct TALER_DenominationSignature *melt_sig,
|
||||
const struct TALER_EXCHANGE_DenomPublicKey *melt_pk,
|
||||
const struct TALER_AgeCommitment *age_commitment,
|
||||
unsigned int fresh_pks_len,
|
||||
const struct TALER_EXCHANGE_DenomPublicKey *fresh_pks);
|
||||
|
||||
|
@ -70,6 +70,12 @@ struct TALER_EXCHANGEDB_DenominationKeyInformationP
|
||||
* Signed properties of the denomination key.
|
||||
*/
|
||||
struct TALER_DenominationKeyValidityPS properties;
|
||||
|
||||
/**
|
||||
* If denomination was setup for age restriction, non-zero age mask.
|
||||
* Note that the mask is not part of the signature.
|
||||
*/
|
||||
struct TALER_AgeMask age_mask;
|
||||
};
|
||||
|
||||
|
||||
@ -295,7 +301,7 @@ struct TALER_EXCHANGEDB_TableData
|
||||
struct
|
||||
{
|
||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||
struct TALER_AgeHash age_hash;
|
||||
struct TALER_AgeCommitmentHash age_hash;
|
||||
uint64_t denominations_serial;
|
||||
struct TALER_DenominationSignature denom_sig;
|
||||
} known_coins;
|
||||
@ -643,7 +649,7 @@ struct TALER_EXCHANGEDB_DenominationKeyMetaData
|
||||
* A value of 0 means that the denomination does not support the extension for
|
||||
* age-restriction.
|
||||
*/
|
||||
struct TALER_AgeMask age_restrictions;
|
||||
struct TALER_AgeMask age_mask;
|
||||
};
|
||||
|
||||
|
||||
@ -1260,6 +1266,13 @@ struct TALER_EXCHANGEDB_Refresh
|
||||
*/
|
||||
struct TALER_CoinSpendSignatureP coin_sig;
|
||||
|
||||
/**
|
||||
* Hash of the age commitment used to sign the coin, if age restriction was
|
||||
* applicable to the denomination. May be all zeroes if no age restriction
|
||||
* applies.
|
||||
*/
|
||||
struct TALER_AgeCommitmentHash h_age_commitment;
|
||||
|
||||
/**
|
||||
* Refresh commitment this coin is melted into.
|
||||
*/
|
||||
@ -1305,6 +1318,13 @@ struct TALER_EXCHANGEDB_MeltListEntry
|
||||
*/
|
||||
struct TALER_DenominationHash h_denom_pub;
|
||||
|
||||
/**
|
||||
* Hash of the age commitment used to sign the coin, if age restriction was
|
||||
* applicable to the denomination. May be all zeroes if no age restriction
|
||||
* applies.
|
||||
*/
|
||||
struct TALER_AgeCommitmentHash h_age_commitment;
|
||||
|
||||
/**
|
||||
* How much value is being melted? This amount includes the fees,
|
||||
* so the final amount contributed to the melt is this value minus
|
||||
@ -1585,6 +1605,7 @@ typedef enum GNUNET_GenericReturnValue
|
||||
* @param cls closure
|
||||
* @param rowid unique serial ID for the refresh session in our DB
|
||||
* @param denom_pub denomination public key of @a coin_pub
|
||||
* @param h_age_commitment age commitment that went into the signing of the coin, may be NULL
|
||||
* @param coin_pub public key of the coin
|
||||
* @param coin_sig signature from the coin
|
||||
* @param amount_with_fee amount that was deposited including fee
|
||||
@ -1597,6 +1618,7 @@ typedef enum GNUNET_GenericReturnValue
|
||||
void *cls,
|
||||
uint64_t rowid,
|
||||
const struct TALER_DenominationPublicKey *denom_pub,
|
||||
const struct TALER_AgeCommitmentHash *h_age_commitment,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_CoinSpendSignatureP *coin_sig,
|
||||
const struct TALER_Amount *amount_with_fee,
|
||||
@ -2735,7 +2757,7 @@ struct TALER_EXCHANGEDB_Plugin
|
||||
const struct TALER_CoinPublicInfo *coin,
|
||||
uint64_t *known_coin_id,
|
||||
struct TALER_DenominationHash *denom_pub_hash,
|
||||
struct TALER_AgeHash *age_hash);
|
||||
struct TALER_AgeCommitmentHash *age_hash);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -85,6 +85,31 @@ enum GNUNET_GenericReturnValue
|
||||
TALER_extensions_load_taler_config (
|
||||
const struct GNUNET_CONFIGURATION_Handle *cfg);
|
||||
|
||||
/*
|
||||
* Check the given obj to be a valid extension object and fill the fields
|
||||
* accordingly.
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_extensions_is_json_config (
|
||||
json_t *obj,
|
||||
int *critical,
|
||||
const char **version,
|
||||
json_t **config);
|
||||
|
||||
/*
|
||||
* Sets the configuration of the extensions from a given JSON object.
|
||||
*
|
||||
* he JSON object must be of type ExchangeKeysResponse as described in
|
||||
* https://docs.taler.net/design-documents/006-extensions.html#exchange
|
||||
*
|
||||
* @param cfg JSON object containting the configuration for all extensions
|
||||
* @return GNUNET_OK on success, GNUNET_SYSERR if unknown extensions were found
|
||||
* or any particular configuration couldn't be parsed.
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_extensions_load_json_config (
|
||||
json_t *cfg);
|
||||
|
||||
/*
|
||||
* Returns the head of the linked list of extensions
|
||||
*/
|
||||
@ -156,20 +181,6 @@ TALER_extensions_verify_json_config_signature (
|
||||
struct TALER_MasterSignatureP *extensions_sig,
|
||||
struct TALER_MasterPublicKeyP *master_pub);
|
||||
|
||||
/*
|
||||
* Sets the configuration of the extensions from a given JSON object.
|
||||
*
|
||||
* The JSON object must be of type ExchangeKeysResponse as described in
|
||||
* https://docs.taler.net/design-documents/006-extensions.html#exchange
|
||||
*
|
||||
* @param cfg Handle to the TALER configuration
|
||||
* @return GNUNET_OK on success, GNUNET_SYSERR if unknown extensions were found
|
||||
* or any particular configuration couldn't be parsed.
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_extensions_load_json_config (
|
||||
json_t *extensions);
|
||||
|
||||
|
||||
/*
|
||||
* TALER Age Restriction Extension
|
||||
@ -221,6 +232,45 @@ char *
|
||||
TALER_age_mask_to_string (
|
||||
const struct TALER_AgeMask *mask);
|
||||
|
||||
/**
|
||||
* Returns true when age restriction is configured and enabled.
|
||||
*/
|
||||
bool
|
||||
TALER_extensions_age_restriction_is_enabled ();
|
||||
|
||||
/**
|
||||
* Returns true when age restriction is configured (might not be _enabled_,
|
||||
* though).
|
||||
*/
|
||||
bool
|
||||
TALER_extensions_age_restriction_is_configured ();
|
||||
|
||||
/**
|
||||
* Returns the currently set age mask. Note that even if age restriction is
|
||||
* not enabled, the age mask might be have a non-zero value.
|
||||
*/
|
||||
struct TALER_AgeMask
|
||||
TALER_extensions_age_restriction_ageMask ();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the amount of age groups defined. 0 means no age restriction
|
||||
* enabled.
|
||||
*/
|
||||
size_t
|
||||
TALER_extensions_age_restriction_num_groups ();
|
||||
|
||||
/**
|
||||
* Parses a JSON object { "age_groups": "a:b:...y:z" }.
|
||||
*
|
||||
* @param root is the json object
|
||||
* @param[out] mask on succes, will contain the age mask
|
||||
* @return #GNUNET_OK on success and #GNUNET_SYSERR on failure.
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_JSON_parse_age_groups (const json_t *root,
|
||||
struct TALER_AgeMask *mask);
|
||||
|
||||
|
||||
/*
|
||||
* TODO: Add Peer2Peer Extension
|
||||
|
@ -552,17 +552,6 @@ enum GNUNET_GenericReturnValue
|
||||
TALER_JSON_extensions_config_hash (const json_t *config,
|
||||
struct TALER_ExtensionConfigHash *eh);
|
||||
|
||||
/**
|
||||
* Parses a JSON object { "extension": "age_restriction", "mask": <uint32> }.
|
||||
*
|
||||
* @param root is the json object
|
||||
* @param[out] mask on succes, will contain the age mask
|
||||
* @return #GNUNET_OK on success and #GNUNET_SYSERR on failure.
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_JSON_parse_agemask (const json_t *root,
|
||||
struct TALER_AgeMask *mask);
|
||||
|
||||
#endif /* TALER_JSON_LIB_H_ */
|
||||
|
||||
/* End of taler_json_lib.h */
|
||||
|
@ -414,6 +414,11 @@ struct TALER_LinkDataPS
|
||||
*/
|
||||
struct TALER_TransferPublicKeyP transfer_pub;
|
||||
|
||||
/**
|
||||
* Hash of the age commitment, if applicable. Can be all zero
|
||||
*/
|
||||
struct TALER_AgeCommitmentHash h_age_commitment;
|
||||
|
||||
/**
|
||||
* Hash of the blinded new coin.
|
||||
*/
|
||||
@ -478,6 +483,12 @@ struct TALER_DepositRequestPS
|
||||
*/
|
||||
struct TALER_PrivateContractHash h_contract_terms GNUNET_PACKED;
|
||||
|
||||
/**
|
||||
* Hash over the age commitment that went into the coin. Maybe all zero, if
|
||||
* age commitment isn't applicable to the denomination.
|
||||
*/
|
||||
struct TALER_AgeCommitmentHash h_age_commitment GNUNET_PACKED;
|
||||
|
||||
/**
|
||||
* Hash over extension attributes shared with the exchange.
|
||||
*/
|
||||
@ -711,6 +722,13 @@ struct TALER_RefreshMeltCoinAffirmationPS
|
||||
*/
|
||||
struct TALER_DenominationHash h_denom_pub GNUNET_PACKED;
|
||||
|
||||
/**
|
||||
* If age commitment was provided during the withdrawal of the coin, this is
|
||||
* the hash of the age commitment vector. It must be all zeroes if no age
|
||||
* commitment was provided.
|
||||
*/
|
||||
struct TALER_AgeCommitmentHash h_age_commitment GNUNET_PACKED;
|
||||
|
||||
/**
|
||||
* How much of the value of the coin should be melted? This amount
|
||||
* includes the fees, so the final amount contributed to the melt is
|
||||
|
@ -66,11 +66,13 @@ TALER_TESTING_make_wire_details (const char *payto);
|
||||
*
|
||||
* @param keys array of keys to search
|
||||
* @param amount coin value to look for
|
||||
* @param age_restricted must the denomination be age restricted?
|
||||
* @return NULL if no matching key was found
|
||||
*/
|
||||
const struct TALER_EXCHANGE_DenomPublicKey *
|
||||
TALER_TESTING_find_pk (const struct TALER_EXCHANGE_Keys *keys,
|
||||
const struct TALER_Amount *amount);
|
||||
const struct TALER_Amount *amount,
|
||||
bool age_restricted);
|
||||
|
||||
|
||||
/**
|
||||
@ -1277,6 +1279,7 @@ TALER_TESTING_cmd_exec_transfer (const char *label,
|
||||
* @param label command label.
|
||||
* @param reserve_reference command providing us with a reserve to withdraw from
|
||||
* @param amount how much we withdraw.
|
||||
* @param age if > 0, age restriction applies
|
||||
* @param expected_response_code which HTTP response code
|
||||
* we expect from the exchange.
|
||||
* @return the withdraw command to be executed by the interpreter.
|
||||
@ -1285,6 +1288,7 @@ struct TALER_TESTING_Command
|
||||
TALER_TESTING_cmd_withdraw_amount (const char *label,
|
||||
const char *reserve_reference,
|
||||
const char *amount,
|
||||
uint8_t age,
|
||||
unsigned int expected_response_code);
|
||||
|
||||
|
||||
@ -1297,6 +1301,7 @@ TALER_TESTING_cmd_withdraw_amount (const char *label,
|
||||
* @param label command label.
|
||||
* @param reserve_reference command providing us with a reserve to withdraw from
|
||||
* @param amount how much we withdraw.
|
||||
* @param age if > 0, age restriction applies.
|
||||
* @param coin_ref reference to (withdraw/reveal) command of a coin
|
||||
* from which we should re-use the private key
|
||||
* @param expected_response_code which HTTP response code
|
||||
@ -1308,6 +1313,7 @@ TALER_TESTING_cmd_withdraw_amount_reuse_key (
|
||||
const char *label,
|
||||
const char *reserve_reference,
|
||||
const char *amount,
|
||||
uint8_t age,
|
||||
const char *coin_ref,
|
||||
unsigned int expected_response_code);
|
||||
|
||||
@ -2138,6 +2144,19 @@ TALER_TESTING_cmd_wire_del (const char *label,
|
||||
unsigned int expected_http_status,
|
||||
bool bad_sig);
|
||||
|
||||
/**
|
||||
* Sign all extensions that the exchange has to offer, f. e. the extension for
|
||||
* age restriction. This has to be run before any withdrawal of age restricted
|
||||
* can be performed.
|
||||
*
|
||||
* @param label command label.
|
||||
* @param config_filename configuration filename.
|
||||
* @return the command
|
||||
*/
|
||||
struct TALER_TESTING_Command
|
||||
TALER_TESTING_cmd_exec_offline_sign_extensions (const char *label,
|
||||
const char *config_filename);
|
||||
|
||||
|
||||
/**
|
||||
* Sign all exchange denomination and online signing keys
|
||||
@ -2482,6 +2501,8 @@ TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits,
|
||||
#define TALER_TESTING_INDEXED_TRAITS(op) \
|
||||
op (denom_pub, const struct TALER_EXCHANGE_DenomPublicKey) \
|
||||
op (denom_sig, const struct TALER_DenominationSignature) \
|
||||
op (age_commitment, struct TALER_AgeCommitment) \
|
||||
op (h_age_commitment, struct TALER_AgeCommitmentHash) \
|
||||
op (coin_priv, const struct TALER_CoinSpendPrivateKeyP) \
|
||||
op (coin_pub, const struct TALER_CoinSpendPublicKeyP) \
|
||||
op (absolute_time, const struct GNUNET_TIME_Absolute) \
|
||||
|
@ -659,36 +659,4 @@ TALER_JSON_spec_i18n_str (const char *name,
|
||||
}
|
||||
|
||||
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_JSON_parse_agemask (const json_t *root,
|
||||
struct TALER_AgeMask *mask)
|
||||
{
|
||||
const char *name;
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_string ("extension",
|
||||
&name),
|
||||
GNUNET_JSON_spec_uint32 ("mask",
|
||||
&mask->mask),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
|
||||
if (GNUNET_OK != GNUNET_JSON_parse (root,
|
||||
spec,
|
||||
NULL,
|
||||
NULL))
|
||||
{
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
if (! strncmp (name,
|
||||
"age_restriction",
|
||||
sizeof("age_restriction")))
|
||||
{
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/* end of json/json_helper.c */
|
||||
|
@ -482,6 +482,7 @@ TALER_EXCHANGE_verify_coin_history (
|
||||
struct TALER_MerchantPublicKeyP merchant_pub;
|
||||
struct GNUNET_TIME_Timestamp refund_deadline = {0};
|
||||
struct TALER_CoinSpendSignatureP sig;
|
||||
struct TALER_AgeCommitmentHash *hac = NULL;
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_fixed_auto ("coin_sig",
|
||||
&sig),
|
||||
@ -516,6 +517,7 @@ TALER_EXCHANGE_verify_coin_history (
|
||||
&fee,
|
||||
&h_wire,
|
||||
&h_contract_terms,
|
||||
hac,
|
||||
NULL /* h_extensions! */,
|
||||
h_denom_pub,
|
||||
wallet_timestamp,
|
||||
@ -548,6 +550,7 @@ TALER_EXCHANGE_verify_coin_history (
|
||||
{
|
||||
struct TALER_CoinSpendSignatureP sig;
|
||||
struct TALER_RefreshCommitmentP rc;
|
||||
struct TALER_AgeCommitmentHash h_age_commitment = {0};
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_fixed_auto ("coin_sig",
|
||||
&sig),
|
||||
@ -555,6 +558,9 @@ TALER_EXCHANGE_verify_coin_history (
|
||||
&rc),
|
||||
GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
|
||||
h_denom_pub),
|
||||
GNUNET_JSON_spec_mark_optional (
|
||||
GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
|
||||
&h_age_commitment)),
|
||||
TALER_JSON_spec_amount_any ("melt_fee",
|
||||
&fee),
|
||||
GNUNET_JSON_spec_end ()
|
||||
@ -568,6 +574,7 @@ TALER_EXCHANGE_verify_coin_history (
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
if (NULL != dk)
|
||||
{
|
||||
/* check that melt fee matches our expectations from /keys! */
|
||||
@ -582,17 +589,26 @@ TALER_EXCHANGE_verify_coin_history (
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const struct TALER_AgeCommitmentHash *ahc = &h_age_commitment;
|
||||
|
||||
if (TALER_AgeCommitmentHash_isNullOrZero (ahc))
|
||||
ahc = NULL;
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_wallet_melt_verify (&amount,
|
||||
&fee,
|
||||
&rc,
|
||||
h_denom_pub,
|
||||
ahc,
|
||||
coin_pub,
|
||||
&sig))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
}
|
||||
add = GNUNET_YES;
|
||||
}
|
||||
else if (0 == strcasecmp (type,
|
||||
|
@ -462,6 +462,7 @@ handle_deposit_finished (void *cls,
|
||||
* @param h_wire hash of the merchant’s account details
|
||||
* @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the exchange)
|
||||
* @param coin_pub coin’s public key
|
||||
* @param h_age_commitment coin’s hash of age commitment, might be NULL
|
||||
* @param denom_sig exchange’s unblinded signature of the coin
|
||||
* @param denom_pub denomination key with which the coin is signed
|
||||
* @param denom_pub_hash hash of @a denom_pub
|
||||
@ -478,6 +479,7 @@ verify_signatures (const struct TALER_EXCHANGE_DenomPublicKey *dki,
|
||||
const struct TALER_PrivateContractHash *h_contract_terms,
|
||||
const struct TALER_ExtensionContractHash *ech,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_AgeCommitmentHash *h_age_commitment,
|
||||
const struct TALER_DenominationSignature *denom_sig,
|
||||
const struct TALER_DenominationPublicKey *denom_pub,
|
||||
const struct TALER_DenominationHash *denom_pub_hash,
|
||||
@ -491,6 +493,7 @@ verify_signatures (const struct TALER_EXCHANGE_DenomPublicKey *dki,
|
||||
&dki->fee_deposit,
|
||||
h_wire,
|
||||
h_contract_terms,
|
||||
h_age_commitment,
|
||||
ech,
|
||||
denom_pub_hash,
|
||||
timestamp,
|
||||
@ -514,8 +517,12 @@ verify_signatures (const struct TALER_EXCHANGE_DenomPublicKey *dki,
|
||||
.coin_pub = *coin_pub,
|
||||
.denom_pub_hash = *denom_pub_hash,
|
||||
.denom_sig = *denom_sig,
|
||||
.age_commitment_hash = {{{0}}} /* FIXME-Oec */
|
||||
.age_commitment_hash = {{{0}}}
|
||||
};
|
||||
if (NULL != h_age_commitment)
|
||||
{
|
||||
coin_info.age_commitment_hash = *h_age_commitment;
|
||||
}
|
||||
|
||||
if (GNUNET_YES !=
|
||||
TALER_test_coin_valid (&coin_info,
|
||||
@ -547,6 +554,7 @@ TALER_EXCHANGE_deposit (
|
||||
const char *merchant_payto_uri,
|
||||
const struct TALER_WireSalt *wire_salt,
|
||||
const struct TALER_PrivateContractHash *h_contract_terms,
|
||||
const struct TALER_AgeCommitmentHash *h_age_commitment,
|
||||
const json_t *extension_details,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_DenominationSignature *denom_sig,
|
||||
@ -599,11 +607,14 @@ TALER_EXCHANGE_deposit (
|
||||
}
|
||||
GNUNET_assert (GNUNET_YES ==
|
||||
TEAH_handle_is_ready (exchange));
|
||||
|
||||
/* initialize h_wire */
|
||||
TALER_merchant_wire_signature_hash (merchant_payto_uri,
|
||||
wire_salt,
|
||||
&h_wire);
|
||||
|
||||
key_state = TALER_EXCHANGE_get_keys (exchange);
|
||||
|
||||
dki = TALER_EXCHANGE_get_denomination_key (key_state,
|
||||
denom_pub);
|
||||
if (NULL == dki)
|
||||
@ -612,6 +623,7 @@ TALER_EXCHANGE_deposit (
|
||||
GNUNET_break_op (0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (0 >
|
||||
TALER_amount_subtract (&amount_without_fee,
|
||||
amount,
|
||||
@ -621,17 +633,18 @@ TALER_EXCHANGE_deposit (
|
||||
GNUNET_break_op (0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TALER_denom_pub_hash (denom_pub,
|
||||
&denom_pub_hash);
|
||||
|
||||
if (GNUNET_OK !=
|
||||
verify_signatures (dki,
|
||||
amount,
|
||||
&h_wire,
|
||||
h_contract_terms,
|
||||
(NULL != extension_details)
|
||||
? &ech
|
||||
: NULL,
|
||||
(NULL != extension_details) ? &ech : NULL,
|
||||
coin_pub,
|
||||
h_age_commitment,
|
||||
denom_sig,
|
||||
denom_pub,
|
||||
&denom_pub_hash,
|
||||
@ -654,6 +667,9 @@ TALER_EXCHANGE_deposit (
|
||||
wire_salt),
|
||||
GNUNET_JSON_pack_data_auto ("h_contract_terms",
|
||||
h_contract_terms),
|
||||
GNUNET_JSON_pack_allow_null (
|
||||
GNUNET_JSON_pack_data_auto ("h_age_commitment",
|
||||
h_age_commitment)),
|
||||
GNUNET_JSON_pack_data_auto ("denom_pub_hash",
|
||||
&denom_pub_hash),
|
||||
TALER_JSON_pack_denom_sig ("ub_sig",
|
||||
|
@ -667,7 +667,9 @@ decode_keys_json (const json_t *resp_obj,
|
||||
enum TALER_EXCHANGE_VersionCompatibility *vc)
|
||||
{
|
||||
struct TALER_ExchangeSignatureP sig;
|
||||
struct GNUNET_HashContext *hash_context;
|
||||
struct GNUNET_HashContext *hash_context = NULL;
|
||||
struct GNUNET_HashContext *hash_context_restricted = NULL;
|
||||
bool have_age_restricted_denom = false;
|
||||
struct TALER_ExchangePublicKeyP pub;
|
||||
const char *currency;
|
||||
struct GNUNET_JSON_Specification mspec[] = {
|
||||
@ -746,7 +748,6 @@ decode_keys_json (const json_t *resp_obj,
|
||||
key_data->version = GNUNET_strdup (ver);
|
||||
}
|
||||
|
||||
hash_context = NULL;
|
||||
EXITIF (GNUNET_OK !=
|
||||
GNUNET_JSON_parse (resp_obj,
|
||||
(check_sig) ? mspec : &mspec[2],
|
||||
@ -766,7 +767,10 @@ decode_keys_json (const json_t *resp_obj,
|
||||
|
||||
/* parse the master public key and issue date of the response */
|
||||
if (check_sig)
|
||||
{
|
||||
hash_context = GNUNET_CRYPTO_hash_context_start ();
|
||||
hash_context_restricted = GNUNET_CRYPTO_hash_context_start ();
|
||||
}
|
||||
|
||||
/* parse the signing keys */
|
||||
{
|
||||
@ -829,6 +833,9 @@ decode_keys_json (const json_t *resp_obj,
|
||||
EXITIF (GNUNET_OK !=
|
||||
TALER_extensions_load_json_config (extensions));
|
||||
}
|
||||
|
||||
/* 4. assuming we might have now a new value for age_mask, set it in key_data */
|
||||
key_data->age_mask = TALER_extensions_age_restriction_ageMask ();
|
||||
}
|
||||
|
||||
/* parse the denomination keys, merging with the
|
||||
@ -839,9 +846,15 @@ decode_keys_json (const json_t *resp_obj,
|
||||
*/
|
||||
struct
|
||||
{ char *name;
|
||||
bool is_optional_age_restriction;} hive[2] = {
|
||||
{ "denoms", false },
|
||||
{ "age_restricted_denoms", true },
|
||||
struct GNUNET_HashContext *hc;
|
||||
bool is_optional_age_restriction;}
|
||||
hive[2] = {
|
||||
{ "denoms",
|
||||
hash_context,
|
||||
false },
|
||||
{ "age_restricted_denoms",
|
||||
hash_context_restricted,
|
||||
true }
|
||||
};
|
||||
|
||||
for (size_t s = 0; s < sizeof(hive) / sizeof(hive[0]); s++)
|
||||
@ -853,25 +866,19 @@ decode_keys_json (const json_t *resp_obj,
|
||||
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)
|
||||
if (NULL == denom_keys_array)
|
||||
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;
|
||||
|
||||
/* mark that we have at least one age restricted denomination, needed
|
||||
* for the hash calculation and signature verification below. */
|
||||
have_age_restricted_denom |= hive[s].is_optional_age_restriction;
|
||||
|
||||
memset (&dk,
|
||||
0,
|
||||
sizeof (dk));
|
||||
@ -880,12 +887,7 @@ decode_keys_json (const json_t *resp_obj,
|
||||
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;
|
||||
hive[s].hc));
|
||||
|
||||
for (unsigned int j = 0;
|
||||
j<key_data->num_denom_keys;
|
||||
@ -1044,6 +1046,18 @@ decode_keys_json (const json_t *resp_obj,
|
||||
.list_issue_date = GNUNET_TIME_timestamp_hton (key_data->list_issue_date)
|
||||
};
|
||||
|
||||
/* If we had any age restricted denominations, add their hash to the end of
|
||||
* the normal denominations. */
|
||||
if (have_age_restricted_denom)
|
||||
{
|
||||
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,
|
||||
&ks.hc);
|
||||
hash_context = NULL;
|
||||
|
@ -105,6 +105,7 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,
|
||||
};
|
||||
struct TALER_TransferSecretP secret;
|
||||
struct TALER_PlanchetSecretsP fc;
|
||||
struct TALER_AgeCommitmentHash h_age_commitment = {0}; // TODO, see below.
|
||||
|
||||
/* parse reply */
|
||||
if (GNUNET_OK !=
|
||||
@ -145,6 +146,7 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,
|
||||
if (GNUNET_OK !=
|
||||
TALER_planchet_prepare (&rpub,
|
||||
&fc,
|
||||
NULL, /* FIXME-oec. struct TALER_AgeCommitmentHash * */
|
||||
&c_hash,
|
||||
&pd))
|
||||
{
|
||||
@ -156,11 +158,21 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,
|
||||
pd.coin_ev_size,
|
||||
&coin_envelope_hash.hash);
|
||||
|
||||
/*
|
||||
* TODO-oec: Derive the age commitment vector and hash it into
|
||||
* h_age_commitment.
|
||||
* Questions:
|
||||
* - Where do we get the information about the support for age
|
||||
* restriction of the denomination?
|
||||
* - Where do we get the information bout the previous coin's age groups?
|
||||
*/
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_wallet_link_verify (&pd.denom_pub_hash,
|
||||
trans_pub,
|
||||
&coin_envelope_hash,
|
||||
&old_coin_pub,
|
||||
&h_age_commitment,
|
||||
&link_sig))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
|
@ -32,7 +32,7 @@
|
||||
/**
|
||||
* Set to 1 for extra debug logging.
|
||||
*/
|
||||
#define DEBUG 0
|
||||
#define DEBUG 1 /* FIXME-oec */
|
||||
|
||||
|
||||
/**
|
||||
|
@ -151,7 +151,7 @@ TALER_EXCHANGE_management_post_extensions (
|
||||
body = GNUNET_JSON_PACK (
|
||||
GNUNET_JSON_pack_object_steal ("extensions",
|
||||
ped->extensions),
|
||||
GNUNET_JSON_pack_data_auto ("extensions_sigs",
|
||||
GNUNET_JSON_pack_data_auto ("extensions_sig",
|
||||
&ped->extensions_sig));
|
||||
|
||||
eh = curl_easy_init ();
|
||||
@ -168,7 +168,7 @@ TALER_EXCHANGE_management_post_extensions (
|
||||
return NULL;
|
||||
}
|
||||
json_decref (body);
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Requesting URL '%s'\n",
|
||||
ph->url);
|
||||
GNUNET_assert (CURLE_OK == curl_easy_setopt (eh,
|
||||
|
@ -79,6 +79,8 @@ serialize_melted_coin (const struct MeltedCoin *mc)
|
||||
return GNUNET_JSON_PACK (
|
||||
GNUNET_JSON_pack_data_auto ("coin_priv",
|
||||
&mc->coin_priv),
|
||||
GNUNET_JSON_pack_data_auto ("h_age_commitment",
|
||||
&mc->h_age_commitment),
|
||||
TALER_JSON_pack_denom_sig ("denom_sig",
|
||||
&mc->sig),
|
||||
TALER_JSON_pack_denom_pub ("denom_pub",
|
||||
@ -113,6 +115,9 @@ deserialize_melted_coin (struct MeltedCoin *mc,
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_fixed_auto ("coin_priv",
|
||||
&mc->coin_priv),
|
||||
GNUNET_JSON_spec_mark_optional (
|
||||
GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
|
||||
&mc->h_age_commitment)),
|
||||
TALER_JSON_spec_denom_sig ("denom_sig",
|
||||
&mc->sig),
|
||||
TALER_JSON_spec_denom_pub ("denom_pub",
|
||||
@ -343,12 +348,14 @@ TALER_EXCHANGE_refresh_prepare (
|
||||
const struct TALER_Amount *melt_amount,
|
||||
const struct TALER_DenominationSignature *melt_sig,
|
||||
const struct TALER_EXCHANGE_DenomPublicKey *melt_pk,
|
||||
const struct TALER_AgeCommitment *age_commitment,
|
||||
unsigned int fresh_pks_len,
|
||||
const struct TALER_EXCHANGE_DenomPublicKey *fresh_pks)
|
||||
{
|
||||
struct MeltData md;
|
||||
json_t *ret;
|
||||
struct TALER_Amount total;
|
||||
struct TALER_AgeCommitmentHash ach = {0};
|
||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||
struct TALER_TransferSecretP trans_sec[TALER_CNC_KAPPA];
|
||||
struct TALER_RefreshCommitmentEntry rce[TALER_CNC_KAPPA];
|
||||
@ -366,6 +373,10 @@ TALER_EXCHANGE_refresh_prepare (
|
||||
md.melted_coin.original_value = melt_pk->value;
|
||||
md.melted_coin.expire_deposit
|
||||
= melt_pk->expire_deposit;
|
||||
md.melted_coin.h_age_commitment = ach;
|
||||
TALER_age_commitment_hash (age_commitment,
|
||||
&md.melted_coin.h_age_commitment);
|
||||
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_amount_set_zero (melt_amount->currency,
|
||||
&total));
|
||||
@ -375,6 +386,7 @@ TALER_EXCHANGE_refresh_prepare (
|
||||
melt_sig);
|
||||
md.fresh_pks = GNUNET_new_array (fresh_pks_len,
|
||||
struct TALER_DenominationPublicKey);
|
||||
|
||||
for (unsigned int i = 0; i<fresh_pks_len; i++)
|
||||
{
|
||||
TALER_denom_pub_deep_copy (&md.fresh_pks[i],
|
||||
@ -393,6 +405,7 @@ TALER_EXCHANGE_refresh_prepare (
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* verify that melt_amount is above total cost */
|
||||
if (1 ==
|
||||
TALER_amount_cmp (&total,
|
||||
@ -416,23 +429,62 @@ TALER_EXCHANGE_refresh_prepare (
|
||||
TALER_link_derive_transfer_secret (melt_priv,
|
||||
&md.melted_coin.transfer_priv[i],
|
||||
&trans_sec[i]);
|
||||
|
||||
md.fresh_coins[i] = GNUNET_new_array (fresh_pks_len,
|
||||
struct TALER_PlanchetSecretsP);
|
||||
|
||||
rce[i].new_coins = GNUNET_new_array (fresh_pks_len,
|
||||
struct TALER_RefreshCoinData);
|
||||
|
||||
md.fresh_ach[i] = GNUNET_new_array (fresh_pks_len,
|
||||
struct TALER_AgeCommitmentHash);
|
||||
|
||||
for (unsigned int j = 0; j<fresh_pks_len; j++)
|
||||
{
|
||||
struct TALER_PlanchetSecretsP *fc = &md.fresh_coins[i][j];
|
||||
struct TALER_RefreshCoinData *rcd = &rce[i].new_coins[j];
|
||||
struct TALER_AgeCommitmentHash *ach = &md.fresh_ach[i][j];
|
||||
struct TALER_PlanchetDetail pd;
|
||||
struct TALER_CoinPubHash c_hash;
|
||||
|
||||
|
||||
/* Handle age commitment, if present */
|
||||
if (NULL == age_commitment)
|
||||
{
|
||||
memset (ach, 0, sizeof(struct TALER_AgeCommitmentHash));
|
||||
ach = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct TALER_AgeCommitment new_ac;
|
||||
uint32_t seed;
|
||||
|
||||
/* we use the first 4 bytes of the trans_sec to generate a new age
|
||||
* commitment */
|
||||
seed = *(uint32_t *) trans_sec[i].key.bits;
|
||||
|
||||
if (GNUNET_OK != TALER_age_commitment_derive (
|
||||
age_commitment,
|
||||
seed,
|
||||
&new_ac))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
TALER_EXCHANGE_free_melt_data_ (&md);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TALER_age_commitment_hash (
|
||||
&new_ac,
|
||||
&md.fresh_ach[i][j]);
|
||||
}
|
||||
|
||||
TALER_planchet_setup_refresh (&trans_sec[i],
|
||||
j,
|
||||
fc);
|
||||
if (GNUNET_OK !=
|
||||
TALER_planchet_prepare (&md.fresh_pks[j],
|
||||
fc,
|
||||
ach,
|
||||
&c_hash,
|
||||
&pd))
|
||||
{
|
||||
@ -453,6 +505,7 @@ TALER_EXCHANGE_refresh_prepare (
|
||||
rce,
|
||||
&coin_pub,
|
||||
melt_amount);
|
||||
|
||||
/* finally, serialize everything */
|
||||
ret = serialize_melt_data (&md);
|
||||
for (unsigned int i = 0; i < TALER_CNC_KAPPA; i++)
|
||||
@ -461,6 +514,7 @@ TALER_EXCHANGE_refresh_prepare (
|
||||
GNUNET_free (rce[i].new_coins[j].coin_ev);
|
||||
GNUNET_free (rce[i].new_coins);
|
||||
}
|
||||
|
||||
TALER_EXCHANGE_free_melt_data_ (&md);
|
||||
return ret;
|
||||
}
|
||||
|
@ -52,6 +52,12 @@ struct MeltedCoin
|
||||
*/
|
||||
struct TALER_Amount original_value;
|
||||
|
||||
/**
|
||||
* The original age commitment hash. MUST be all zeroes, if no age
|
||||
* commitment was set.
|
||||
*/
|
||||
struct TALER_AgeCommitmentHash h_age_commitment;
|
||||
|
||||
/**
|
||||
* Transfer private keys for each cut-and-choose dimension.
|
||||
*/
|
||||
@ -107,6 +113,14 @@ struct MeltData
|
||||
* coins to be created, for each cut-and-choose dimension.
|
||||
*/
|
||||
struct TALER_PlanchetSecretsP *fresh_coins[TALER_CNC_KAPPA];
|
||||
|
||||
/**
|
||||
* Arrays of @e num_fresh_coins with information about the hashes of age
|
||||
* commitments coins to be created, for each cut-and-choose dimension. The
|
||||
* entries in each list might be NULL and indicate no age
|
||||
* commitment/restriction on the particular coin.
|
||||
*/
|
||||
struct TALER_AgeCommitmentHash *fresh_ach[TALER_CNC_KAPPA];
|
||||
};
|
||||
|
||||
|
||||
|
@ -136,6 +136,7 @@ refresh_reveal_ok (struct TALER_EXCHANGE_RefreshesRevealHandle *rrh,
|
||||
{
|
||||
const struct TALER_PlanchetSecretsP *fc;
|
||||
struct TALER_DenominationPublicKey *pk;
|
||||
struct TALER_AgeCommitmentHash *ach = NULL;
|
||||
json_t *jsonai;
|
||||
struct TALER_BlindedDenominationSignature blind_sig;
|
||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||
@ -152,6 +153,12 @@ refresh_reveal_ok (struct TALER_EXCHANGE_RefreshesRevealHandle *rrh,
|
||||
jsonai = json_array_get (jsona, i);
|
||||
GNUNET_assert (NULL != jsonai);
|
||||
|
||||
if (! TALER_AgeCommitmentHash_isNullOrZero (
|
||||
&rrh->md->melted_coin.h_age_commitment))
|
||||
{
|
||||
ach = &rrh->md->fresh_ach[rrh->noreveal_index][i];
|
||||
}
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_JSON_parse (jsonai,
|
||||
spec,
|
||||
@ -166,14 +173,14 @@ refresh_reveal_ok (struct TALER_EXCHANGE_RefreshesRevealHandle *rrh,
|
||||
hence recomputing it here... */
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
|
||||
&coin_pub.eddsa_pub);
|
||||
/* FIXME-Oec: Age commitment hash. */
|
||||
TALER_coin_pub_hash (&coin_pub,
|
||||
NULL, /* FIXME-Oec */
|
||||
ach,
|
||||
&coin_hash);
|
||||
if (GNUNET_OK !=
|
||||
TALER_planchet_to_coin (pk,
|
||||
&blind_sig,
|
||||
fc,
|
||||
ach,
|
||||
&coin_hash,
|
||||
&coin))
|
||||
{
|
||||
@ -359,6 +366,7 @@ TALER_EXCHANGE_refreshes_reveal (
|
||||
if (GNUNET_OK !=
|
||||
TALER_planchet_prepare (&md->fresh_pks[i],
|
||||
&md->fresh_coins[noreveal_index][i],
|
||||
NULL, /* FIXME-oec */
|
||||
&c_hash,
|
||||
&pd))
|
||||
{
|
||||
|
@ -203,6 +203,7 @@ verify_conflict_history_ok (struct TALER_EXCHANGE_RefundHandle *rh,
|
||||
struct TALER_Amount deposit_fee;
|
||||
struct TALER_MerchantWireHash h_wire;
|
||||
struct TALER_PrivateContractHash h_contract_terms;
|
||||
struct TALER_AgeCommitmentHash h_age_commitment = {{{0}}};
|
||||
// struct TALER_ExtensionContractHash h_extensions; // FIXME!
|
||||
struct TALER_DenominationHash h_denom_pub;
|
||||
struct GNUNET_TIME_Timestamp wallet_timestamp;
|
||||
@ -218,6 +219,9 @@ verify_conflict_history_ok (struct TALER_EXCHANGE_RefundHandle *rh,
|
||||
&h_wire),
|
||||
GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
|
||||
&h_denom_pub),
|
||||
GNUNET_JSON_spec_mark_optional (
|
||||
GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
|
||||
&h_age_commitment)),
|
||||
GNUNET_JSON_spec_timestamp ("timestamp",
|
||||
&wallet_timestamp),
|
||||
GNUNET_JSON_spec_timestamp ("refund_deadline",
|
||||
@ -243,6 +247,7 @@ verify_conflict_history_ok (struct TALER_EXCHANGE_RefundHandle *rh,
|
||||
&deposit_fee,
|
||||
&h_wire,
|
||||
&h_contract_terms,
|
||||
&h_age_commitment,
|
||||
NULL /* h_extensions! */,
|
||||
&h_denom_pub,
|
||||
wallet_timestamp,
|
||||
|
@ -63,6 +63,11 @@ struct TALER_EXCHANGE_WithdrawHandle
|
||||
*/
|
||||
struct TALER_PlanchetSecretsP ps;
|
||||
|
||||
/**
|
||||
* Hash of the age commitment for this coin, if applicable. Maybe NULL
|
||||
*/
|
||||
const struct TALER_AgeCommitmentHash *ach;
|
||||
|
||||
/**
|
||||
* Denomination key we are withdrawing.
|
||||
*/
|
||||
@ -106,6 +111,7 @@ handle_reserve_withdraw_finished (
|
||||
TALER_planchet_to_coin (&wh->pk.key,
|
||||
blind_sig,
|
||||
&wh->ps,
|
||||
wh->ach,
|
||||
&wh->c_hash,
|
||||
&fc))
|
||||
{
|
||||
@ -159,6 +165,7 @@ handle_reserve_withdraw_finished (
|
||||
* @param reserve_priv private key of the reserve to withdraw from
|
||||
* @param ps secrets of the planchet
|
||||
* caller must have committed this value to disk before the call (with @a pk)
|
||||
* @param ach (optional) hash of the age commitment that should be bound to this coin. Maybe NULL.
|
||||
* @param res_cb the callback to call when the final result for this request is available
|
||||
* @param res_cb_cls closure for the above callback
|
||||
* @return handle for the operation on success, NULL on error, i.e.
|
||||
@ -171,11 +178,13 @@ TALER_EXCHANGE_withdraw (
|
||||
const struct TALER_EXCHANGE_DenomPublicKey *pk,
|
||||
const struct TALER_ReservePrivateKeyP *reserve_priv,
|
||||
const struct TALER_PlanchetSecretsP *ps,
|
||||
const struct TALER_AgeCommitmentHash *ach,
|
||||
TALER_EXCHANGE_WithdrawCallback res_cb,
|
||||
void *res_cb_cls)
|
||||
{
|
||||
struct TALER_PlanchetDetail pd;
|
||||
struct TALER_EXCHANGE_WithdrawHandle *wh;
|
||||
bool age_restricted = (0 != pk->key.age_mask.mask);
|
||||
|
||||
wh = GNUNET_new (struct TALER_EXCHANGE_WithdrawHandle);
|
||||
wh->exchange = exchange;
|
||||
@ -183,9 +192,14 @@ TALER_EXCHANGE_withdraw (
|
||||
wh->cb_cls = res_cb_cls;
|
||||
wh->pk = *pk;
|
||||
wh->ps = *ps;
|
||||
wh->ach = ach;
|
||||
|
||||
GNUNET_assert (age_restricted == (NULL != ach));
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_planchet_prepare (&pk->key,
|
||||
ps,
|
||||
ach,
|
||||
&wh->c_hash,
|
||||
&pd))
|
||||
{
|
||||
|
@ -68,6 +68,7 @@ libtalertesting_la_SOURCES = \
|
||||
testing_api_cmd_oauth.c \
|
||||
testing_api_cmd_offline_sign_fees.c \
|
||||
testing_api_cmd_offline_sign_keys.c \
|
||||
testing_api_cmd_offline_sign_extensions.c \
|
||||
testing_api_cmd_set_wire_fee.c \
|
||||
testing_api_cmd_recoup.c \
|
||||
testing_api_cmd_recoup_refresh.c \
|
||||
@ -208,6 +209,7 @@ test_exchange_api_LDADD = \
|
||||
-lgnunetcurl \
|
||||
-lgnunetutil \
|
||||
-ljansson \
|
||||
-ltalerextensions \
|
||||
$(XLIB)
|
||||
|
||||
test_exchange_management_api_SOURCES = \
|
||||
|
@ -128,6 +128,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1",
|
||||
"create-reserve-1",
|
||||
"EUR:5",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_end ()
|
||||
};
|
||||
@ -168,6 +169,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("refresh-withdraw-coin-1",
|
||||
"refresh-create-reserve-1",
|
||||
"EUR:5",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
/**
|
||||
* Try to partially spend (deposit) 1 EUR of the 5 EUR coin (in
|
||||
@ -315,6 +317,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-unaggregated",
|
||||
"create-reserve-unaggregated",
|
||||
"EUR:5",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_deposit ("deposit-unaggregated",
|
||||
"withdraw-coin-unaggregated",
|
||||
@ -347,6 +350,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-r1",
|
||||
"create-reserve-r1",
|
||||
"EUR:5",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
/**
|
||||
* Spend 5 EUR of the 5 EUR coin (in full). Merchant would
|
||||
@ -402,6 +406,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-1",
|
||||
"recoup-create-reserve-1",
|
||||
"EUR:5",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_revoke ("revoke-1",
|
||||
MHD_HTTP_OK,
|
||||
@ -417,6 +422,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2",
|
||||
"recoup-create-reserve-1",
|
||||
"EUR:1",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
/**
|
||||
* These commands should close the reserve because the aggregator
|
||||
@ -447,6 +453,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2a",
|
||||
"recoup-create-reserve-2",
|
||||
"EUR:1",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
/**
|
||||
* Withdraw a 1 EUR coin, at fee of 1 ct
|
||||
@ -454,6 +461,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2b",
|
||||
"recoup-create-reserve-2",
|
||||
"EUR:1",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_deposit ("recoup-deposit-partial",
|
||||
"recoup-withdraw-coin-2a",
|
||||
@ -491,42 +499,52 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-1",
|
||||
"massive-reserve",
|
||||
"EUR:1",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-2",
|
||||
"massive-reserve",
|
||||
"EUR:1",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-3",
|
||||
"massive-reserve",
|
||||
"EUR:1",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-4",
|
||||
"massive-reserve",
|
||||
"EUR:1",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-5",
|
||||
"massive-reserve",
|
||||
"EUR:1",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-6",
|
||||
"massive-reserve",
|
||||
"EUR:1",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-7",
|
||||
"massive-reserve",
|
||||
"EUR:1",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-8",
|
||||
"massive-reserve",
|
||||
"EUR:1",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-9",
|
||||
"massive-reserve",
|
||||
"EUR:1",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-10",
|
||||
"massive-reserve",
|
||||
"EUR:1",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_deposit (
|
||||
"massive-deposit-1",
|
||||
@ -708,7 +726,7 @@ main (int argc,
|
||||
GNUNET_break (0);
|
||||
return 1;
|
||||
case GNUNET_NO:
|
||||
return 77;
|
||||
return 78;
|
||||
case GNUNET_OK:
|
||||
if (GNUNET_OK !=
|
||||
/* Set up event loop and reschedule context, plus
|
||||
@ -718,11 +736,11 @@ main (int argc,
|
||||
TALER_TESTING_auditor_setup (&run,
|
||||
NULL,
|
||||
CONFIG_FILE))
|
||||
return 1;
|
||||
return 2;
|
||||
break;
|
||||
default:
|
||||
GNUNET_break (0);
|
||||
return 1;
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "taler_bank_service.h"
|
||||
#include "taler_fakebank_lib.h"
|
||||
#include "taler_testing_lib.h"
|
||||
#include "taler_extensions.h"
|
||||
|
||||
/**
|
||||
* Configuration file we use. One (big) configuration is used
|
||||
@ -138,6 +139,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1",
|
||||
"create-reserve-1",
|
||||
"EUR:5",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
/**
|
||||
* Withdraw EUR:1 using the SAME private coin key as for the previous coin
|
||||
@ -146,6 +148,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount_reuse_key ("withdraw-coin-1x",
|
||||
"create-reserve-1",
|
||||
"EUR:1",
|
||||
0, /* age restriction off */
|
||||
"withdraw-coin-1",
|
||||
MHD_HTTP_OK),
|
||||
/**
|
||||
@ -161,6 +164,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-2",
|
||||
"create-reserve-1",
|
||||
"EUR:5",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_CONFLICT),
|
||||
TALER_TESTING_cmd_end ()
|
||||
};
|
||||
@ -254,6 +258,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("refresh-withdraw-coin-1",
|
||||
"refresh-create-reserve-1",
|
||||
"EUR:5",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
/* Try to partially spend (deposit) 1 EUR of the 5 EUR coin
|
||||
* (in full) (merchant would receive EUR:0.99 due to 1 ct
|
||||
@ -330,6 +335,61 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_end ()
|
||||
};
|
||||
|
||||
/**
|
||||
* Test withdrawal with age restriction. Success is expected, so it MUST be
|
||||
* called _after_ TALER_TESTING_cmd_exec_offline_sign_extensions is called,
|
||||
* i. e. age restriction is activated in the exchange!
|
||||
*
|
||||
* TODO: create a test that tries to withdraw coins with age restriction but
|
||||
* (expectedly) fails because the exchange doesn't support age restriction
|
||||
* yet.
|
||||
*/
|
||||
struct TALER_TESTING_Command withdraw_age[] = {
|
||||
/**
|
||||
* Move money to the exchange's bank account.
|
||||
*/
|
||||
CMD_TRANSFER_TO_EXCHANGE ("create-reserve-age",
|
||||
"EUR:5.02"),
|
||||
TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-age",
|
||||
"EUR:5.02",
|
||||
bc.user42_payto,
|
||||
bc.exchange_payto,
|
||||
"create-reserve-age"),
|
||||
/**
|
||||
* Make a reserve exist, according to the previous
|
||||
* transfer.
|
||||
*/
|
||||
CMD_EXEC_WIREWATCH ("wirewatch-age"),
|
||||
/**
|
||||
* Withdraw EUR:5.
|
||||
*/
|
||||
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-age-1",
|
||||
"create-reserve-age",
|
||||
"EUR:5",
|
||||
13,
|
||||
MHD_HTTP_OK),
|
||||
|
||||
TALER_TESTING_cmd_end ()
|
||||
};
|
||||
|
||||
struct TALER_TESTING_Command spend_age[] = {
|
||||
/**
|
||||
* Spend the coin.
|
||||
*/
|
||||
TALER_TESTING_cmd_deposit ("deposit-simple-age",
|
||||
"withdraw-coin-age-1",
|
||||
0,
|
||||
bc.user42_payto,
|
||||
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
|
||||
GNUNET_TIME_UNIT_ZERO,
|
||||
"EUR:5",
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_deposit_replay ("deposit-simple-replay-age",
|
||||
"deposit-simple-age",
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_end ()
|
||||
};
|
||||
|
||||
struct TALER_TESTING_Command track[] = {
|
||||
/* Try resolving a deposit's WTID, as we never triggered
|
||||
* execution of transactions, the answer should be that
|
||||
@ -372,6 +432,11 @@ run (void *cls,
|
||||
"EUR:4.98",
|
||||
bc.exchange_payto,
|
||||
bc.user42_payto),
|
||||
TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-499c2",
|
||||
ec.exchange_url,
|
||||
"EUR:4.98",
|
||||
bc.exchange_payto,
|
||||
bc.user42_payto),
|
||||
TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c1",
|
||||
ec.exchange_url,
|
||||
"EUR:0.98",
|
||||
@ -426,6 +491,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-unaggregated",
|
||||
"create-reserve-unaggregated",
|
||||
"EUR:5",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_deposit ("deposit-unaggregated",
|
||||
"withdraw-coin-unaggregated",
|
||||
@ -464,6 +530,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-aggtest",
|
||||
"create-reserve-aggtest",
|
||||
"EUR:5",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_deposit ("deposit-aggtest-1",
|
||||
"withdraw-coin-aggtest",
|
||||
@ -512,6 +579,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-r1",
|
||||
"create-reserve-r1",
|
||||
"EUR:5",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
/**
|
||||
* Spend 5 EUR of the 5 EUR coin (in full) (merchant would
|
||||
@ -612,6 +680,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-rb",
|
||||
"create-reserve-rb",
|
||||
"EUR:5",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_deposit ("deposit-refund-1b",
|
||||
"withdraw-coin-rb",
|
||||
@ -661,11 +730,13 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-1",
|
||||
"recoup-create-reserve-1",
|
||||
"EUR:5",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
/* Withdraw a 10 EUR coin, at fee of 1 ct */
|
||||
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-1b",
|
||||
"recoup-create-reserve-1",
|
||||
"EUR:10",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
/* melt 10 EUR coin to get 5 EUR refreshed coin */
|
||||
TALER_TESTING_cmd_melt ("recoup-melt-coin-1b",
|
||||
@ -756,6 +827,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2",
|
||||
"recoup-create-reserve-1",
|
||||
"EUR:1",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
/**
|
||||
* This withdrawal will test the logic to create a "recoup"
|
||||
@ -764,6 +836,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2-over",
|
||||
"recoup-create-reserve-1",
|
||||
"EUR:10",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_CONFLICT),
|
||||
TALER_TESTING_cmd_status ("recoup-reserve-status-2",
|
||||
"recoup-create-reserve-1",
|
||||
@ -796,6 +869,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("expired-withdraw",
|
||||
"short-lived-reserve",
|
||||
"EUR:1",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_CONFLICT),
|
||||
TALER_TESTING_cmd_check_bank_transfer ("check_bank_short-lived_reimburse",
|
||||
ec.exchange_url,
|
||||
@ -820,11 +894,13 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2a",
|
||||
"recoup-create-reserve-2",
|
||||
"EUR:1",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
/* Withdraw a 1 EUR coin, at fee of 1 ct */
|
||||
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2b",
|
||||
"recoup-create-reserve-2",
|
||||
"EUR:1",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_deposit ("recoup-deposit-partial",
|
||||
"recoup-withdraw-coin-2a",
|
||||
@ -885,6 +961,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-3-revoked",
|
||||
"recoup-create-reserve-3",
|
||||
"EUR:1",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_GONE),
|
||||
/* check that we are empty before the rejection test */
|
||||
TALER_TESTING_cmd_check_bank_empty ("check-empty-again"),
|
||||
@ -931,6 +1008,8 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_auditor_add ("add-auditor-OK",
|
||||
MHD_HTTP_NO_CONTENT,
|
||||
false),
|
||||
TALER_TESTING_cmd_exec_offline_sign_extensions ("offline-sign-extensions",
|
||||
CONFIG_FILE),
|
||||
TALER_TESTING_cmd_wire_add ("add-wire-account",
|
||||
"payto://x-taler-bank/localhost/2",
|
||||
MHD_HTTP_NO_CONTENT,
|
||||
@ -951,6 +1030,10 @@ run (void *cls,
|
||||
spend),
|
||||
TALER_TESTING_cmd_batch ("refresh",
|
||||
refresh),
|
||||
TALER_TESTING_cmd_batch ("withdraw-age",
|
||||
withdraw_age),
|
||||
TALER_TESTING_cmd_batch ("spend-age",
|
||||
spend_age),
|
||||
TALER_TESTING_cmd_batch ("track",
|
||||
track),
|
||||
TALER_TESTING_cmd_batch ("unaggregation",
|
||||
@ -986,6 +1069,9 @@ main (int argc,
|
||||
GNUNET_log_setup ("test-exchange-api",
|
||||
"INFO",
|
||||
NULL);
|
||||
|
||||
TALER_extensions_init ();
|
||||
|
||||
/* Check fakebank port is available and get config */
|
||||
if (GNUNET_OK !=
|
||||
TALER_TESTING_prepare_fakebank (CONFIG_FILE,
|
||||
@ -1004,7 +1090,7 @@ main (int argc,
|
||||
GNUNET_break (0);
|
||||
return 1;
|
||||
case GNUNET_NO:
|
||||
return 77;
|
||||
return 78;
|
||||
case GNUNET_OK:
|
||||
if (GNUNET_OK !=
|
||||
/* Set up event loop and reschedule context, plus
|
||||
@ -1014,11 +1100,11 @@ main (int argc,
|
||||
TALER_TESTING_setup_with_exchange (&run,
|
||||
NULL,
|
||||
CONFIG_FILE))
|
||||
return 1;
|
||||
return 2;
|
||||
break;
|
||||
default:
|
||||
GNUNET_break (0);
|
||||
return 1;
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ fee_deposit = EUR:0.00
|
||||
fee_refresh = EUR:0.01
|
||||
fee_refund = EUR:0.01
|
||||
rsa_keysize = 1024
|
||||
age_restricted = true
|
||||
age_restricted = YES
|
||||
|
||||
[coin_eur_ct_10_age_restricted]
|
||||
value = EUR:0.10
|
||||
@ -162,7 +162,7 @@ fee_deposit = EUR:0.01
|
||||
fee_refresh = EUR:0.03
|
||||
fee_refund = EUR:0.01
|
||||
rsa_keysize = 1024
|
||||
age_restricted = true
|
||||
age_restricted = YES
|
||||
|
||||
[coin_eur_1_age_restricted]
|
||||
value = EUR:1
|
||||
@ -174,7 +174,7 @@ fee_deposit = EUR:0.01
|
||||
fee_refresh = EUR:0.03
|
||||
fee_refund = EUR:0.01
|
||||
rsa_keysize = 1024
|
||||
age_restricted = true
|
||||
age_restricted = YES
|
||||
|
||||
[coin_eur_5_age_restricted]
|
||||
value = EUR:5
|
||||
@ -186,7 +186,7 @@ fee_deposit = EUR:0.01
|
||||
fee_refresh = EUR:0.03
|
||||
fee_refund = EUR:0.01
|
||||
rsa_keysize = 1024
|
||||
age_restricted = true
|
||||
age_restricted = YES
|
||||
|
||||
[coin_eur_10_age_restricted]
|
||||
value = EUR:10
|
||||
@ -198,4 +198,4 @@ fee_deposit = EUR:0.01
|
||||
fee_refresh = EUR:0.03
|
||||
fee_refund = EUR:0.01
|
||||
rsa_keysize = 1024
|
||||
age_restricted = true
|
||||
age_restricted = YES
|
||||
|
@ -95,11 +95,13 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("withdraw-revocation-coin-1",
|
||||
"create-reserve-1",
|
||||
"EUR:5",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
/* Withdraw another 5 EUR coin, at fee of 1 ct */
|
||||
TALER_TESTING_cmd_withdraw_amount ("withdraw-revocation-coin-2",
|
||||
"create-reserve-1",
|
||||
"EUR:5",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
/* Try to partially spend (deposit) 1 EUR of the 5 EUR coin (in full)
|
||||
* (merchant would receive EUR:0.99 due to 1 ct deposit fee) *///
|
||||
|
@ -105,10 +105,12 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1-no-kyc",
|
||||
"create-reserve-1",
|
||||
"EUR:10",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_ACCEPTED),
|
||||
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1",
|
||||
"create-reserve-1",
|
||||
"EUR:5",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_end ()
|
||||
};
|
||||
@ -120,6 +122,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1-lacking-kyc",
|
||||
"create-reserve-1",
|
||||
"EUR:5",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_ACCEPTED),
|
||||
TALER_TESTING_cmd_proof_kyc ("proof-kyc",
|
||||
"withdraw-coin-1-lacking-kyc",
|
||||
@ -129,6 +132,7 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1-with-kyc",
|
||||
"create-reserve-1",
|
||||
"EUR:5",
|
||||
0, /* age restriction off */
|
||||
MHD_HTTP_OK),
|
||||
TALER_TESTING_cmd_end ()
|
||||
};
|
||||
|
@ -287,6 +287,8 @@ deposit_run (void *cls,
|
||||
const struct TALER_TESTING_Command *coin_cmd;
|
||||
const struct TALER_CoinSpendPrivateKeyP *coin_priv;
|
||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||
struct TALER_AgeCommitment *age_commitment = NULL;
|
||||
struct TALER_AgeCommitmentHash h_age_commitment = {0};
|
||||
const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
|
||||
const struct TALER_DenominationSignature *denom_pub_sig;
|
||||
struct TALER_CoinSpendSignatureP coin_sig;
|
||||
@ -382,6 +384,10 @@ deposit_run (void *cls,
|
||||
TALER_TESTING_get_trait_coin_priv (coin_cmd,
|
||||
ds->coin_index,
|
||||
&coin_priv)) ||
|
||||
(GNUNET_OK !=
|
||||
TALER_TESTING_get_trait_age_commitment (coin_cmd,
|
||||
ds->coin_index,
|
||||
&age_commitment)) ||
|
||||
(GNUNET_OK !=
|
||||
TALER_TESTING_get_trait_denom_pub (coin_cmd,
|
||||
ds->coin_index,
|
||||
@ -398,6 +404,12 @@ deposit_run (void *cls,
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
return;
|
||||
}
|
||||
|
||||
if (NULL != age_commitment)
|
||||
{
|
||||
TALER_age_commitment_hash (age_commitment, &h_age_commitment);
|
||||
}
|
||||
|
||||
ds->deposit_fee = denom_pub->fee_deposit;
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
|
||||
&coin_pub.eddsa_pub);
|
||||
@ -431,7 +443,8 @@ deposit_run (void *cls,
|
||||
&denom_pub->fee_deposit,
|
||||
&h_wire,
|
||||
&h_contract_terms,
|
||||
NULL, /* FIXME: extension hash! */
|
||||
&h_age_commitment,
|
||||
NULL, /* FIXME: add hash of extensions */
|
||||
&denom_pub->h_key,
|
||||
ds->wallet_timestamp,
|
||||
&merchant_pub,
|
||||
@ -445,7 +458,8 @@ deposit_run (void *cls,
|
||||
payto_uri,
|
||||
&wire_salt,
|
||||
&h_contract_terms,
|
||||
NULL, /* FIXME: extension object */
|
||||
&h_age_commitment,
|
||||
NULL, /* FIXME: add hash of extensions */
|
||||
&coin_pub,
|
||||
denom_pub_sig,
|
||||
&denom_pub->key,
|
||||
@ -520,6 +534,7 @@ deposit_traits (void *cls,
|
||||
const struct TALER_TESTING_Command *coin_cmd;
|
||||
/* Will point to coin cmd internals. */
|
||||
const struct TALER_CoinSpendPrivateKeyP *coin_spent_priv;
|
||||
struct TALER_AgeCommitment *age_commitment;
|
||||
|
||||
if (GNUNET_YES != ds->command_initialized)
|
||||
{
|
||||
@ -540,7 +555,11 @@ deposit_traits (void *cls,
|
||||
if (GNUNET_OK !=
|
||||
TALER_TESTING_get_trait_coin_priv (coin_cmd,
|
||||
ds->coin_index,
|
||||
&coin_spent_priv))
|
||||
&coin_spent_priv) ||
|
||||
(GNUNET_OK !=
|
||||
TALER_TESTING_get_trait_age_commitment (coin_cmd,
|
||||
ds->coin_index,
|
||||
&age_commitment)))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
TALER_TESTING_interpreter_fail (ds->is);
|
||||
@ -555,6 +574,8 @@ deposit_traits (void *cls,
|
||||
/* These traits are always available */
|
||||
TALER_TESTING_make_trait_coin_priv (0,
|
||||
coin_spent_priv),
|
||||
TALER_TESTING_make_trait_age_commitment (0,
|
||||
age_commitment),
|
||||
TALER_TESTING_make_trait_wire_details (ds->wire_details),
|
||||
TALER_TESTING_make_trait_contract_terms (ds->contract_terms),
|
||||
TALER_TESTING_make_trait_merchant_priv (&ds->merchant_priv),
|
||||
|
@ -238,7 +238,7 @@ insert_deposit_run (void *cls,
|
||||
{
|
||||
uint64_t known_coin_id;
|
||||
struct TALER_DenominationHash dph;
|
||||
struct TALER_AgeHash agh;
|
||||
struct TALER_AgeCommitmentHash agh;
|
||||
|
||||
if ( (GNUNET_OK !=
|
||||
ids->dbc->plugin->start (ids->dbc->plugin->cls,
|
||||
|
164
src/testing/testing_api_cmd_offline_sign_extensions.c
Normal file
164
src/testing/testing_api_cmd_offline_sign_extensions.c
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2022 Taler Systems SA
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published
|
||||
by the Free Software Foundation; either version 3, or (at your
|
||||
option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with TALER; see the file COPYING. If not,
|
||||
see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file testing/testing_api_cmd_offline_sign_extensions.c
|
||||
* @brief run the taler-exchange-offline command to sign extensions (and therefore activate them)
|
||||
* @author Özgür Kesim
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include <gnunet/gnunet_curl_lib.h>
|
||||
#include "taler_signatures.h"
|
||||
#include "taler_testing_lib.h"
|
||||
|
||||
|
||||
/**
|
||||
* State for a "extensionssign" CMD.
|
||||
*/
|
||||
struct ExtensionsSignState
|
||||
{
|
||||
|
||||
/**
|
||||
* Process for the "extensionssign" command.
|
||||
*/
|
||||
struct GNUNET_OS_Process *extensionssign_proc;
|
||||
|
||||
/**
|
||||
* Configuration file used by the command.
|
||||
*/
|
||||
const char *config_filename;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Run the command; calls the `taler-exchange-offline' program.
|
||||
*
|
||||
* @param cls closure.
|
||||
* @param cmd the commaind being run.
|
||||
* @param is interpreter state.
|
||||
*/
|
||||
static void
|
||||
extensionssign_run (void *cls,
|
||||
const struct TALER_TESTING_Command *cmd,
|
||||
struct TALER_TESTING_Interpreter *is)
|
||||
{
|
||||
struct ExtensionsSignState *ks = cls;
|
||||
|
||||
ks->extensionssign_proc
|
||||
= GNUNET_OS_start_process (
|
||||
GNUNET_OS_INHERIT_STD_ALL,
|
||||
NULL, NULL, NULL,
|
||||
"taler-exchange-offline",
|
||||
"taler-exchange-offline",
|
||||
"-c", ks->config_filename,
|
||||
"-L", "INFO",
|
||||
"extensions",
|
||||
"sign",
|
||||
"upload",
|
||||
NULL);
|
||||
if (NULL == ks->extensionssign_proc)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
return;
|
||||
}
|
||||
TALER_TESTING_wait_for_sigchld (is);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Free the state of a "extensionssign" CMD, and possibly kills its
|
||||
* process if it did not terminate correctly.
|
||||
*
|
||||
* @param cls closure.
|
||||
* @param cmd the command being freed.
|
||||
*/
|
||||
static void
|
||||
extensionssign_cleanup (void *cls,
|
||||
const struct TALER_TESTING_Command *cmd)
|
||||
{
|
||||
struct ExtensionsSignState *ks = cls;
|
||||
|
||||
(void) cmd;
|
||||
if (NULL != ks->extensionssign_proc)
|
||||
{
|
||||
GNUNET_break (0 ==
|
||||
GNUNET_OS_process_kill (ks->extensionssign_proc,
|
||||
SIGKILL));
|
||||
GNUNET_OS_process_wait (ks->extensionssign_proc);
|
||||
GNUNET_OS_process_destroy (ks->extensionssign_proc);
|
||||
ks->extensionssign_proc = NULL;
|
||||
}
|
||||
GNUNET_free (ks);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Offer "extensionssign" CMD internal data to other commands.
|
||||
*
|
||||
* @param cls closure.
|
||||
* @param[out] ret result
|
||||
* @param trait name of the trait.
|
||||
* @param index index number of the object to offer.
|
||||
* @return #GNUNET_OK on success.
|
||||
*/
|
||||
static enum GNUNET_GenericReturnValue
|
||||
extensionssign_traits (void *cls,
|
||||
const void **ret,
|
||||
const char *trait,
|
||||
unsigned int index)
|
||||
{
|
||||
struct ExtensionsSignState *ks = cls;
|
||||
struct TALER_TESTING_Trait traits[] = {
|
||||
TALER_TESTING_make_trait_process (&ks->extensionssign_proc),
|
||||
TALER_TESTING_trait_end ()
|
||||
};
|
||||
|
||||
return TALER_TESTING_get_trait (traits,
|
||||
ret,
|
||||
trait,
|
||||
index);
|
||||
}
|
||||
|
||||
|
||||
struct TALER_TESTING_Command
|
||||
TALER_TESTING_cmd_exec_offline_sign_extensions (const char *label,
|
||||
const char *config_filename)
|
||||
{
|
||||
struct ExtensionsSignState *ks;
|
||||
|
||||
ks = GNUNET_new (struct ExtensionsSignState);
|
||||
ks->config_filename = config_filename;
|
||||
{
|
||||
struct TALER_TESTING_Command cmd = {
|
||||
.cls = ks,
|
||||
.label = label,
|
||||
.run = &extensionssign_run,
|
||||
.cleanup = &extensionssign_cleanup,
|
||||
.traits = &extensionssign_traits
|
||||
};
|
||||
|
||||
return cmd;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* end of testing_api_cmd_exec_offline_sign_extensions.c */
|
@ -70,6 +70,11 @@ struct TALER_TESTING_FreshCoinData
|
||||
*/
|
||||
struct TALER_CoinSpendPrivateKeyP coin_priv;
|
||||
|
||||
/*
|
||||
* Age commitment for the coin, NULL if not applicable.
|
||||
*/
|
||||
struct TALER_AgeCommitment *age_commitment;
|
||||
|
||||
/**
|
||||
* The blinding key (needed for recoup operations).
|
||||
*/
|
||||
@ -121,6 +126,11 @@ struct RefreshMeltState
|
||||
*/
|
||||
const struct TALER_CoinSpendPrivateKeyP *melt_priv;
|
||||
|
||||
/*
|
||||
* Age commitment for the coin, NULL if not applicable.
|
||||
*/
|
||||
struct TALER_AgeCommitment *age_commitment;
|
||||
|
||||
/**
|
||||
* Task scheduled to try later.
|
||||
*/
|
||||
@ -992,6 +1002,7 @@ melt_run (void *cls,
|
||||
const struct TALER_DenominationSignature *melt_sig;
|
||||
const struct TALER_EXCHANGE_DenomPublicKey *melt_denom_pub;
|
||||
const struct TALER_TESTING_Command *coin_command;
|
||||
bool age_restricted;
|
||||
|
||||
if (NULL == (coin_command
|
||||
= TALER_TESTING_interpreter_lookup_command
|
||||
@ -1012,6 +1023,16 @@ melt_run (void *cls,
|
||||
return;
|
||||
}
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_TESTING_get_trait_age_commitment (coin_command,
|
||||
0,
|
||||
&rms->age_commitment))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
TALER_TESTING_interpreter_fail (rms->is);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_TESTING_get_trait_denom_sig (coin_command,
|
||||
0,
|
||||
@ -1021,6 +1042,7 @@ melt_run (void *cls,
|
||||
TALER_TESTING_interpreter_fail (rms->is);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_TESTING_get_trait_denom_pub (coin_command,
|
||||
0,
|
||||
@ -1030,9 +1052,11 @@ melt_run (void *cls,
|
||||
TALER_TESTING_interpreter_fail (rms->is);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Melt amount starts with the melt fee of the old coin; we'll add the
|
||||
values and withdraw fees of the fresh coins next */
|
||||
melt_amount = melt_denom_pub->fee_refresh;
|
||||
age_restricted = melt_denom_pub->key.age_mask.mask != 0;
|
||||
for (unsigned int i = 0; i<num_fresh_coins; i++)
|
||||
{
|
||||
const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk;
|
||||
@ -1048,8 +1072,9 @@ melt_run (void *cls,
|
||||
TALER_TESTING_interpreter_fail (rms->is);
|
||||
return;
|
||||
}
|
||||
fresh_pk = TALER_TESTING_find_pk
|
||||
(TALER_EXCHANGE_get_keys (is->exchange), &fresh_amount);
|
||||
fresh_pk = TALER_TESTING_find_pk (TALER_EXCHANGE_get_keys (is->exchange),
|
||||
&fresh_amount,
|
||||
age_restricted);
|
||||
if (NULL == fresh_pk)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
@ -1071,13 +1096,33 @@ melt_run (void *cls,
|
||||
&fresh_pk->key);
|
||||
} /* end for */
|
||||
GNUNET_assert (NULL == rms->refresh_data);
|
||||
{
|
||||
struct TALER_AgeCommitment *ac = NULL;
|
||||
|
||||
GNUNET_assert (age_restricted == (NULL != rms->age_commitment));
|
||||
|
||||
if (NULL != rms->age_commitment)
|
||||
{
|
||||
uint32_t seed = GNUNET_CRYPTO_random_u32 (
|
||||
GNUNET_CRYPTO_QUALITY_WEAK,
|
||||
UINT32_MAX);
|
||||
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_age_commitment_derive (
|
||||
rms->age_commitment,
|
||||
seed,
|
||||
ac));
|
||||
}
|
||||
|
||||
rms->refresh_data
|
||||
= TALER_EXCHANGE_refresh_prepare (rms->melt_priv,
|
||||
&melt_amount,
|
||||
melt_sig,
|
||||
melt_denom_pub,
|
||||
ac,
|
||||
num_fresh_coins,
|
||||
rms->fresh_pks);
|
||||
}
|
||||
if (NULL == rms->refresh_data)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
@ -1168,6 +1213,8 @@ melt_traits (void *cls,
|
||||
&rms->fresh_pks[index]),
|
||||
TALER_TESTING_make_trait_coin_priv (0,
|
||||
rms->melt_priv),
|
||||
TALER_TESTING_make_trait_age_commitment (index,
|
||||
rms->age_commitment),
|
||||
TALER_TESTING_trait_end ()
|
||||
};
|
||||
|
||||
@ -1326,6 +1373,9 @@ refresh_reveal_traits (void *cls,
|
||||
TALER_TESTING_make_trait_coin_priv (
|
||||
index,
|
||||
&rrs->fresh_coins[index].coin_priv),
|
||||
TALER_TESTING_make_trait_age_commitment (
|
||||
index,
|
||||
rrs->fresh_coins[index].age_commitment),
|
||||
TALER_TESTING_make_trait_denom_pub (
|
||||
index,
|
||||
rrs->fresh_coins[index].pk),
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <microhttpd.h>
|
||||
#include <gnunet/gnunet_curl_lib.h>
|
||||
#include "taler_signatures.h"
|
||||
#include "taler_extensions.h"
|
||||
#include "taler_testing_lib.h"
|
||||
#include "backoff.h"
|
||||
|
||||
@ -115,6 +116,18 @@ struct WithdrawState
|
||||
*/
|
||||
struct TALER_PlanchetSecretsP ps;
|
||||
|
||||
/**
|
||||
* An age > 0 signifies age restriction is required
|
||||
*/
|
||||
uint8_t age;
|
||||
|
||||
/**
|
||||
* If age > 0, put here the corresponding age commitment and its hash,
|
||||
* respectivelly, NULL otherwise.
|
||||
*/
|
||||
struct TALER_AgeCommitment *age_commitment;
|
||||
struct TALER_AgeCommitmentHash *h_age_commitment;
|
||||
|
||||
/**
|
||||
* Reserve history entry that corresponds to this operation.
|
||||
* Will be of type #TALER_EXCHANGE_RTT_WITHDRAWAL.
|
||||
@ -363,12 +376,14 @@ withdraw_run (void *cls,
|
||||
= TALER_TESTING_interpreter_lookup_command (
|
||||
is,
|
||||
ws->reserve_reference);
|
||||
|
||||
if (NULL == create_reserve)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_TESTING_get_trait_reserve_priv (create_reserve,
|
||||
&rp))
|
||||
@ -377,6 +392,7 @@ withdraw_run (void *cls,
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
return;
|
||||
}
|
||||
|
||||
if (NULL == ws->exchange_url)
|
||||
ws->exchange_url
|
||||
= GNUNET_strdup (TALER_EXCHANGE_get_base_url (is->exchange));
|
||||
@ -386,6 +402,7 @@ withdraw_run (void *cls,
|
||||
ws->reserve_payto_uri
|
||||
= TALER_payto_from_reserve (ws->exchange_url,
|
||||
&ws->reserve_pub);
|
||||
|
||||
if (NULL == ws->reuse_coin_key_ref)
|
||||
{
|
||||
TALER_planchet_setup_random (&ws->ps);
|
||||
@ -412,10 +429,12 @@ withdraw_run (void *cls,
|
||||
TALER_planchet_setup_random (&ws->ps);
|
||||
ws->ps.coin_priv = *coin_priv;
|
||||
}
|
||||
|
||||
if (NULL == ws->pk)
|
||||
{
|
||||
dpk = TALER_TESTING_find_pk (TALER_EXCHANGE_get_keys (is->exchange),
|
||||
&ws->amount);
|
||||
&ws->amount,
|
||||
ws->age > 0);
|
||||
if (NULL == dpk)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
@ -433,18 +452,24 @@ withdraw_run (void *cls,
|
||||
{
|
||||
ws->amount = ws->pk->value;
|
||||
}
|
||||
|
||||
ws->reserve_history.type = TALER_EXCHANGE_RTT_WITHDRAWAL;
|
||||
GNUNET_assert (0 <=
|
||||
TALER_amount_add (&ws->reserve_history.amount,
|
||||
&ws->amount,
|
||||
&ws->pk->fee_withdraw));
|
||||
ws->reserve_history.details.withdraw.fee = ws->pk->fee_withdraw;
|
||||
|
||||
{
|
||||
|
||||
ws->wsh = TALER_EXCHANGE_withdraw (is->exchange,
|
||||
ws->pk,
|
||||
rp,
|
||||
&ws->ps,
|
||||
ws->h_age_commitment,
|
||||
&reserve_withdraw_cb,
|
||||
ws);
|
||||
}
|
||||
if (NULL == ws->wsh)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
@ -486,6 +511,16 @@ withdraw_cleanup (void *cls,
|
||||
TALER_EXCHANGE_destroy_denomination_key (ws->pk);
|
||||
ws->pk = NULL;
|
||||
}
|
||||
if (NULL != ws->age_commitment)
|
||||
{
|
||||
GNUNET_free (ws->age_commitment);
|
||||
ws->age_commitment = NULL;
|
||||
}
|
||||
if (NULL != ws->h_age_commitment)
|
||||
{
|
||||
GNUNET_free (ws->h_age_commitment);
|
||||
ws->h_age_commitment = NULL;
|
||||
}
|
||||
GNUNET_free (ws->exchange_url);
|
||||
GNUNET_free (ws->reserve_payto_uri);
|
||||
GNUNET_free (ws);
|
||||
@ -512,13 +547,13 @@ withdraw_traits (void *cls,
|
||||
struct TALER_TESTING_Trait traits[] = {
|
||||
/* history entry MUST be first due to response code logic below! */
|
||||
TALER_TESTING_make_trait_reserve_history (&ws->reserve_history),
|
||||
TALER_TESTING_make_trait_coin_priv (0 /* only one coin */,
|
||||
TALER_TESTING_make_trait_coin_priv (index /* only one coin */,
|
||||
&ws->ps.coin_priv),
|
||||
TALER_TESTING_make_trait_blinding_key (0 /* only one coin */,
|
||||
TALER_TESTING_make_trait_blinding_key (index /* only one coin */,
|
||||
&ws->ps.blinding_key),
|
||||
TALER_TESTING_make_trait_denom_pub (0 /* only one coin */,
|
||||
TALER_TESTING_make_trait_denom_pub (index /* only one coin */,
|
||||
ws->pk),
|
||||
TALER_TESTING_make_trait_denom_sig (0 /* only one coin */,
|
||||
TALER_TESTING_make_trait_denom_sig (index /* only one coin */,
|
||||
&ws->sig),
|
||||
TALER_TESTING_make_trait_reserve_priv (&ws->reserve_priv),
|
||||
TALER_TESTING_make_trait_reserve_pub (&ws->reserve_pub),
|
||||
@ -528,6 +563,8 @@ withdraw_traits (void *cls,
|
||||
(const char **) &ws->reserve_payto_uri),
|
||||
TALER_TESTING_make_trait_exchange_url (
|
||||
(const char **) &ws->exchange_url),
|
||||
TALER_TESTING_make_trait_age_commitment (index, ws->age_commitment),
|
||||
TALER_TESTING_make_trait_h_age_commitment (index, ws->h_age_commitment),
|
||||
TALER_TESTING_trait_end ()
|
||||
};
|
||||
|
||||
@ -547,6 +584,7 @@ withdraw_traits (void *cls,
|
||||
* @param label command label.
|
||||
* @param reserve_reference command providing us with a reserve to withdraw from
|
||||
* @param amount how much we withdraw.
|
||||
* @param age if > 0, age restriction is activated
|
||||
* @param expected_response_code which HTTP response code
|
||||
* we expect from the exchange.
|
||||
* @return the withdraw command to be executed by the interpreter.
|
||||
@ -555,11 +593,45 @@ struct TALER_TESTING_Command
|
||||
TALER_TESTING_cmd_withdraw_amount (const char *label,
|
||||
const char *reserve_reference,
|
||||
const char *amount,
|
||||
const uint8_t age,
|
||||
unsigned int expected_response_code)
|
||||
{
|
||||
struct WithdrawState *ws;
|
||||
|
||||
ws = GNUNET_new (struct WithdrawState);
|
||||
|
||||
ws->age = age;
|
||||
if (0 < age)
|
||||
{
|
||||
struct TALER_AgeCommitment *ac;
|
||||
struct TALER_AgeCommitmentHash *hac;
|
||||
uint32_t seed;
|
||||
struct TALER_AgeMask mask;
|
||||
|
||||
ac = GNUNET_new (struct TALER_AgeCommitment);
|
||||
hac = GNUNET_new (struct TALER_AgeCommitmentHash);
|
||||
seed = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX);
|
||||
mask = TALER_extensions_age_restriction_ageMask ();
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_age_restriction_commit (
|
||||
&mask,
|
||||
age,
|
||||
seed,
|
||||
ac))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to generate age commitment for age %d at %s\n",
|
||||
age,
|
||||
label);
|
||||
GNUNET_assert (0);
|
||||
}
|
||||
|
||||
TALER_age_commitment_hash (ac,hac);
|
||||
ws->age_commitment = ac;
|
||||
ws->h_age_commitment = hac;
|
||||
}
|
||||
|
||||
ws->reserve_reference = reserve_reference;
|
||||
if (GNUNET_OK !=
|
||||
TALER_string_to_amount (amount,
|
||||
@ -595,6 +667,7 @@ TALER_TESTING_cmd_withdraw_amount (const char *label,
|
||||
* @param label command label.
|
||||
* @param reserve_reference command providing us with a reserve to withdraw from
|
||||
* @param amount how much we withdraw.
|
||||
* @param age if > 0, age restriction is activated
|
||||
* @param coin_ref reference to (withdraw/reveal) command of a coin
|
||||
* from which we should re-use the private key
|
||||
* @param expected_response_code which HTTP response code
|
||||
@ -606,6 +679,7 @@ TALER_TESTING_cmd_withdraw_amount_reuse_key (
|
||||
const char *label,
|
||||
const char *reserve_reference,
|
||||
const char *amount,
|
||||
uint8_t age,
|
||||
const char *coin_ref,
|
||||
unsigned int expected_response_code)
|
||||
{
|
||||
@ -614,6 +688,7 @@ TALER_TESTING_cmd_withdraw_amount_reuse_key (
|
||||
cmd = TALER_TESTING_cmd_withdraw_amount (label,
|
||||
reserve_reference,
|
||||
amount,
|
||||
age,
|
||||
expected_response_code);
|
||||
{
|
||||
struct WithdrawState *ws = cmd.cls;
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "taler_json_lib.h"
|
||||
#include <gnunet/gnunet_curl_lib.h>
|
||||
#include "taler_signatures.h"
|
||||
#include "taler_extensions.h"
|
||||
#include "taler_testing_lib.h"
|
||||
|
||||
/**
|
||||
@ -312,6 +313,9 @@ sign_keys_for_exchange (void *cls,
|
||||
char *exchange_master_pub;
|
||||
int ret;
|
||||
|
||||
/* Load the age restriction mask from the configuration */
|
||||
TALER_extensions_load_taler_config (cfg);
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CONFIGURATION_get_value_string (cfg,
|
||||
"exchange",
|
||||
@ -416,11 +420,13 @@ TALER_TESTING_prepare_exchange (const char *config_filename,
|
||||
*
|
||||
* @param keys array of keys to search
|
||||
* @param amount coin value to look for
|
||||
* @param age_restricted must denomination support age restriction?
|
||||
* @return NULL if no matching key was found
|
||||
*/
|
||||
const struct TALER_EXCHANGE_DenomPublicKey *
|
||||
TALER_TESTING_find_pk (const struct TALER_EXCHANGE_Keys *keys,
|
||||
const struct TALER_Amount *amount)
|
||||
const struct TALER_Amount *amount,
|
||||
bool age_restricted)
|
||||
{
|
||||
struct GNUNET_TIME_Timestamp now;
|
||||
struct TALER_EXCHANGE_DenomPublicKey *pk;
|
||||
@ -437,7 +443,8 @@ TALER_TESTING_find_pk (const struct TALER_EXCHANGE_Keys *keys,
|
||||
pk->valid_from)) &&
|
||||
(GNUNET_TIME_timestamp_cmp (now,
|
||||
<,
|
||||
pk->withdraw_valid_until)) )
|
||||
pk->withdraw_valid_until)) &&
|
||||
(age_restricted == (0 != pk->key.age_mask.mask)) )
|
||||
return pk;
|
||||
}
|
||||
/* do 2nd pass to check if expiration times are to blame for
|
||||
@ -453,7 +460,8 @@ TALER_TESTING_find_pk (const struct TALER_EXCHANGE_Keys *keys,
|
||||
pk->valid_from) ||
|
||||
GNUNET_TIME_timestamp_cmp (now,
|
||||
>,
|
||||
pk->withdraw_valid_until) ) )
|
||||
pk->withdraw_valid_until) ) &&
|
||||
(age_restricted == (0 != pk->key.age_mask.mask)) )
|
||||
{
|
||||
GNUNET_log
|
||||
(GNUNET_ERROR_TYPE_WARNING,
|
||||
|
@ -20,11 +20,16 @@
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
* @author Christian Grothoff
|
||||
* @author Özgür Kesim
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_util.h"
|
||||
#include <gcrypt.h>
|
||||
|
||||
/**
|
||||
* Used in TALER_AgeCommitmentHash_isNullOrZero for comparison
|
||||
*/
|
||||
const struct TALER_AgeCommitmentHash TALER_ZeroAgeCommitmentHash = {0};
|
||||
|
||||
/**
|
||||
* Function called by libgcrypt on serious errors.
|
||||
@ -83,12 +88,11 @@ TALER_test_coin_valid (const struct TALER_CoinPublicInfo *coin_public_info,
|
||||
GNUNET_memcmp (&d_hash,
|
||||
&coin_public_info->denom_pub_hash));
|
||||
#endif
|
||||
// FIXME-Oec: replace with function that
|
||||
// also hashes the age vector if we have
|
||||
// one!
|
||||
GNUNET_CRYPTO_hash (&coin_public_info->coin_pub,
|
||||
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
|
||||
&c_hash.hash);
|
||||
|
||||
TALER_coin_pub_hash (&coin_public_info->coin_pub,
|
||||
&coin_public_info->age_commitment_hash,
|
||||
&c_hash);
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TALER_denom_pub_verify (denom_pub,
|
||||
&coin_public_info->denom_sig,
|
||||
@ -178,6 +182,7 @@ TALER_planchet_setup_random (struct TALER_PlanchetSecretsP *ps)
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_planchet_prepare (const struct TALER_DenominationPublicKey *dk,
|
||||
const struct TALER_PlanchetSecretsP *ps,
|
||||
const struct TALER_AgeCommitmentHash *ach,
|
||||
struct TALER_CoinPubHash *c_hash,
|
||||
struct TALER_PlanchetDetail *pd)
|
||||
{
|
||||
@ -188,7 +193,7 @@ TALER_planchet_prepare (const struct TALER_DenominationPublicKey *dk,
|
||||
if (GNUNET_OK !=
|
||||
TALER_denom_blind (dk,
|
||||
&ps->blinding_key,
|
||||
NULL, /* FIXME-Oec */
|
||||
ach,
|
||||
&coin_pub,
|
||||
c_hash,
|
||||
&pd->coin_ev,
|
||||
@ -208,6 +213,7 @@ TALER_planchet_to_coin (
|
||||
const struct TALER_DenominationPublicKey *dk,
|
||||
const struct TALER_BlindedDenominationSignature *blind_sig,
|
||||
const struct TALER_PlanchetSecretsP *ps,
|
||||
const struct TALER_AgeCommitmentHash *ach,
|
||||
const struct TALER_CoinPubHash *c_hash,
|
||||
struct TALER_FreshCoin *coin)
|
||||
{
|
||||
@ -233,6 +239,7 @@ TALER_planchet_to_coin (
|
||||
}
|
||||
coin->sig = sig;
|
||||
coin->coin_priv = ps->coin_priv;
|
||||
coin->h_age_commitment = ach;
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
@ -319,10 +326,10 @@ TALER_coin_ev_hash (const void *coin_ev,
|
||||
|
||||
void
|
||||
TALER_coin_pub_hash (const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_AgeHash *age_commitment_hash,
|
||||
const struct TALER_AgeCommitmentHash *ach,
|
||||
struct TALER_CoinPubHash *coin_h)
|
||||
{
|
||||
if (NULL == age_commitment_hash)
|
||||
if (TALER_AgeCommitmentHash_isNullOrZero (ach))
|
||||
{
|
||||
/* No age commitment was set */
|
||||
GNUNET_CRYPTO_hash (&coin_pub->eddsa_pub,
|
||||
@ -334,7 +341,7 @@ TALER_coin_pub_hash (const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
/* Coin comes with age commitment. Take the hash of the age commitment
|
||||
* into account */
|
||||
const size_t key_s = sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey);
|
||||
const size_t age_s = sizeof(struct TALER_AgeHash);
|
||||
const size_t age_s = sizeof(struct TALER_AgeCommitmentHash);
|
||||
char data[key_s + age_s];
|
||||
|
||||
GNUNET_memcpy (&data[0],
|
||||
@ -342,7 +349,7 @@ TALER_coin_pub_hash (const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
key_s);
|
||||
|
||||
GNUNET_memcpy (&data[key_s],
|
||||
age_commitment_hash,
|
||||
ach,
|
||||
age_s);
|
||||
|
||||
GNUNET_CRYPTO_hash (&data,
|
||||
@ -352,4 +359,276 @@ TALER_coin_pub_hash (const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TALER_age_commitment_hash (
|
||||
const struct TALER_AgeCommitment *commitment,
|
||||
struct TALER_AgeCommitmentHash *ahash)
|
||||
{
|
||||
struct GNUNET_HashContext *hash_context;
|
||||
struct GNUNET_HashCode hash;
|
||||
|
||||
GNUNET_assert (NULL != ahash);
|
||||
if (NULL == commitment)
|
||||
{
|
||||
memset (ahash, 0, sizeof(struct TALER_AgeCommitmentHash));
|
||||
return;
|
||||
}
|
||||
|
||||
GNUNET_assert (__builtin_popcount (commitment->mask.mask) - 1 ==
|
||||
commitment->num_pub);
|
||||
|
||||
hash_context = GNUNET_CRYPTO_hash_context_start ();
|
||||
|
||||
for (size_t i = 0; i < commitment->num_pub; i++)
|
||||
{
|
||||
GNUNET_CRYPTO_hash_context_read (hash_context,
|
||||
&commitment->pub[i],
|
||||
sizeof(struct
|
||||
GNUNET_CRYPTO_EddsaPublicKey));
|
||||
}
|
||||
|
||||
GNUNET_CRYPTO_hash_context_finish (hash_context,
|
||||
&hash);
|
||||
GNUNET_memcpy (&ahash->shash.bits,
|
||||
&hash.bits,
|
||||
sizeof(ahash->shash.bits));
|
||||
}
|
||||
|
||||
|
||||
/* To a given age value between 0 and 31, returns the index of the age group
|
||||
* defined by the given mask.
|
||||
*/
|
||||
static uint8_t
|
||||
get_age_group (
|
||||
const struct TALER_AgeMask *mask,
|
||||
uint8_t age)
|
||||
{
|
||||
uint32_t m = mask->mask;
|
||||
uint8_t i = 0;
|
||||
|
||||
while (m > 0)
|
||||
{
|
||||
if (0 >= age)
|
||||
break;
|
||||
m = m >> 1;
|
||||
i += m & 1;
|
||||
age--;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_age_restriction_commit (
|
||||
const struct TALER_AgeMask *mask,
|
||||
const uint8_t age,
|
||||
const uint32_t seed,
|
||||
struct TALER_AgeCommitment *new)
|
||||
{
|
||||
uint8_t num_pub = __builtin_popcount (mask->mask) - 1;
|
||||
uint8_t num_priv = get_age_group (mask, age) - 1;
|
||||
size_t i;
|
||||
|
||||
GNUNET_assert (NULL != new);
|
||||
GNUNET_assert (mask->mask & 1); /* fist bit must have been set */
|
||||
GNUNET_assert (0 <= num_priv);
|
||||
GNUNET_assert (31 > num_priv);
|
||||
|
||||
new->mask.mask = mask->mask;
|
||||
new->num_pub = num_pub;
|
||||
new->num_priv = num_priv;
|
||||
|
||||
new->pub = GNUNET_new_array (
|
||||
num_pub,
|
||||
struct TALER_AgeCommitmentPublicKeyP);
|
||||
new->priv = GNUNET_new_array (
|
||||
num_priv,
|
||||
struct TALER_AgeCommitmentPrivateKeyP);
|
||||
|
||||
/* Create as many private keys as we need */
|
||||
for (i = 0; i < num_priv; i++)
|
||||
{
|
||||
uint32_t seedBE = htonl (seed + i);
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CRYPTO_kdf (&new->priv[i],
|
||||
sizeof (new->priv[i]),
|
||||
&seedBE,
|
||||
sizeof (seedBE),
|
||||
"taler-age-commitment-derivation",
|
||||
strlen (
|
||||
"taler-age-commitment-derivation"),
|
||||
NULL, 0))
|
||||
goto FAIL;
|
||||
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&new->priv[i].eddsa_priv,
|
||||
&new->pub[i].eddsa_pub);
|
||||
}
|
||||
|
||||
/* Fill the rest of the public keys with random values */
|
||||
for (; i<num_pub; i++)
|
||||
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
|
||||
&new->pub[i],
|
||||
sizeof(new->pub[i]));
|
||||
|
||||
return GNUNET_OK;
|
||||
|
||||
FAIL:
|
||||
GNUNET_free (new->pub);
|
||||
GNUNET_free (new->priv);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_age_commitment_derive (
|
||||
const struct TALER_AgeCommitment *orig,
|
||||
const uint32_t seed,
|
||||
struct TALER_AgeCommitment *new)
|
||||
{
|
||||
struct GNUNET_CRYPTO_EccScalar val;
|
||||
|
||||
/*
|
||||
* age commitment consists of GNUNET_CRYPTO_Eddsa{Private,Public}Key
|
||||
*
|
||||
* GNUNET_CRYPTO_EddsaPrivateKey is a
|
||||
* unsigned char d[256 / 8];
|
||||
*
|
||||
* GNUNET_CRYPTO_EddsaPublicKey is a
|
||||
* unsigned char q_y[256 / 8];
|
||||
*
|
||||
* We want to multiply, both, the Private Key by an integer factor and the
|
||||
* public key (point on curve) with the equivalent scalar.
|
||||
*
|
||||
* From the seed we will derive
|
||||
* 1. a scalar to multiply the public keys with
|
||||
* 2. a factor to multiply the private key with
|
||||
*
|
||||
* Invariants:
|
||||
* point*scalar == public(private*factor)
|
||||
*
|
||||
* A point on a curve is GNUNET_CRYPTO_EccPoint which is
|
||||
* unsigned char v[256 / 8];
|
||||
*
|
||||
* A ECC scaler for use in point multiplications is a
|
||||
* GNUNET_CRYPTO_EccScalar which is a
|
||||
* unsigned car v[256 / 8];
|
||||
* */
|
||||
|
||||
GNUNET_assert (NULL != new);
|
||||
GNUNET_assert (orig->num_pub == __builtin_popcount (orig->mask.mask) - 1);
|
||||
GNUNET_assert (orig->num_priv <= orig->num_pub);
|
||||
|
||||
new->mask = orig->mask;
|
||||
new->num_pub = orig->num_pub;
|
||||
new->num_priv = orig->num_priv;
|
||||
new->pub = GNUNET_new_array (
|
||||
new->num_pub,
|
||||
struct TALER_AgeCommitmentPublicKeyP);
|
||||
new->priv = GNUNET_new_array (
|
||||
new->num_priv,
|
||||
struct TALER_AgeCommitmentPrivateKeyP);
|
||||
|
||||
|
||||
GNUNET_CRYPTO_ecc_scalar_from_int (seed, &val);
|
||||
|
||||
/* scalar multiply the public keys on the curve */
|
||||
for (size_t i = 0; i < orig->num_pub; i++)
|
||||
{
|
||||
/* We shift all keys by the same scalar */
|
||||
struct GNUNET_CRYPTO_EccPoint *p = (struct
|
||||
GNUNET_CRYPTO_EccPoint *) &orig->pub[i];
|
||||
struct GNUNET_CRYPTO_EccPoint *np = (struct
|
||||
GNUNET_CRYPTO_EccPoint *) &new->pub[i];
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CRYPTO_ecc_pmul_mpi (
|
||||
p,
|
||||
&val,
|
||||
np))
|
||||
goto FAIL;
|
||||
|
||||
}
|
||||
|
||||
/* multiply the private keys */
|
||||
/* we borough ideas from GNUNET_CRYPTO_ecdsa_private_key_derive */
|
||||
{
|
||||
uint32_t seedBE;
|
||||
uint8_t dc[32];
|
||||
gcry_mpi_t f, x, d, n;
|
||||
gcry_ctx_t ctx;
|
||||
|
||||
GNUNET_assert (0==gcry_mpi_ec_new (&ctx,NULL, "Ed25519"));
|
||||
n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
|
||||
|
||||
/* make the seed big endian */
|
||||
seedBE = GNUNET_htonll (seed);
|
||||
|
||||
GNUNET_CRYPTO_mpi_scan_unsigned (&f, &seedBE, sizeof(seedBE));
|
||||
|
||||
for (size_t i = 0; i < orig->num_priv; i++)
|
||||
{
|
||||
|
||||
/* convert to big endian for libgrypt */
|
||||
for (size_t j = 0; j < 32; j++)
|
||||
dc[i] = orig->priv[i].eddsa_priv.d[31 - j];
|
||||
GNUNET_CRYPTO_mpi_scan_unsigned (&x, dc, sizeof(dc));
|
||||
|
||||
d = gcry_mpi_new (256);
|
||||
gcry_mpi_mulm (d, f, x, n);
|
||||
gcry_mpi_release (x);
|
||||
gcry_mpi_release (d);
|
||||
gcry_mpi_release (n);
|
||||
gcry_mpi_release (d);
|
||||
GNUNET_CRYPTO_mpi_print_unsigned (dc, sizeof(dc), d);
|
||||
|
||||
for (size_t j = 0; j <32; j++)
|
||||
new->priv[i].eddsa_priv.d[j] = dc[31 - 1];
|
||||
|
||||
sodium_memzero (dc, sizeof(dc));
|
||||
|
||||
/* TODO:
|
||||
* make sure that the calculated private key generate the same public
|
||||
* keys */
|
||||
}
|
||||
|
||||
gcry_mpi_release (f);
|
||||
gcry_ctx_release (ctx);
|
||||
}
|
||||
|
||||
return GNUNET_OK;
|
||||
|
||||
FAIL:
|
||||
GNUNET_free (new->pub);
|
||||
GNUNET_free (new->priv);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TALER_age_restriction_commmitment_free_inside (
|
||||
struct TALER_AgeCommitment *commitment)
|
||||
{
|
||||
if (NULL == commitment)
|
||||
return;
|
||||
|
||||
if (NULL != commitment->priv)
|
||||
{
|
||||
GNUNET_CRYPTO_zero_keys (
|
||||
commitment->priv,
|
||||
sizeof(*commitment->priv) * commitment->num_priv);
|
||||
|
||||
GNUNET_free (commitment->priv);
|
||||
commitment->priv = NULL;
|
||||
}
|
||||
|
||||
if (NULL != commitment->pub)
|
||||
{
|
||||
GNUNET_free (commitment->pub);
|
||||
commitment->priv = NULL;
|
||||
}
|
||||
|
||||
/* Caller is responsible for commitment itself */
|
||||
}
|
||||
|
||||
|
||||
/* end of crypto.c */
|
||||
|
@ -235,7 +235,7 @@ TALER_denom_priv_to_pub (const struct TALER_DenominationPrivateKey *denom_priv,
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_denom_blind (const struct TALER_DenominationPublicKey *dk,
|
||||
const union TALER_DenominationBlindingKeyP *coin_bks,
|
||||
const struct TALER_AgeHash *age_commitment_hash,
|
||||
const struct TALER_AgeCommitmentHash *ach,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
struct TALER_CoinPubHash *c_hash,
|
||||
void **coin_ev,
|
||||
@ -245,7 +245,7 @@ TALER_denom_blind (const struct TALER_DenominationPublicKey *dk,
|
||||
{
|
||||
case TALER_DENOMINATION_RSA:
|
||||
TALER_coin_pub_hash (coin_pub,
|
||||
age_commitment_hash,
|
||||
ach,
|
||||
c_hash);
|
||||
if (GNUNET_YES !=
|
||||
GNUNET_CRYPTO_rsa_blind (&c_hash->hash,
|
||||
|
@ -101,6 +101,7 @@ test_planchets (void)
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_planchet_prepare (&dk_pub,
|
||||
&ps,
|
||||
NULL, /* no age commitment */
|
||||
&c_hash,
|
||||
&pd));
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
@ -112,6 +113,62 @@ test_planchets (void)
|
||||
TALER_planchet_to_coin (&dk_pub,
|
||||
&blind_sig,
|
||||
&ps,
|
||||
NULL, /* no age commitment */
|
||||
&c_hash,
|
||||
&coin));
|
||||
TALER_blinded_denom_sig_free (&blind_sig);
|
||||
TALER_denom_sig_free (&coin.sig);
|
||||
TALER_denom_priv_free (&dk_priv);
|
||||
TALER_denom_pub_free (&dk_pub);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test the basic planchet functionality of creating a fresh planchet and
|
||||
* extracting the respective signature, this time _with_ age commitment.
|
||||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
static int
|
||||
test_planchets_with_age_commitment (void)
|
||||
{
|
||||
struct TALER_PlanchetSecretsP ps;
|
||||
struct TALER_AgeCommitmentHash ach;
|
||||
struct TALER_DenominationPrivateKey dk_priv;
|
||||
struct TALER_DenominationPublicKey dk_pub;
|
||||
struct TALER_PlanchetDetail pd;
|
||||
struct TALER_BlindedDenominationSignature blind_sig;
|
||||
struct TALER_FreshCoin coin;
|
||||
struct TALER_CoinPubHash c_hash;
|
||||
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_denom_priv_create (&dk_priv,
|
||||
&dk_pub,
|
||||
TALER_DENOMINATION_RSA,
|
||||
1024));
|
||||
TALER_planchet_setup_random (&ps);
|
||||
GNUNET_CRYPTO_random_block (
|
||||
GNUNET_CRYPTO_QUALITY_WEAK,
|
||||
&ach,
|
||||
sizeof(struct TALER_AgeCommitmentHash));
|
||||
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_planchet_prepare (&dk_pub,
|
||||
&ps,
|
||||
&ach,
|
||||
&c_hash,
|
||||
&pd));
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_denom_sign_blinded (&blind_sig,
|
||||
&dk_priv,
|
||||
pd.coin_ev,
|
||||
pd.coin_ev_size));
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_planchet_to_coin (&dk_pub,
|
||||
&blind_sig,
|
||||
&ps,
|
||||
&ach,
|
||||
&c_hash,
|
||||
&coin));
|
||||
TALER_blinded_denom_sig_free (&blind_sig);
|
||||
@ -221,10 +278,12 @@ main (int argc,
|
||||
return 1;
|
||||
if (0 != test_planchets ())
|
||||
return 2;
|
||||
if (0 != test_exchange_sigs ())
|
||||
if (0 != test_planchets_with_age_commitment ())
|
||||
return 3;
|
||||
if (0 != test_merchant_sigs ())
|
||||
if (0 != test_exchange_sigs ())
|
||||
return 4;
|
||||
if (0 != test_merchant_sigs ())
|
||||
return 5;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -268,9 +268,13 @@ test_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh)
|
||||
enum TALER_ErrorCode ec;
|
||||
bool success = false;
|
||||
struct TALER_PlanchetSecretsP ps;
|
||||
struct TALER_AgeCommitmentHash ach;
|
||||
struct TALER_CoinPubHash c_hash;
|
||||
|
||||
TALER_planchet_setup_random (&ps);
|
||||
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
|
||||
&ach,
|
||||
sizeof(ach));
|
||||
for (unsigned int i = 0; i<MAX_KEYS; i++)
|
||||
{
|
||||
if (! keys[i].valid)
|
||||
@ -281,6 +285,7 @@ test_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh)
|
||||
GNUNET_assert (GNUNET_YES ==
|
||||
TALER_planchet_prepare (&keys[i].denom_pub,
|
||||
&ps,
|
||||
&ach,
|
||||
&c_hash,
|
||||
&pd));
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
@ -418,8 +423,12 @@ perf_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh,
|
||||
enum TALER_ErrorCode ec;
|
||||
struct GNUNET_TIME_Relative duration;
|
||||
struct TALER_PlanchetSecretsP ps;
|
||||
struct TALER_AgeCommitmentHash ach;
|
||||
|
||||
TALER_planchet_setup_random (&ps);
|
||||
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
|
||||
&ach,
|
||||
sizeof(ach));
|
||||
duration = GNUNET_TIME_UNIT_ZERO;
|
||||
TALER_CRYPTO_helper_rsa_poll (dh);
|
||||
for (unsigned int j = 0; j<NUM_SIGN_PERFS;)
|
||||
@ -445,6 +454,7 @@ perf_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh,
|
||||
GNUNET_assert (GNUNET_YES ==
|
||||
TALER_planchet_prepare (&keys[i].denom_pub,
|
||||
&ps,
|
||||
&ach,
|
||||
&c_hash,
|
||||
&pd));
|
||||
/* use this key as long as it works */
|
||||
|
@ -29,6 +29,7 @@ TALER_wallet_deposit_sign (
|
||||
const struct TALER_Amount *deposit_fee,
|
||||
const struct TALER_MerchantWireHash *h_wire,
|
||||
const struct TALER_PrivateContractHash *h_contract_terms,
|
||||
const struct TALER_AgeCommitmentHash *h_age_commitment,
|
||||
const struct TALER_ExtensionContractHash *h_extensions,
|
||||
const struct TALER_DenominationHash *h_denom_pub,
|
||||
struct GNUNET_TIME_Timestamp wallet_timestamp,
|
||||
@ -48,8 +49,12 @@ TALER_wallet_deposit_sign (
|
||||
.merchant = *merchant_pub
|
||||
};
|
||||
|
||||
if (NULL != h_age_commitment)
|
||||
dr.h_age_commitment = *h_age_commitment;
|
||||
|
||||
if (NULL != h_extensions)
|
||||
dr.h_extensions = *h_extensions;
|
||||
|
||||
TALER_amount_hton (&dr.amount_with_fee,
|
||||
amount);
|
||||
TALER_amount_hton (&dr.deposit_fee,
|
||||
@ -66,6 +71,7 @@ TALER_wallet_deposit_verify (
|
||||
const struct TALER_Amount *deposit_fee,
|
||||
const struct TALER_MerchantWireHash *h_wire,
|
||||
const struct TALER_PrivateContractHash *h_contract_terms,
|
||||
const struct TALER_AgeCommitmentHash *h_age_commitment,
|
||||
const struct TALER_ExtensionContractHash *h_extensions,
|
||||
const struct TALER_DenominationHash *h_denom_pub,
|
||||
struct GNUNET_TIME_Timestamp wallet_timestamp,
|
||||
@ -82,11 +88,21 @@ TALER_wallet_deposit_verify (
|
||||
.h_denom_pub = *h_denom_pub,
|
||||
.wallet_timestamp = GNUNET_TIME_timestamp_hton (wallet_timestamp),
|
||||
.refund_deadline = GNUNET_TIME_timestamp_hton (refund_deadline),
|
||||
.merchant = *merchant_pub
|
||||
.merchant = *merchant_pub,
|
||||
.h_age_commitment = {{{0}}},
|
||||
.h_extensions = {{{0}}}
|
||||
};
|
||||
|
||||
if (NULL != h_age_commitment)
|
||||
{
|
||||
dr.h_age_commitment = *h_age_commitment;
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"VFVFVFVF got NON-NULL h_age_commitment\n");
|
||||
}
|
||||
|
||||
if (NULL != h_extensions)
|
||||
dr.h_extensions = *h_extensions;
|
||||
|
||||
TALER_amount_hton (&dr.amount_with_fee,
|
||||
amount);
|
||||
TALER_amount_hton (&dr.deposit_fee,
|
||||
@ -135,6 +151,7 @@ TALER_wallet_link_verify (
|
||||
const struct TALER_TransferPublicKeyP *transfer_pub,
|
||||
const struct TALER_BlindedCoinHash *h_coin_ev,
|
||||
const struct TALER_CoinSpendPublicKeyP *old_coin_pub,
|
||||
const struct TALER_AgeCommitmentHash *h_age_commitment,
|
||||
const struct TALER_CoinSpendSignatureP *coin_sig)
|
||||
{
|
||||
struct TALER_LinkDataPS ldp = {
|
||||
@ -142,9 +159,13 @@ TALER_wallet_link_verify (
|
||||
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_LINK),
|
||||
.h_denom_pub = *h_denom_pub,
|
||||
.transfer_pub = *transfer_pub,
|
||||
.coin_envelope_hash = *h_coin_ev
|
||||
.coin_envelope_hash = *h_coin_ev,
|
||||
.h_age_commitment = {{{0}}}
|
||||
};
|
||||
|
||||
if (NULL != h_age_commitment)
|
||||
ldp.h_age_commitment = *h_age_commitment;
|
||||
|
||||
return
|
||||
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_LINK,
|
||||
&ldp,
|
||||
@ -267,6 +288,7 @@ TALER_wallet_melt_verify (
|
||||
const struct TALER_Amount *melt_fee,
|
||||
const struct TALER_RefreshCommitmentP *rc,
|
||||
const struct TALER_DenominationHash *h_denom_pub,
|
||||
const struct TALER_AgeCommitmentHash *h_age_commitment,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_CoinSpendSignatureP *coin_sig)
|
||||
{
|
||||
@ -274,9 +296,13 @@ TALER_wallet_melt_verify (
|
||||
.purpose.size = htonl (sizeof (melt)),
|
||||
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT),
|
||||
.rc = *rc,
|
||||
.h_denom_pub = *h_denom_pub
|
||||
.h_denom_pub = *h_denom_pub,
|
||||
.h_age_commitment = {{{0}}},
|
||||
};
|
||||
|
||||
if (NULL != h_age_commitment)
|
||||
melt.h_age_commitment = *h_age_commitment;
|
||||
|
||||
TALER_amount_hton (&melt.amount_with_fee,
|
||||
amount_with_fee);
|
||||
TALER_amount_hton (&melt.melt_fee,
|
||||
|
Loading…
Reference in New Issue
Block a user