summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÖzgür Kesim <oec-taler@kesim.org>2022-06-27 17:38:11 +0200
committerÖzgür Kesim <oec-taler@kesim.org>2022-06-27 17:38:11 +0200
commitcddfaf007f4ac22e224f3df5f0151a0d620fb131 (patch)
tree691801af8cce13e8c4fd1adb3c53606a5e7c57fb
parent87025cfd178780f2e928019163ce81c1b7675c57 (diff)
downloadexchange-cddfaf007f4ac22e224f3df5f0151a0d620fb131.tar.gz
exchange-cddfaf007f4ac22e224f3df5f0151a0d620fb131.tar.bz2
exchange-cddfaf007f4ac22e224f3df5f0151a0d620fb131.zip
age commitment: json parser helper and support for purses added
-rw-r--r--src/exchange/taler-exchange-httpd_purses_create.c57
-rw-r--r--src/exchange/taler-exchange-httpd_purses_deposit.c57
-rw-r--r--src/include/taler_json_lib.h23
-rw-r--r--src/json/json_helper.c103
-rw-r--r--src/json/json_pack.c34
-rw-r--r--src/lib/exchange_api_purse_deposit.c44
6 files changed, 289 insertions, 29 deletions
diff --git a/src/exchange/taler-exchange-httpd_purses_create.c b/src/exchange/taler-exchange-httpd_purses_create.c
index a981ba582..2c8032342 100644
--- a/src/exchange/taler-exchange-httpd_purses_create.c
+++ b/src/exchange/taler-exchange-httpd_purses_create.c
@@ -456,6 +456,10 @@ parse_coin (struct MHD_Connection *connection,
struct Coin *coin,
const json_t *jcoin)
{
+ struct TALER_AgeAttestation attest = {0};
+ bool no_attest = true;
+ struct TALER_AgeCommitment age_commitment = {0};
+ bool no_age_commitment = true;
struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_amount ("amount",
TEH_currency,
@@ -465,10 +469,13 @@ parse_coin (struct MHD_Connection *connection,
TALER_JSON_spec_denom_sig ("ub_sig",
&coin->cpi.denom_sig),
GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
- &coin->cpi.h_age_commitment),
- &coin->cpi.no_age_commitment),
- // FIXME-Oec: proof of age is missing.
+ GNUNET_JSON_spec_fixed_auto ("attest",
+ &attest),
+ &no_attest),
+ GNUNET_JSON_spec_mark_optional (
+ TALER_JSON_spec_age_commitment ("age_commitment",
+ &age_commitment),
+ &no_age_commitment),
GNUNET_JSON_spec_fixed_auto ("coin_sig",
&coin->coin_sig),
GNUNET_JSON_spec_fixed_auto ("coin_pub",
@@ -591,6 +598,48 @@ parse_coin (struct MHD_Connection *connection,
TALER_amount_subtract (&coin->amount_minus_fee,
&coin->amount,
&coin->deposit_fee));
+
+ // Check and verify the age restriction. Needs to happen before
+ // coin-signature check, because we set the h_age_commitment here.
+ {
+ if (no_attest != no_age_commitment)
+
+ {
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ /* FIXME: other error code? */
+ TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_AGE_HASH,
+ "mismatch of attest and age_commitment");
+ }
+
+ if (! no_age_commitment)
+ {
+ // attestation must be valid.
+ if (GNUNET_OK !=
+ TALER_age_commitment_verify (
+ &age_commitment,
+ pcc->min_age,
+ &attest))
+ {
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ /* FIXME: other error code? */
+ TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_AGE_HASH,
+ "invalid attest for minimum age");
+ }
+
+ // Save the hash of the age commitment in the coin's public info, so we
+ // can verify the signature later.
+ TALER_age_commitment_hash (&age_commitment,
+ &coin->cpi.h_age_commitment);
+ coin->cpi.no_age_commitment = false;
+
+ }
+ }
+
+
/* check coin signature */
switch (dk->denom_pub.cipher)
{
diff --git a/src/exchange/taler-exchange-httpd_purses_deposit.c b/src/exchange/taler-exchange-httpd_purses_deposit.c
index 50ed582ad..d65610dc6 100644
--- a/src/exchange/taler-exchange-httpd_purses_deposit.c
+++ b/src/exchange/taler-exchange-httpd_purses_deposit.c
@@ -300,6 +300,10 @@ parse_coin (struct MHD_Connection *connection,
struct Coin *coin,
const json_t *jcoin)
{
+ struct TALER_AgeAttestation attest = {0};
+ bool no_attest = true;
+ struct TALER_AgeCommitment age_commitment = {0};
+ bool no_age_commitment = true;
struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_amount ("amount",
TEH_currency,
@@ -309,10 +313,13 @@ parse_coin (struct MHD_Connection *connection,
TALER_JSON_spec_denom_sig ("ub_sig",
&coin->cpi.denom_sig),
GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
- &coin->cpi.h_age_commitment),
- &coin->cpi.no_age_commitment),
- // FIXME-Oec: proof of age is missing!
+ GNUNET_JSON_spec_fixed_auto ("attest",
+ &attest),
+ &no_attest),
+ GNUNET_JSON_spec_mark_optional (
+ TALER_JSON_spec_age_commitment ("age_commitment",
+ &age_commitment),
+ &no_age_commitment),
GNUNET_JSON_spec_fixed_auto ("coin_sig",
&coin->coin_sig),
GNUNET_JSON_spec_fixed_auto ("coin_pub",
@@ -433,6 +440,47 @@ parse_coin (struct MHD_Connection *connection,
TALER_amount_subtract (&coin->amount_minus_fee,
&coin->amount,
&coin->deposit_fee));
+
+ // Check and verify the age restriction. Needs to happen before
+ // coin-signature check, because we set the h_age_commitment here.
+ {
+ if (no_attest != no_age_commitment)
+
+ {
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ /* FIXME: other error code? */
+ TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_AGE_HASH,
+ "mismatch of attest and age_commitment");
+ }
+
+ if (! no_age_commitment)
+ {
+ // attestation must be valid.
+ if (GNUNET_OK !=
+ TALER_age_commitment_verify (
+ &age_commitment,
+ pcc->min_age,
+ &attest))
+ {
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ /* FIXME: other error code? */
+ TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_AGE_HASH,
+ "invalid attest for minimum age");
+ }
+
+ // Save the hash of the age commitment in the coin's public info, so we
+ // can verify the signature later.
+ TALER_age_commitment_hash (&age_commitment,
+ &coin->cpi.h_age_commitment);
+ coin->cpi.no_age_commitment = false;
+
+ }
+ }
+
/* check coin signature */
switch (dk->denom_pub.cipher)
{
@@ -470,6 +518,7 @@ parse_coin (struct MHD_Connection *connection,
"total deposit contribution");
}
}
+
{
MHD_RESULT mhd_ret = MHD_NO;
enum GNUNET_DB_QueryStatus qs;
diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h
index 1300f8751..d8912e52e 100644
--- a/src/include/taler_json_lib.h
+++ b/src/include/taler_json_lib.h
@@ -215,6 +215,18 @@ TALER_JSON_pack_econtract (
const char *name,
const struct TALER_EncryptedContract *econtract);
+/**
+ * Generate packer instruction for a JSON field of type age_commitment
+ *
+ * @param name name of the field to add to the object
+ * @param age_commitment age commitment to add
+ * @return json pack specification
+ */
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_age_commitment (
+ const char *name,
+ const struct TALER_AgeCommitment *age_commitment);
+
/**
* Convert a TALER amount to a JSON object.
@@ -295,6 +307,17 @@ TALER_JSON_spec_econtract (const char *name,
/**
+ * Provide specification to parse a given JSON object to an age commitment.
+ *
+ * @param name name of the age commitment field in the JSON
+ * @param[out] age_commitment where to store the age commitment
+ * @return spec for parsing an age commitment
+ */
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_age_commitment (const char *name,
+ struct TALER_AgeCommitment *age_commitment);
+
+/**
* Provide specification to parse given JSON object to an amount
* in any currency in network byte order.
*
diff --git a/src/json/json_helper.c b/src/json/json_helper.c
index 202caf6f1..cf169384e 100644
--- a/src/json/json_helper.c
+++ b/src/json/json_helper.c
@@ -402,6 +402,109 @@ TALER_JSON_spec_econtract (const char *name,
/**
+ * Parse given JSON object to an age commitmnet
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static enum GNUNET_GenericReturnValue
+parse_age_commitment (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_AgeCommitment *age_commitment = spec->ptr;
+ json_t *pk;
+ unsigned int idx;
+ size_t num;
+
+ if (NULL == root || ! json_is_array (root))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ num = json_array_size (root);
+ if (32 <= num || 0 == num)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ age_commitment->num = num;
+ age_commitment->keys =
+ GNUNET_new_array (num,
+ struct TALER_AgeCommitmentPublicKeyP);
+
+ json_array_foreach (root, idx, pk) {
+ const char *emsg;
+ unsigned int eline;
+ struct GNUNET_JSON_Specification pkspec[] = {
+ GNUNET_JSON_spec_fixed_auto (
+ NULL,
+ &age_commitment->keys[idx].pub),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (pk,
+ pkspec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
+ return GNUNET_SYSERR;
+ }
+ };
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Cleanup data left fom parsing age commitment
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_age_commitment (void *cls,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_AgeCommitment *age_commitment = spec->ptr;
+
+ (void) cls;
+
+ if (NULL == age_commitment ||
+ NULL == age_commitment->keys)
+ return;
+
+ age_commitment->num = 0;
+ GNUNET_free (age_commitment->keys);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_age_commitment (const char *name,
+ struct TALER_AgeCommitment *age_commitment)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_age_commitment,
+ .cleaner = &clean_age_commitment,
+ .cls = NULL,
+ .field = name,
+ .ptr = age_commitment,
+ .ptr_size = 0,
+ .size_ptr = NULL
+ };
+
+ return ret;
+}
+
+
+/**
* Parse given JSON object to denomination public key.
*
* @param cls closure, NULL
diff --git a/src/json/json_pack.c b/src/json/json_pack.c
index bb52eeb05..ec036f691 100644
--- a/src/json/json_pack.c
+++ b/src/json/json_pack.c
@@ -72,6 +72,40 @@ TALER_JSON_pack_econtract (
struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_age_commitment (
+ const char *name,
+ const struct TALER_AgeCommitment *age_commitment)
+{
+ struct GNUNET_JSON_PackSpec ps = {
+ .field_name = name,
+ };
+ json_t *keys;
+
+ if (NULL == age_commitment ||
+ 0 == age_commitment->num)
+ return ps;
+
+ GNUNET_assert (NULL !=
+ (keys = json_array ()));
+
+ for (size_t i = 0;
+ i < age_commitment->num;
+ i++)
+ {
+ json_t *val;
+ val = GNUNET_JSON_from_data (&age_commitment->keys[i],
+ sizeof(age_commitment->keys[i]));
+ GNUNET_assert (NULL != val);
+ GNUNET_assert (0 ==
+ json_array_append_new (keys, val));
+ }
+
+ ps.object = keys;
+ return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
TALER_JSON_pack_denom_pub (
const char *name,
const struct TALER_DenominationPublicKey *pk)
diff --git a/src/lib/exchange_api_purse_deposit.c b/src/lib/exchange_api_purse_deposit.c
index 6946419dc..836183bbe 100644
--- a/src/lib/exchange_api_purse_deposit.c
+++ b/src/lib/exchange_api_purse_deposit.c
@@ -485,29 +485,33 @@ TALER_EXCHANGE_purse_deposit (
for (unsigned int i = 0; i<num_deposits; i++)
{
const struct TALER_EXCHANGE_PurseDeposit *deposit = &deposits[i];
+ const struct TALER_AgeCommitmentProof *acp = deposit->age_commitment_proof;
struct Coin *coin = &pch->coins[i];
json_t *jdeposit;
-#if FIXME_OEC
- struct TALER_AgeCommitmentHash agh;
- struct TALER_AgeCommitmentHash *aghp = NULL;
+ struct TALER_AgeCommitmentHash ach;
+ struct TALER_AgeCommitmentHash *achp = NULL;
struct TALER_AgeAttestation attest;
+ struct TALER_AgeAttestation *attestp = NULL;
- TALER_age_commitment_hash (&deposit->age_commitment,
- &agh);
- aghp = &agh;
- if (GNUNET_OK !=
- TALER_age_commitment_attest (&deposit->age_proof,
- min_age,
- &attest))
+ if (NULL != acp)
{
- GNUNET_break (0);
- json_decref (deposit_arr);
- GNUNET_free (pch->base_url);
- GNUNET_free (pch->coins);
- GNUNET_free (pch);
- return NULL;
+ TALER_age_commitment_hash (&acp->commitment,
+ &ach);
+ achp = &ach;
+ if (GNUNET_OK !=
+ TALER_age_commitment_attest (acp,
+ min_age,
+ &attest))
+ {
+ GNUNET_break (0);
+ json_decref (deposit_arr);
+ GNUNET_free (pch->base_url);
+ GNUNET_free (pch->coins);
+ GNUNET_free (pch);
+ return NULL;
+ }
+ attestp = &attest;
}
-#endif
GNUNET_CRYPTO_eddsa_key_get_public (&deposit->coin_priv.eddsa_priv,
&coin->coin_pub.eddsa_pub);
coin->h_denom_pub = deposit->h_denom_pub;
@@ -519,14 +523,12 @@ TALER_EXCHANGE_purse_deposit (
&deposit->coin_priv,
&coin->coin_sig);
jdeposit = GNUNET_JSON_PACK (
-#if FIXME_OEC
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_data_auto ("h_age_commitment",
- aghp)),
+ achp)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_data_auto ("age_attestation",
- &attest)),
-#endif
+ attestp)),
TALER_JSON_pack_amount ("amount",
&deposit->amount),
GNUNET_JSON_pack_data_auto ("denom_pub_hash",