summaryrefslogtreecommitdiff
path: root/src/json/json_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/json/json_helper.c')
-rw-r--r--src/json/json_helper.c1376
1 files changed, 1160 insertions, 216 deletions
diff --git a/src/json/json_helper.c b/src/json/json_helper.c
index 7c01cde0c..0a533610b 100644
--- a/src/json/json_helper.c
+++ b/src/json/json_helper.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2021 Taler Systems SA
+ Copyright (C) 2014-2023 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
@@ -26,6 +26,29 @@
#include "taler_json_lib.h"
+/**
+ * Convert string value to numeric cipher value.
+ *
+ * @param cipher_s input string
+ * @return numeric cipher value
+ */
+static enum GNUNET_CRYPTO_BlindSignatureAlgorithm
+string_to_cipher (const char *cipher_s)
+{
+ if ((0 == strcasecmp (cipher_s,
+ "RSA")) ||
+ (0 == strcasecmp (cipher_s,
+ "RSA+age_restricted")))
+ return GNUNET_CRYPTO_BSA_RSA;
+ if ((0 == strcasecmp (cipher_s,
+ "CS")) ||
+ (0 == strcasecmp (cipher_s,
+ "CS+age_restricted")))
+ return GNUNET_CRYPTO_BSA_CS;
+ return GNUNET_CRYPTO_BSA_INVALID;
+}
+
+
json_t *
TALER_JSON_from_amount (const struct TALER_Amount *amount)
{
@@ -41,17 +64,6 @@ TALER_JSON_from_amount (const struct TALER_Amount *amount)
}
-json_t *
-TALER_JSON_from_amount_nbo (const struct TALER_AmountNBO *amount)
-{
- struct TALER_Amount a;
-
- TALER_amount_ntoh (&a,
- amount);
- return TALER_JSON_from_amount (&a);
-}
-
-
/**
* Parse given JSON object to Amount
*
@@ -87,6 +99,11 @@ parse_amount (void *cls,
r_amount->currency)) )
{
GNUNET_break_op (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Expected currency `%s', but amount used currency `%s' in field `%s'\n",
+ currency,
+ r_amount->currency,
+ spec->field);
return GNUNET_SYSERR;
}
return GNUNET_OK;
@@ -132,7 +149,7 @@ TALER_JSON_spec_amount_any (const char *name,
/**
- * Parse given JSON object to Amount in NBO.
+ * Parse given JSON object to currency spec.
*
* @param cls closure, NULL
* @param root the json object representing data
@@ -140,157 +157,200 @@ TALER_JSON_spec_amount_any (const char *name,
* @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
*/
static enum GNUNET_GenericReturnValue
-parse_amount_nbo (void *cls,
- json_t *root,
- struct GNUNET_JSON_Specification *spec)
+parse_cspec (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
{
- const char *currency = cls;
- struct TALER_AmountNBO *r_amount = spec->ptr;
- const char *sv;
+ struct TALER_CurrencySpecification *r_cspec = spec->ptr;
+ const char *currency = spec->cls;
+ const char *name;
+ uint32_t fid;
+ uint32_t fnd;
+ uint32_t ftzd;
+ const json_t *map;
+ struct GNUNET_JSON_Specification gspec[] = {
+ GNUNET_JSON_spec_string ("name",
+ &name),
+ GNUNET_JSON_spec_uint32 ("num_fractional_input_digits",
+ &fid),
+ GNUNET_JSON_spec_uint32 ("num_fractional_normal_digits",
+ &fnd),
+ GNUNET_JSON_spec_uint32 ("num_fractional_trailing_zero_digits",
+ &ftzd),
+ GNUNET_JSON_spec_object_const ("alt_unit_names",
+ &map),
+ GNUNET_JSON_spec_end ()
+ };
+ const char *emsg;
+ unsigned int eline;
- (void) cls;
- if (! json_is_string (root))
+ memset (r_cspec->currency,
+ 0,
+ sizeof (r_cspec->currency));
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ gspec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to parse %s at %u: %s\n",
+ spec[eline].field,
+ eline,
+ emsg);
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (strlen (currency) >= TALER_CURRENCY_LEN)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if ( (fid > TALER_AMOUNT_FRAC_LEN) ||
+ (fnd > TALER_AMOUNT_FRAC_LEN) ||
+ (ftzd > TALER_AMOUNT_FRAC_LEN) )
{
- GNUNET_break (0);
+ GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- sv = json_string_value (root);
if (GNUNET_OK !=
- TALER_string_to_amount_nbo (sv,
- r_amount))
+ TALER_check_currency (currency))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "`%s' is not a valid amount\n",
- sv);
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- if ( (NULL != currency) &&
- (0 !=
- strcasecmp (currency,
- r_amount->currency)) )
+ strcpy (r_cspec->currency,
+ currency);
+ if (GNUNET_OK !=
+ TALER_check_currency_scale_map (map))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
+ r_cspec->name = GNUNET_strdup (name);
+ r_cspec->map_alt_unit_names = json_incref ((json_t *) map);
return GNUNET_OK;
}
-struct GNUNET_JSON_Specification
-TALER_JSON_spec_amount_nbo (const char *name,
- const char *currency,
- struct TALER_AmountNBO *r_amount)
+/**
+ * Cleanup data left from parsing encrypted contract.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_cspec (void *cls,
+ struct GNUNET_JSON_Specification *spec)
{
- struct GNUNET_JSON_Specification ret = {
- .parser = &parse_amount_nbo,
- .cleaner = NULL,
- .cls = (void *) currency,
- .field = name,
- .ptr = r_amount,
- .ptr_size = 0,
- .size_ptr = NULL
- };
+ struct TALER_CurrencySpecification *cspec = spec->ptr;
- GNUNET_assert (NULL != currency);
- return ret;
+ (void) cls;
+ GNUNET_free (cspec->name);
+ json_decref (cspec->map_alt_unit_names);
}
struct GNUNET_JSON_Specification
-TALER_JSON_spec_amount_any_nbo (const char *name,
- struct TALER_AmountNBO *r_amount)
+TALER_JSON_spec_currency_specification (
+ const char *name,
+ const char *currency,
+ struct TALER_CurrencySpecification *r_cspec)
{
struct GNUNET_JSON_Specification ret = {
- .parser = &parse_amount_nbo,
- .cleaner = NULL,
- .cls = NULL,
+ .parser = &parse_cspec,
+ .cleaner = &clean_cspec,
+ .cls = (void *) currency,
.field = name,
- .ptr = r_amount,
- .ptr_size = 0,
+ .ptr = r_cspec,
+ .ptr_size = sizeof (*r_cspec),
.size_ptr = NULL
};
+ memset (r_cspec,
+ 0,
+ sizeof (*r_cspec));
return ret;
}
-/**
- * Parse given JSON object to *rounded* absolute time.
- *
- * @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_abs_time (void *cls,
- json_t *root,
- struct GNUNET_JSON_Specification *spec)
+parse_denomination_group (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
{
- struct GNUNET_TIME_Absolute *abs = spec->ptr;
- json_t *json_t_ms;
- unsigned long long int tval;
+ struct TALER_DenominationGroup *group = spec->ptr;
+ const char *cipher;
+ const char *currency = cls;
+ bool age_mask_missing = false;
+ bool has_age_restricted_suffix = false;
+ struct GNUNET_JSON_Specification gspec[] = {
+ GNUNET_JSON_spec_string ("cipher",
+ &cipher),
+ TALER_JSON_spec_amount ("value",
+ currency,
+ &group->value),
+ TALER_JSON_SPEC_DENOM_FEES ("fee",
+ currency,
+ &group->fees),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_uint32 ("age_mask",
+ &group->age_mask.bits),
+ &age_mask_missing),
+ GNUNET_JSON_spec_end ()
+ };
+ const char *emsg;
+ unsigned int eline;
- (void) cls;
- if (! json_is_object (root))
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ gspec,
+ &emsg,
+ &eline))
{
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to parse %s at %u: %s\n",
+ spec[eline].field,
+ eline,
+ emsg);
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- json_t_ms = json_object_get (root,
- "t_ms");
- if (json_is_integer (json_t_ms))
+
+ group->cipher = string_to_cipher (cipher);
+ if (GNUNET_CRYPTO_BSA_INVALID == group->cipher)
{
- tval = json_integer_value (json_t_ms);
- /* Time is in milliseconds in JSON, but in microseconds in GNUNET_TIME_Absolute */
- abs->abs_value_us = tval * 1000LL;
- if ((abs->abs_value_us) / 1000LL != tval)
- {
- /* Integer overflow */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_TIME_round_abs (abs))
- {
- /* time not rounded */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
}
- if (json_is_string (json_t_ms))
- {
- const char *val;
- val = json_string_value (json_t_ms);
- if ((0 == strcasecmp (val, "never")))
- {
- *abs = GNUNET_TIME_UNIT_FOREVER_ABS;
- return GNUNET_OK;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "`%s' is not a valid absolute time\n",
- json_string_value (json_t_ms));
+ /* age_mask and suffix must be consistent */
+ has_age_restricted_suffix =
+ (NULL != strstr (cipher, "+age_restricted"));
+ if (has_age_restricted_suffix && age_mask_missing)
+ {
+ GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- return GNUNET_SYSERR;
+
+ if (age_mask_missing)
+ group->age_mask.bits = 0;
+
+ return GNUNET_OK;
}
struct GNUNET_JSON_Specification
-TALER_JSON_spec_absolute_time (const char *name,
- struct GNUNET_TIME_Absolute *r_time)
+TALER_JSON_spec_denomination_group (const char *name,
+ const char *currency,
+ struct TALER_DenominationGroup *group)
{
struct GNUNET_JSON_Specification ret = {
- .parser = &parse_abs_time,
- .cleaner = NULL,
- .cls = NULL,
+ .cls = (void *) currency,
+ .parser = &parse_denomination_group,
.field = name,
- .ptr = r_time,
- .ptr_size = sizeof(struct GNUNET_TIME_Absolute),
- .size_ptr = NULL
+ .ptr = group,
+ .ptr_size = sizeof(*group)
};
return ret;
@@ -298,7 +358,7 @@ TALER_JSON_spec_absolute_time (const char *name,
/**
- * Parse given JSON object to absolute time.
+ * Parse given JSON object to an encrypted contract.
*
* @param cls closure, NULL
* @param root the json object representing data
@@ -306,43 +366,64 @@ TALER_JSON_spec_absolute_time (const char *name,
* @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
*/
static enum GNUNET_GenericReturnValue
-parse_abs_time_nbo (void *cls,
- json_t *root,
- struct GNUNET_JSON_Specification *spec)
+parse_econtract (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
{
- struct GNUNET_TIME_AbsoluteNBO *abs = spec->ptr;
- struct GNUNET_TIME_Absolute a;
- struct GNUNET_JSON_Specification ispec;
+ struct TALER_EncryptedContract *econtract = spec->ptr;
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_varsize ("econtract",
+ &econtract->econtract,
+ &econtract->econtract_size),
+ GNUNET_JSON_spec_fixed_auto ("econtract_sig",
+ &econtract->econtract_sig),
+ GNUNET_JSON_spec_fixed_auto ("contract_pub",
+ &econtract->contract_pub),
+ GNUNET_JSON_spec_end ()
+ };
+ const char *emsg;
+ unsigned int eline;
(void) cls;
- ispec = *spec;
- ispec.parser = &parse_abs_time;
- ispec.ptr = &a;
if (GNUNET_OK !=
- parse_abs_time (NULL,
- root,
- &ispec))
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- *abs = GNUNET_TIME_absolute_hton (a);
return GNUNET_OK;
}
+/**
+ * Cleanup data left from parsing encrypted contract.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_econtract (void *cls,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_EncryptedContract *econtract = spec->ptr;
+
+ (void) cls;
+ GNUNET_free (econtract->econtract);
+}
+
+
struct GNUNET_JSON_Specification
-TALER_JSON_spec_absolute_time_nbo (const char *name,
- struct GNUNET_TIME_AbsoluteNBO *r_time)
+TALER_JSON_spec_econtract (const char *name,
+ struct TALER_EncryptedContract *econtract)
{
struct GNUNET_JSON_Specification ret = {
- .parser = &parse_abs_time_nbo,
- .cleaner = NULL,
- .cls = NULL,
+ .parser = &parse_econtract,
+ .cleaner = &clean_econtract,
.field = name,
- .ptr = r_time,
- .ptr_size = sizeof(struct GNUNET_TIME_AbsoluteNBO),
- .size_ptr = NULL
+ .ptr = econtract
};
return ret;
@@ -350,7 +431,7 @@ TALER_JSON_spec_absolute_time_nbo (const char *name,
/**
- * Parse given JSON object to relative time.
+ * Parse given JSON object to an age commitmnet
*
* @param cls closure, NULL
* @param root the json object representing data
@@ -358,70 +439,93 @@ TALER_JSON_spec_absolute_time_nbo (const char *name,
* @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
*/
static enum GNUNET_GenericReturnValue
-parse_rel_time (void *cls,
- json_t *root,
- struct GNUNET_JSON_Specification *spec)
+parse_age_commitment (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
{
- struct GNUNET_TIME_Relative *rel = spec->ptr;
- json_t *json_d_ms;
- unsigned long long int tval;
+ struct TALER_AgeCommitment *age_commitment = spec->ptr;
+ json_t *pk;
+ unsigned int idx;
+ size_t num;
(void) cls;
- if (! json_is_object (root))
+ if ( (NULL == root) ||
+ (! json_is_array (root)))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- json_d_ms = json_object_get (root, "d_ms");
- if (json_is_integer (json_d_ms))
+
+ num = json_array_size (root);
+ if (32 <= num || 0 == num)
{
- tval = json_integer_value (json_d_ms);
- /* Time is in milliseconds in JSON, but in microseconds in GNUNET_TIME_Absolute */
- rel->rel_value_us = tval * 1000LL;
- if ((rel->rel_value_us) / 1000LL != tval)
- {
- /* Integer overflow */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
+ 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_TIME_round_rel (rel))
+ GNUNET_JSON_parse (pk,
+ pkspec,
+ &emsg,
+ &eline))
{
- /* time not rounded */
GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
- return GNUNET_OK;
- }
- if (json_is_string (json_d_ms))
- {
- const char *val;
- val = json_string_value (json_d_ms);
- if ((0 == strcasecmp (val, "forever")))
- {
- *rel = GNUNET_TIME_UNIT_FOREVER_REL;
- return GNUNET_OK;
- }
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
+ };
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Cleanup data left from 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_relative_time (const char *name,
- struct GNUNET_TIME_Relative *r_time)
+TALER_JSON_spec_age_commitment (const char *name,
+ struct TALER_AgeCommitment *age_commitment)
{
struct GNUNET_JSON_Specification ret = {
- .parser = &parse_rel_time,
- .cleaner = NULL,
- .cls = NULL,
+ .parser = &parse_age_commitment,
+ .cleaner = &clean_age_commitment,
.field = name,
- .ptr = r_time,
- .ptr_size = sizeof(struct GNUNET_TIME_Relative),
- .size_ptr = NULL
+ .ptr = age_commitment
};
return ret;
@@ -442,12 +546,16 @@ parse_denom_pub (void *cls,
struct GNUNET_JSON_Specification *spec)
{
struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
- uint32_t cipher;
+ struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
+ const char *cipher;
+ bool age_mask_missing = false;
struct GNUNET_JSON_Specification dspec[] = {
- GNUNET_JSON_spec_uint32 ("cipher",
+ GNUNET_JSON_spec_string ("cipher",
&cipher),
- GNUNET_JSON_spec_uint32 ("age_mask",
- &denom_pub->age_mask.mask),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_uint32 ("age_mask",
+ &denom_pub->age_mask.bits),
+ &age_mask_missing),
GNUNET_JSON_spec_end ()
};
const char *emsg;
@@ -463,15 +571,22 @@ parse_denom_pub (void *cls,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- denom_pub->cipher = (enum TALER_DenominationCipher) cipher;
- switch (denom_pub->cipher)
+
+ if (age_mask_missing)
+ denom_pub->age_mask.bits = 0;
+ bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
+ bsign_pub->rc = 1;
+ bsign_pub->cipher = string_to_cipher (cipher);
+ switch (bsign_pub->cipher)
{
- case TALER_DENOMINATION_RSA:
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
{
struct GNUNET_JSON_Specification ispec[] = {
GNUNET_JSON_spec_rsa_public_key (
"rsa_public_key",
- &denom_pub->details.rsa_public_key),
+ &bsign_pub->details.rsa_public_key),
GNUNET_JSON_spec_end ()
};
@@ -482,14 +597,38 @@ parse_denom_pub (void *cls,
&eline))
{
GNUNET_break_op (0);
+ GNUNET_free (bsign_pub);
return GNUNET_SYSERR;
}
+ denom_pub->bsign_pub_key = bsign_pub;
+ return GNUNET_OK;
+ }
+ case GNUNET_CRYPTO_BSA_CS:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_fixed ("cs_public_key",
+ &bsign_pub->details.cs_public_key,
+ sizeof (bsign_pub->details.cs_public_key)),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (bsign_pub);
+ return GNUNET_SYSERR;
+ }
+ denom_pub->bsign_pub_key = bsign_pub;
return GNUNET_OK;
}
- default:
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
}
+ GNUNET_break_op (0);
+ GNUNET_free (bsign_pub);
+ return GNUNET_SYSERR;
}
@@ -521,6 +660,105 @@ TALER_JSON_spec_denom_pub (const char *field,
.ptr = pk
};
+ pk->bsign_pub_key = NULL;
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object partially into a denomination public key.
+ *
+ * Depending on the cipher in cls, it parses the corresponding public key type.
+ *
+ * @param cls closure, enum GNUNET_CRYPTO_BlindSignatureAlgorithm
+ * @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_denom_pub_cipher (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
+ enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher =
+ (enum GNUNET_CRYPTO_BlindSignatureAlgorithm) (long) cls;
+ struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
+ const char *emsg;
+ unsigned int eline;
+
+ bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
+ bsign_pub->cipher = cipher;
+ bsign_pub->rc = 1;
+ switch (cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_rsa_public_key (
+ "rsa_pub",
+ &bsign_pub->details.rsa_public_key),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (bsign_pub);
+ return GNUNET_SYSERR;
+ }
+ denom_pub->bsign_pub_key = bsign_pub;
+ return GNUNET_OK;
+ }
+ case GNUNET_CRYPTO_BSA_CS:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_fixed ("cs_pub",
+ &bsign_pub->details.cs_public_key,
+ sizeof (bsign_pub->details.cs_public_key)),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (bsign_pub);
+ return GNUNET_SYSERR;
+ }
+ denom_pub->bsign_pub_key = bsign_pub;
+ return GNUNET_OK;
+ }
+ }
+ GNUNET_break_op (0);
+ GNUNET_free (bsign_pub);
+ return GNUNET_SYSERR;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_denom_pub_cipher (const char *field,
+ enum GNUNET_CRYPTO_BlindSignatureAlgorithm
+ cipher,
+ struct TALER_DenominationPublicKey *pk)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_denom_pub_cipher,
+ .cleaner = &clean_denom_pub,
+ .field = field,
+ .cls = (void *) cipher,
+ .ptr = pk
+ };
+
return ret;
}
@@ -539,9 +777,10 @@ parse_denom_sig (void *cls,
struct GNUNET_JSON_Specification *spec)
{
struct TALER_DenominationSignature *denom_sig = spec->ptr;
- uint32_t cipher;
+ struct GNUNET_CRYPTO_UnblindedSignature *unblinded_sig;
+ const char *cipher;
struct GNUNET_JSON_Specification dspec[] = {
- GNUNET_JSON_spec_uint32 ("cipher",
+ GNUNET_JSON_spec_string ("cipher",
&cipher),
GNUNET_JSON_spec_end ()
};
@@ -558,15 +797,19 @@ parse_denom_sig (void *cls,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- denom_sig->cipher = (enum TALER_DenominationCipher) cipher;
- switch (denom_sig->cipher)
+ unblinded_sig = GNUNET_new (struct GNUNET_CRYPTO_UnblindedSignature);
+ unblinded_sig->cipher = string_to_cipher (cipher);
+ unblinded_sig->rc = 1;
+ switch (unblinded_sig->cipher)
{
- case TALER_DENOMINATION_RSA:
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
{
struct GNUNET_JSON_Specification ispec[] = {
GNUNET_JSON_spec_rsa_signature (
"rsa_signature",
- &denom_sig->details.rsa_signature),
+ &unblinded_sig->details.rsa_signature),
GNUNET_JSON_spec_end ()
};
@@ -577,14 +820,41 @@ parse_denom_sig (void *cls,
&eline))
{
GNUNET_break_op (0);
+ GNUNET_free (unblinded_sig);
return GNUNET_SYSERR;
}
+ denom_sig->unblinded_sig = unblinded_sig;
+ return GNUNET_OK;
+ }
+ case GNUNET_CRYPTO_BSA_CS:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_fixed_auto ("cs_signature_r",
+ &unblinded_sig->details.cs_signature.
+ r_point),
+ GNUNET_JSON_spec_fixed_auto ("cs_signature_s",
+ &unblinded_sig->details.cs_signature.
+ s_scalar),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (unblinded_sig);
+ return GNUNET_SYSERR;
+ }
+ denom_sig->unblinded_sig = unblinded_sig;
return GNUNET_OK;
}
- default:
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
}
+ GNUNET_break_op (0);
+ GNUNET_free (unblinded_sig);
+ return GNUNET_SYSERR;
}
@@ -616,6 +886,7 @@ TALER_JSON_spec_denom_sig (const char *field,
.ptr = sig
};
+ sig->unblinded_sig = NULL;
return ret;
}
@@ -634,9 +905,10 @@ parse_blinded_denom_sig (void *cls,
struct GNUNET_JSON_Specification *spec)
{
struct TALER_BlindedDenominationSignature *denom_sig = spec->ptr;
- uint32_t cipher;
+ struct GNUNET_CRYPTO_BlindedSignature *blinded_sig;
+ const char *cipher;
struct GNUNET_JSON_Specification dspec[] = {
- GNUNET_JSON_spec_uint32 ("cipher",
+ GNUNET_JSON_spec_string ("cipher",
&cipher),
GNUNET_JSON_spec_end ()
};
@@ -653,15 +925,19 @@ parse_blinded_denom_sig (void *cls,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- denom_sig->cipher = (enum TALER_DenominationCipher) cipher;
- switch (denom_sig->cipher)
+ blinded_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
+ blinded_sig->cipher = string_to_cipher (cipher);
+ blinded_sig->rc = 1;
+ switch (blinded_sig->cipher)
{
- case TALER_DENOMINATION_RSA:
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
{
struct GNUNET_JSON_Specification ispec[] = {
GNUNET_JSON_spec_rsa_signature (
"blinded_rsa_signature",
- &denom_sig->details.blinded_rsa_signature),
+ &blinded_sig->details.blinded_rsa_signature),
GNUNET_JSON_spec_end ()
};
@@ -672,14 +948,40 @@ parse_blinded_denom_sig (void *cls,
&eline))
{
GNUNET_break_op (0);
+ GNUNET_free (blinded_sig);
return GNUNET_SYSERR;
}
+ denom_sig->blinded_sig = blinded_sig;
+ return GNUNET_OK;
+ }
+ case GNUNET_CRYPTO_BSA_CS:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_uint32 ("b",
+ &blinded_sig->details.blinded_cs_answer.b),
+ GNUNET_JSON_spec_fixed_auto ("s",
+ &blinded_sig->details.blinded_cs_answer.
+ s_scalar),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (blinded_sig);
+ return GNUNET_SYSERR;
+ }
+ denom_sig->blinded_sig = blinded_sig;
return GNUNET_OK;
}
- default:
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
}
+ GNUNET_break_op (0);
+ GNUNET_free (blinded_sig);
+ return GNUNET_SYSERR;
}
@@ -712,6 +1014,253 @@ TALER_JSON_spec_blinded_denom_sig (
.ptr = sig
};
+ sig->blinded_sig = NULL;
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object to blinded planchet.
+ *
+ * @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_blinded_planchet (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_BlindedPlanchet *blinded_planchet = spec->ptr;
+ struct GNUNET_CRYPTO_BlindedMessage *blinded_message;
+ const char *cipher;
+ struct GNUNET_JSON_Specification dspec[] = {
+ GNUNET_JSON_spec_string ("cipher",
+ &cipher),
+ GNUNET_JSON_spec_end ()
+ };
+ const char *emsg;
+ unsigned int eline;
+
+ (void) cls;
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ dspec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ blinded_message = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage);
+ blinded_message->rc = 1;
+ blinded_message->cipher = string_to_cipher (cipher);
+ switch (blinded_message->cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_varsize (
+ "rsa_blinded_planchet",
+ &blinded_message->details.rsa_blinded_message.blinded_msg,
+ &blinded_message->details.rsa_blinded_message.blinded_msg_size),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (blinded_message);
+ return GNUNET_SYSERR;
+ }
+ blinded_planchet->blinded_message = blinded_message;
+ return GNUNET_OK;
+ }
+ case GNUNET_CRYPTO_BSA_CS:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_fixed_auto (
+ "cs_nonce",
+ &blinded_message->details.cs_blinded_message.nonce),
+ GNUNET_JSON_spec_fixed_auto (
+ "cs_blinded_c0",
+ &blinded_message->details.cs_blinded_message.c[0]),
+ GNUNET_JSON_spec_fixed_auto (
+ "cs_blinded_c1",
+ &blinded_message->details.cs_blinded_message.c[1]),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (blinded_message);
+ return GNUNET_SYSERR;
+ }
+ blinded_planchet->blinded_message = blinded_message;
+ return GNUNET_OK;
+ }
+ }
+ GNUNET_break_op (0);
+ GNUNET_free (blinded_message);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Cleanup data left from parsing blinded planchet.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_blinded_planchet (void *cls,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_BlindedPlanchet *blinded_planchet = spec->ptr;
+
+ (void) cls;
+ TALER_blinded_planchet_free (blinded_planchet);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_blinded_planchet (const char *field,
+ struct TALER_BlindedPlanchet *blinded_planchet)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_blinded_planchet,
+ .cleaner = &clean_blinded_planchet,
+ .field = field,
+ .ptr = blinded_planchet
+ };
+
+ blinded_planchet->blinded_message = NULL;
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object to exchange withdraw values (/csr).
+ *
+ * @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_exchange_withdraw_values (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_ExchangeWithdrawValues *ewv = spec->ptr;
+ struct GNUNET_CRYPTO_BlindingInputValues *bi;
+ const char *cipher;
+ struct GNUNET_JSON_Specification dspec[] = {
+ GNUNET_JSON_spec_string ("cipher",
+ &cipher),
+ GNUNET_JSON_spec_end ()
+ };
+ const char *emsg;
+ unsigned int eline;
+ enum GNUNET_CRYPTO_BlindSignatureAlgorithm ci;
+
+ (void) cls;
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ dspec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ ci = string_to_cipher (cipher);
+ switch (ci)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ ewv->blinding_inputs = TALER_denom_ewv_rsa_singleton ()->blinding_inputs;
+ return GNUNET_OK;
+ case GNUNET_CRYPTO_BSA_CS:
+ bi = GNUNET_new (struct GNUNET_CRYPTO_BlindingInputValues);
+ bi->cipher = GNUNET_CRYPTO_BSA_CS;
+ bi->rc = 1;
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_fixed (
+ "r_pub_0",
+ &bi->details.cs_values.r_pub[0],
+ sizeof (struct GNUNET_CRYPTO_CsRPublic)),
+ GNUNET_JSON_spec_fixed (
+ "r_pub_1",
+ &bi->details.cs_values.r_pub[1],
+ sizeof (struct GNUNET_CRYPTO_CsRPublic)),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (bi);
+ return GNUNET_SYSERR;
+ }
+ ewv->blinding_inputs = bi;
+ return GNUNET_OK;
+ }
+ }
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Cleanup data left from parsing withdraw values
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_exchange_withdraw_values (
+ void *cls,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_ExchangeWithdrawValues *ewv = spec->ptr;
+
+ (void) cls;
+ TALER_denom_ewv_free (ewv);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_exchange_withdraw_values (
+ const char *field,
+ struct TALER_ExchangeWithdrawValues *ewv)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_exchange_withdraw_values,
+ .cleaner = &clean_exchange_withdraw_values,
+ .field = field,
+ .ptr = ewv
+ };
+
+ ewv->blinding_inputs = NULL;
return ret;
}
@@ -788,11 +1337,6 @@ parse_i18n_string (void *cls,
const char *str;
str = json_string_value (val);
- if (NULL == str)
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
*(const char **) spec->ptr = str;
}
return GNUNET_OK;
@@ -812,8 +1356,11 @@ i18n_cleaner (void *cls,
struct I18nContext *ctx = cls;
(void) spec;
- GNUNET_free (ctx->lp);
- GNUNET_free (ctx);
+ if (NULL != ctx)
+ {
+ GNUNET_free (ctx->lp);
+ GNUNET_free (ctx);
+ }
}
@@ -833,8 +1380,9 @@ TALER_JSON_spec_i18n_string (const char *name,
.size_ptr = NULL
};
- ctx->lp = (NULL != language_pattern) ? GNUNET_strdup (language_pattern) :
- NULL;
+ ctx->lp = (NULL != language_pattern)
+ ? GNUNET_strdup (language_pattern)
+ : NULL;
ctx->field = name;
*strptr = NULL;
return ret;
@@ -872,4 +1420,400 @@ TALER_JSON_spec_i18n_str (const char *name,
}
+/**
+ * Parse given JSON object with Taler error code.
+ *
+ * @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_ec (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ enum TALER_ErrorCode *ec = spec->ptr;
+ json_int_t num;
+
+ (void) cls;
+ if (! json_is_integer (root))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ num = json_integer_value (root);
+ if (num < 0)
+ {
+ GNUNET_break_op (0);
+ *ec = TALER_EC_INVALID;
+ return GNUNET_SYSERR;
+ }
+ *ec = (enum TALER_ErrorCode) num;
+ return GNUNET_OK;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_ec (const char *field,
+ enum TALER_ErrorCode *ec)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_ec,
+ .field = field,
+ .ptr = ec
+ };
+
+ *ec = TALER_EC_NONE;
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object with AML decision.
+ *
+ * @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_aml_decision (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ enum TALER_AmlDecisionState *aml = spec->ptr;
+ json_int_t num;
+
+ (void) cls;
+ if (! json_is_integer (root))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ num = json_integer_value (root);
+ if ( (num > TALER_AML_MAX) ||
+ (num < 0) )
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ *aml = (enum TALER_AmlDecisionState) num;
+ return GNUNET_OK;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_aml_decision (const char *field,
+ enum TALER_AmlDecisionState *aml_state)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_aml_decision,
+ .field = field,
+ .ptr = aml_state
+ };
+
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object to web URL.
+ *
+ * @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_web_url (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ const char *str;
+
+ (void) cls;
+ str = json_string_value (root);
+ if (NULL == str)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (! TALER_is_web_url (str))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ *(const char **) spec->ptr = str;
+ return GNUNET_OK;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_web_url (const char *field,
+ const char **url)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_web_url,
+ .field = field,
+ .ptr = url
+ };
+
+ *url = NULL;
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object to payto:// URI.
+ *
+ * @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_payto_uri (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ const char *str;
+ char *err;
+
+ (void) cls;
+ str = json_string_value (root);
+ if (NULL == str)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ err = TALER_payto_validate (str);
+ if (NULL != err)
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (err);
+ return GNUNET_SYSERR;
+ }
+ *(const char **) spec->ptr = str;
+ return GNUNET_OK;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_payto_uri (const char *field,
+ const char **payto_uri)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_payto_uri,
+ .field = field,
+ .ptr = payto_uri
+ };
+
+ *payto_uri = NULL;
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object with protocol version.
+ *
+ * @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_protocol_version (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_JSON_ProtocolVersion *pv = spec->ptr;
+ const char *ver;
+ char dummy;
+
+ (void) cls;
+ if (! json_is_string (root))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ ver = json_string_value (root);
+ if (3 != sscanf (ver,
+ "%u:%u:%u%c",
+ &pv->current,
+ &pv->revision,
+ &pv->age,
+ &dummy))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_version (const char *field,
+ struct TALER_JSON_ProtocolVersion *ver)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_protocol_version,
+ .field = field,
+ .ptr = ver
+ };
+
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object to an OTP key.
+ *
+ * @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_otp_key (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ const char *pos_key;
+
+ (void) cls;
+ pos_key = json_string_value (root);
+ if (NULL == pos_key)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ {
+ size_t pos_key_length = strlen (pos_key);
+ void *key; /* pos_key in binary */
+ size_t key_len; /* length of the key */
+ int dret;
+
+ key_len = pos_key_length * 5 / 8;
+ key = GNUNET_malloc (key_len);
+ dret = TALER_rfc3548_base32decode (pos_key,
+ pos_key_length,
+ key,
+ key_len);
+ if (-1 == dret)
+ {
+ GNUNET_free (key);
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (key);
+ }
+ *(const char **) spec->ptr = pos_key;
+ return GNUNET_OK;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_otp_key (const char *name,
+ const char **otp_key)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_otp_key,
+ .field = name,
+ .ptr = otp_key
+ };
+
+ *otp_key = NULL;
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object to `enum TALER_MerchantConfirmationAlgorithm`
+ *
+ * @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_otp_type (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ static const struct Entry
+ {
+ const char *name;
+ enum TALER_MerchantConfirmationAlgorithm val;
+ } lt [] = {
+ { .name = "NONE",
+ .val = TALER_MCA_NONE },
+ { .name = "TOTP_WITHOUT_PRICE",
+ .val = TALER_MCA_WITHOUT_PRICE },
+ { .name = "TOTP_WITH_PRICE",
+ .val = TALER_MCA_WITH_PRICE },
+ { .name = NULL,
+ .val = TALER_MCA_NONE },
+ };
+ enum TALER_MerchantConfirmationAlgorithm *res
+ = (enum TALER_MerchantConfirmationAlgorithm *) spec->ptr;
+
+ (void) cls;
+ if (json_is_string (root))
+ {
+ const char *str;
+
+ str = json_string_value (root);
+ if (NULL == str)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ for (unsigned int i = 0; NULL != lt[i].name; i++)
+ {
+ if (0 == strcasecmp (str,
+ lt[i].name))
+ {
+ *res = lt[i].val;
+ return GNUNET_OK;
+ }
+ }
+ GNUNET_break_op (0);
+ }
+ if (json_is_integer (root))
+ {
+ json_int_t val;
+
+ val = json_integer_value (root);
+ for (unsigned int i = 0; NULL != lt[i].name; i++)
+ {
+ if (val == lt[i].val)
+ {
+ *res = lt[i].val;
+ return GNUNET_OK;
+ }
+ }
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_otp_type (const char *name,
+ enum TALER_MerchantConfirmationAlgorithm *mca)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_otp_type,
+ .field = name,
+ .ptr = mca
+ };
+
+ *mca = TALER_MCA_NONE;
+ return ret;
+}
+
+
/* end of json/json_helper.c */