[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-donau] 01/03: [deps] add json from exchange (can be removed again
From: |
gnunet |
Subject: |
[taler-donau] 01/03: [deps] add json from exchange (can be removed again if json is linked against json from exchange) |
Date: |
Sat, 06 Jan 2024 23:18:10 +0100 |
This is an automated email from the git hooks/post-receive script.
pius-loosli pushed a commit to branch master
in repository donau.
commit afc7557882e41c13ae1c59f29b2292eb696a87dc
Author: Pius Loosli <loosp2@bfh.ch>
AuthorDate: Sat Jan 6 21:36:14 2024 +0100
[deps] add json from exchange (can be removed again if json is linked
against json from exchange)
---
src/json/Makefile.am | 5 +-
src/json/json.c | 763 ++++++++++++++++++++++-
src/json/json_helper.c | 1621 ++++++++++++++++++++++++++++++++++++++++++++++++
src/json/json_pack.c | 324 ++++++++++
4 files changed, 2710 insertions(+), 3 deletions(-)
diff --git a/src/json/Makefile.am b/src/json/Makefile.am
index d952331..8806c67 100644
--- a/src/json/Makefile.am
+++ b/src/json/Makefile.am
@@ -10,7 +10,10 @@ lib_LTLIBRARIES = \
libtalerjson.la
libtalerjson_la_SOURCES = \
- json.c
+ json.c \
+ json_helper.c \
+ json_pack.c
+
libtalerjson_la_LDFLAGS = \
-version-info 1:0:1 \
-no-undefined
diff --git a/src/json/json.c b/src/json/json.c
index e71577b..8c2415c 100644
--- a/src/json/json.c
+++ b/src/json/json.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2023 Taler Systems SA
+ Copyright (C) 2024 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
@@ -21,9 +21,768 @@
*/
#include "taler/platform.h"
#include <gnunet/gnunet_util_lib.h>
-#include <taler/taler_util.h>
+#include "taler/taler_util.h"
#include "taler/taler_json_lib.h"
#include <unistr.h>
+/**
+ * Check if @a json contains a 'real' value anywhere.
+ *
+ * @param json json to check
+ * @return true if a real is in it somewhere
+ */
+static bool
+contains_real (const json_t *json)
+{
+ if (json_is_real (json))
+ return true;
+ if (json_is_object (json))
+ {
+ json_t *member;
+ const char *name;
+
+ json_object_foreach ((json_t *) json, name, member)
+ if (contains_real (member))
+ return true;
+ return false;
+ }
+ if (json_is_array (json))
+ {
+ json_t *member;
+ size_t index;
+
+ json_array_foreach ((json_t *) json, index, member)
+ if (contains_real (member))
+ return true;
+ return false;
+ }
+ return false;
+}
+
+
+/**
+ * Dump the @a json to a string and hash it.
+ *
+ * @param json value to hash
+ * @param salt salt value to include when using HKDF,
+ * NULL to not use any salt and to use SHA512
+ * @param[out] hc where to store the hash
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO if @a json was not hash-able
+ * #GNUNET_SYSERR on failure
+ */
+static enum GNUNET_GenericReturnValue
+dump_and_hash (const json_t *json,
+ const char *salt,
+ struct GNUNET_HashCode *hc)
+{
+ char *wire_enc;
+ size_t len;
+
+ if (NULL == json)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_NO;
+ }
+ if (contains_real (json))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_NO;
+ }
+ if (NULL == (wire_enc = json_dumps (json,
+ JSON_ENCODE_ANY
+ | JSON_COMPACT
+ | JSON_SORT_KEYS)))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ len = TALER_rfc8785encode (&wire_enc);
+ if (NULL == salt)
+ {
+ GNUNET_CRYPTO_hash (wire_enc,
+ len,
+ hc);
+ }
+ else
+ {
+ if (GNUNET_YES !=
+ GNUNET_CRYPTO_kdf (hc,
+ sizeof (*hc),
+ salt,
+ strlen (salt) + 1,
+ wire_enc,
+ len,
+ NULL,
+ 0))
+ {
+ GNUNET_break (0);
+ free (wire_enc);
+ return GNUNET_SYSERR;
+ }
+ }
+ free (wire_enc);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Replace "forgettable" parts of a JSON object with their salted hash.
+ *
+ * @param[in] in some JSON value
+ * @param[out] out resulting JSON value
+ * @return #GNUNET_OK on success,
+ * #GNUNET_NO if @a json was not hash-able
+ * #GNUNET_SYSERR on failure
+ */
+static enum GNUNET_GenericReturnValue
+forget (const json_t *in,
+ json_t **out)
+{
+ if (json_is_real (in))
+ {
+ /* floating point is not allowed! */
+ GNUNET_break_op (0);
+ return GNUNET_NO;
+ }
+ if (json_is_array (in))
+ {
+ /* array is a JSON array */
+ size_t index;
+ json_t *value;
+ json_t *ret;
+
+ ret = json_array ();
+ if (NULL == ret)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ json_array_foreach (in, index, value) {
+ enum GNUNET_GenericReturnValue iret;
+ json_t *t;
+
+ iret = forget (value,
+ &t);
+ if (GNUNET_OK != iret)
+ {
+ json_decref (ret);
+ return iret;
+ }
+ if (0 != json_array_append_new (ret,
+ t))
+ {
+ GNUNET_break (0);
+ json_decref (ret);
+ return GNUNET_SYSERR;
+ }
+ }
+ *out = ret;
+ return GNUNET_OK;
+ }
+ if (json_is_object (in))
+ {
+ json_t *ret;
+ const char *key;
+ json_t *value;
+ json_t *fg;
+ json_t *rx;
+
+ fg = json_object_get (in,
+ "$forgettable");
+ rx = json_object_get (in,
+ "$forgotten");
+ if (NULL != rx)
+ {
+ rx = json_deep_copy (rx); /* should be shallow
+ by structure, but
+ deep copy is safer */
+ if (NULL == rx)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ }
+ ret = json_object ();
+ if (NULL == ret)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ json_object_foreach ((json_t*) in, key, value) {
+ json_t *t;
+ json_t *salt;
+ enum GNUNET_GenericReturnValue iret;
+
+ if (fg == value)
+ continue; /* skip! */
+ if (rx == value)
+ continue; /* skip! */
+ if ( (NULL != rx) &&
+ (NULL !=
+ json_object_get (rx,
+ key)) )
+ {
+ (void) json_object_del (ret,
+ key);
+ continue; /* already forgotten earlier */
+ }
+ iret = forget (value,
+ &t);
+ if (GNUNET_OK != iret)
+ {
+ json_decref (ret);
+ json_decref (rx);
+ return iret;
+ }
+ if ( (NULL != fg) &&
+ (NULL != (salt = json_object_get (fg,
+ key))) )
+ {
+ /* 't' is to be forgotten! */
+ struct GNUNET_HashCode hc;
+
+ if (! json_is_string (salt))
+ {
+ GNUNET_break_op (0);
+ json_decref (ret);
+ json_decref (rx);
+ json_decref (t);
+ return GNUNET_NO;
+ }
+ iret = dump_and_hash (t,
+ json_string_value (salt),
+ &hc);
+ if (GNUNET_OK != iret)
+ {
+ json_decref (ret);
+ json_decref (rx);
+ json_decref (t);
+ return iret;
+ }
+ json_decref (t);
+ /* scrub salt */
+ if (0 !=
+ json_object_del (fg,
+ key))
+ {
+ GNUNET_break_op (0);
+ json_decref (ret);
+ json_decref (rx);
+ return GNUNET_NO;
+ }
+ if (NULL == rx)
+ rx = json_object ();
+ if (NULL == rx)
+ {
+ GNUNET_break (0);
+ json_decref (ret);
+ return GNUNET_SYSERR;
+ }
+ if (0 !=
+ json_object_set_new (rx,
+ key,
+ GNUNET_JSON_from_data_auto (&hc)))
+ {
+ GNUNET_break (0);
+ json_decref (ret);
+ json_decref (rx);
+ return GNUNET_SYSERR;
+ }
+ }
+ else
+ {
+ /* 't' to be used without 'forgetting' */
+ if (0 !=
+ json_object_set_new (ret,
+ key,
+ t))
+ {
+ GNUNET_break (0);
+ json_decref (ret);
+ json_decref (rx);
+ return GNUNET_SYSERR;
+ }
+ }
+ } /* json_object_foreach */
+ if ( (NULL != rx) &&
+ (0 !=
+ json_object_set_new (ret,
+ "$forgotten",
+ rx)) )
+ {
+ GNUNET_break (0);
+ json_decref (ret);
+ return GNUNET_SYSERR;
+ }
+ *out = ret;
+ return GNUNET_OK;
+ }
+ *out = json_incref ((json_t *) in);
+ return GNUNET_OK;
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_JSON_contract_hash (const json_t *json,
+ struct TALER_PrivateContractHashP *hc)
+{
+ enum GNUNET_GenericReturnValue ret;
+ json_t *cjson;
+ json_t *dc;
+
+ dc = json_deep_copy (json);
+ ret = forget (dc,
+ &cjson);
+ json_decref (dc);
+ if (GNUNET_OK != ret)
+ return ret;
+ ret = dump_and_hash (cjson,
+ NULL,
+ &hc->hash);
+ json_decref (cjson);
+ return ret;
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_JSON_contract_mark_forgettable (json_t *json,
+ const char *field)
+{
+ json_t *fg;
+ struct GNUNET_ShortHashCode salt;
+
+ if (! json_is_object (json))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ /* check field name is legal for forgettable field */
+ for (const char *f = field; '\0' != *f; f++)
+ {
+ char c = *f;
+
+ if ( (c >= 'a') && (c <= 'z') )
+ continue;
+ if ( (c >= 'A') && (c <= 'Z') )
+ continue;
+ if ( (c >= '0') && (c <= '9') )
+ continue;
+ if ('_' == c)
+ continue;
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (NULL == json_object_get (json,
+ field))
+ {
+ /* field must exist */
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ fg = json_object_get (json,
+ "$forgettable");
+ if (NULL == fg)
+ {
+ fg = json_object ();
+ if (0 !=
+ json_object_set_new (json,
+ "$forgettable",
+ fg))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ }
+
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+ &salt,
+ sizeof (salt));
+ if (0 !=
+ json_object_set_new (fg,
+ field,
+ GNUNET_JSON_from_data_auto (&salt)))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_JSON_contract_part_forget (json_t *json,
+ const char *field)
+{
+ json_t *fg;
+ const json_t *part;
+ json_t *fp;
+ json_t *rx;
+ struct GNUNET_HashCode hc;
+ const char *salt;
+ enum GNUNET_GenericReturnValue ret;
+
+ if (! json_is_object (json))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (NULL == (part = json_object_get (json,
+ field)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Did not find field `%s' we were asked to forget\n",
+ field);
+ return GNUNET_SYSERR;
+ }
+ fg = json_object_get (json,
+ "$forgettable");
+ if (NULL == fg)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Did not find '$forgettable' attribute trying to forget field
`%s'\n",
+ field);
+ return GNUNET_SYSERR;
+ }
+ rx = json_object_get (json,
+ "$forgotten");
+ if (NULL == rx)
+ {
+ rx = json_object ();
+ if (0 !=
+ json_object_set_new (json,
+ "$forgotten",
+ rx))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ }
+ if (NULL !=
+ json_object_get (rx,
+ field))
+ {
+ if (! json_is_null (json_object_get (json,
+ field)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Field `%s' market as forgotten, but still exists!\n",
+ field);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Already forgot field `%s'\n",
+ field);
+ return GNUNET_NO;
+ }
+ salt = json_string_value (json_object_get (fg,
+ field));
+ if (NULL == salt)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Did not find required salt to forget field `%s'\n",
+ field);
+ return GNUNET_SYSERR;
+ }
+
+ /* need to recursively forget to compute 'hc' */
+ ret = forget (part,
+ &fp);
+ if (GNUNET_OK != ret)
+ return ret;
+ if (GNUNET_OK !=
+ dump_and_hash (fp,
+ salt,
+ &hc))
+ {
+ json_decref (fp);
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ json_decref (fp);
+ /* drop salt */
+ if (0 !=
+ json_object_del (fg,
+ field))
+ {
+ json_decref (fp);
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+
+ /* remember field as 'forgotten' */
+ if (0 !=
+ json_object_set_new (rx,
+ field,
+ GNUNET_JSON_from_data_auto (&hc)))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ /* finally, set 'forgotten' field to null */
+ if (0 !=
+ json_object_del (json,
+ field))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Parse a json path.
+ *
+ * @param obj the object that the path is relative to.
+ * @param prev the parent of @e obj.
+ * @param path the path to parse.
+ * @param cb the callback to call, if we get to the end of @e path.
+ * @param cb_cls the closure for the callback.
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR if @e path is malformed.
+ */
+static enum GNUNET_GenericReturnValue
+parse_path (json_t *obj,
+ json_t *prev,
+ const char *path,
+ TALER_JSON_ExpandPathCallback cb,
+ void *cb_cls)
+{
+ char *id = GNUNET_strdup (path);
+ char *next_id = strchr (id,
+ '.');
+ char *next_path;
+ char *bracket;
+ json_t *next_obj = NULL;
+ char *next_dot;
+
+ GNUNET_assert (NULL != id); /* make stupid compiler happy */
+ if (NULL == next_id)
+ {
+ cb (cb_cls,
+ id,
+ prev);
+ GNUNET_free (id);
+ return GNUNET_OK;
+ }
+ bracket = strchr (next_id,
+ '[');
+ *next_id = '\0';
+ next_id++;
+ next_path = GNUNET_strdup (next_id);
+ next_dot = strchr (next_id,
+ '.');
+ if (NULL != next_dot)
+ *next_dot = '\0';
+ /* If this is the first time this is called, make sure id is "$" */
+ if ( (NULL == prev) &&
+ (0 != strcmp (id,
+ "$")))
+ {
+ GNUNET_free (id);
+ GNUNET_free (next_path);
+ return GNUNET_SYSERR;
+ }
+
+ /* Check for bracketed indices */
+ if (NULL != bracket)
+ {
+ char *end_bracket = strchr (bracket,
+ ']');
+ if (NULL == end_bracket)
+ {
+ GNUNET_free (id);
+ GNUNET_free (next_path);
+ return GNUNET_SYSERR;
+ }
+ *end_bracket = '\0';
+
+ *bracket = '\0';
+ bracket++;
+
+ json_t *array = json_object_get (obj,
+ next_id);
+ if (0 == strcmp (bracket,
+ "*"))
+ {
+ size_t index;
+ json_t *value;
+ int ret = GNUNET_OK;
+
+ json_array_foreach (array, index, value) {
+ ret = parse_path (value,
+ obj,
+ next_path,
+ cb,
+ cb_cls);
+ if (GNUNET_OK != ret)
+ {
+ GNUNET_free (id);
+ GNUNET_free (next_path);
+ return ret;
+ }
+ }
+ }
+ else
+ {
+ unsigned int index;
+ char dummy;
+
+ if (1 != sscanf (bracket,
+ "%u%c",
+ &index,
+ &dummy))
+ {
+ GNUNET_free (id);
+ GNUNET_free (next_path);
+ return GNUNET_SYSERR;
+ }
+ next_obj = json_array_get (array,
+ index);
+ }
+ }
+ else
+ {
+ /* No brackets, so just fetch the object by name */
+ next_obj = json_object_get (obj,
+ next_id);
+ }
+
+ if (NULL != next_obj)
+ {
+ int ret = parse_path (next_obj,
+ obj,
+ next_path,
+ cb,
+ cb_cls);
+ GNUNET_free (id);
+ GNUNET_free (next_path);
+ return ret;
+ }
+ GNUNET_free (id);
+ GNUNET_free (next_path);
+ return GNUNET_OK;
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_JSON_expand_path (json_t *json,
+ const char *path,
+ TALER_JSON_ExpandPathCallback cb,
+ void *cb_cls)
+{
+ return parse_path (json,
+ NULL,
+ path,
+ cb,
+ cb_cls);
+}
+
+
+enum TALER_ErrorCode
+TALER_JSON_get_error_code (const json_t *json)
+{
+ const json_t *jc;
+
+ if (NULL == json)
+ return TALER_EC_GENERIC_INVALID_RESPONSE;
+ jc = json_object_get (json, "code");
+ /* The caller already knows that the JSON represents an error,
+ so we are dealing with a missing error code here. */
+ if (NULL == jc)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Expected Taler error code `code' in JSON, but field does not
exist!\n");
+ return TALER_EC_INVALID;
+ }
+ if (json_is_integer (jc))
+ return (enum TALER_ErrorCode) json_integer_value (jc);
+ GNUNET_break_op (0);
+ return TALER_EC_INVALID;
+}
+
+
+const char *
+TALER_JSON_get_error_hint (const json_t *json)
+{
+ const json_t *jc;
+
+ if (NULL == json)
+ return NULL;
+ jc = json_object_get (json,
+ "hint");
+ if (NULL == jc)
+ return NULL; /* no hint, is allowed */
+ if (! json_is_string (jc))
+ {
+ /* Hints must be strings */
+ GNUNET_break_op (0);
+ return NULL;
+ }
+ return json_string_value (jc);
+}
+
+
+enum TALER_ErrorCode
+TALER_JSON_get_error_code2 (const void *data,
+ size_t data_size)
+{
+ json_t *json;
+ enum TALER_ErrorCode ec;
+ json_error_t err;
+
+ json = json_loadb (data,
+ data_size,
+ JSON_REJECT_DUPLICATES,
+ &err);
+ if (NULL == json)
+ return TALER_EC_INVALID;
+ ec = TALER_JSON_get_error_code (json);
+ json_decref (json);
+ if (ec == TALER_EC_NONE)
+ return TALER_EC_INVALID;
+ return ec;
+}
+
+
+void
+TALER_deposit_policy_hash (const json_t *policy,
+ struct TALER_ExtensionPolicyHashP *ech)
+{
+ GNUNET_assert (GNUNET_OK ==
+ dump_and_hash (policy,
+ "taler-extensions-policy",
+ &ech->hash));
+}
+
+
+char *
+TALER_JSON_canonicalize (const json_t *input)
+{
+ char *wire_enc;
+
+ if (NULL == (wire_enc = json_dumps (input,
+ JSON_ENCODE_ANY
+ | JSON_COMPACT
+ | JSON_SORT_KEYS)))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ TALER_rfc8785encode (&wire_enc);
+ return wire_enc;
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_JSON_extensions_manifests_hash (const json_t *manifests,
+ struct TALER_ExtensionManifestsHashP
*ech)
+{
+ return dump_and_hash (manifests,
+ "taler-extensions-manifests",
+ &ech->hash);
+}
+
+
/* End of json/json.c */
diff --git a/src/json/json_helper.c b/src/json/json_helper.c
new file mode 100644
index 0000000..0126574
--- /dev/null
+++ b/src/json/json_helper.c
@@ -0,0 +1,1621 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2024 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 json/json_helper.c
+ * @brief helper functions to generate specifications to parse
+ * Taler-specific JSON objects with libgnunetjson
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ * @author Christian Grothoff
+ */
+#include "taler/platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler/taler_util.h"
+#include "taler/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)
+{
+ char *amount_str = TALER_amount_to_string (amount);
+
+ GNUNET_assert (NULL != amount_str);
+ {
+ json_t *j = json_string (amount_str);
+
+ GNUNET_free (amount_str);
+ return j;
+ }
+}
+
+
+/**
+ * Parse given JSON object to Amount
+ *
+ * @param cls closure, expected currency, or 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_amount (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ const char *currency = cls;
+ struct TALER_Amount *r_amount = spec->ptr;
+
+ (void) cls;
+ if (! json_is_string (root))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_string_to_amount (json_string_value (root),
+ r_amount))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if ( (NULL != currency) &&
+ (0 !=
+ strcasecmp (currency,
+ 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;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_amount (const char *name,
+ const char *currency,
+ struct TALER_Amount *r_amount)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_amount,
+ .cleaner = NULL,
+ .cls = (void *) currency,
+ .field = name,
+ .ptr = r_amount,
+ .ptr_size = 0,
+ .size_ptr = NULL
+ };
+
+ GNUNET_assert (NULL != currency);
+ return ret;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_amount_any (const char *name,
+ struct TALER_Amount *r_amount)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_amount,
+ .cleaner = NULL,
+ .cls = NULL,
+ .field = name,
+ .ptr = r_amount,
+ .ptr_size = 0,
+ .size_ptr = NULL
+ };
+
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object to currency spec.
+ *
+ * @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_cspec (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ 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;
+
+ 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_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_check_currency (currency))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ 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;
+}
+
+
+/**
+ * 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 TALER_CurrencySpecification *cspec = spec->ptr;
+
+ (void) cls;
+ GNUNET_free (cspec->name);
+ json_decref (cspec->map_alt_unit_names);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_currency_specification (
+ const char *name,
+ const char *currency,
+ struct TALER_CurrencySpecification *r_cspec)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_cspec,
+ .cleaner = &clean_cspec,
+ .cls = (void *) currency,
+ .field = name,
+ .ptr = r_cspec,
+ .ptr_size = sizeof (*r_cspec),
+ .size_ptr = NULL
+ };
+
+ memset (r_cspec,
+ 0,
+ sizeof (*r_cspec));
+ return ret;
+}
+
+
+static enum GNUNET_GenericReturnValue
+parse_denomination_group (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ 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;
+
+ 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;
+ }
+
+ group->cipher = string_to_cipher (cipher);
+ if (GNUNET_CRYPTO_BSA_INVALID == group->cipher)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ /* 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;
+ }
+
+ if (age_mask_missing)
+ group->age_mask.bits = 0;
+
+ return GNUNET_OK;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_denomination_group (const char *name,
+ const char *currency,
+ struct TALER_DenominationGroup *group)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .cls = (void *) currency,
+ .parser = &parse_denomination_group,
+ .field = name,
+ .ptr = group,
+ .ptr_size = sizeof(*group)
+ };
+
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object to an encrypted contract.
+ *
+ * @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_econtract (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ 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;
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ ispec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ 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_econtract (const char *name,
+ struct TALER_EncryptedContract *econtract)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_econtract,
+ .cleaner = &clean_econtract,
+ .field = name,
+ .ptr = econtract
+ };
+
+ return ret;
+}
+
+
+/**
+ * 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;
+
+ (void) cls;
+ 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 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_age_commitment (const char *name,
+ struct TALER_AgeCommitment *age_commitment)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_age_commitment,
+ .cleaner = &clean_age_commitment,
+ .field = name,
+ .ptr = age_commitment
+ };
+
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object to denomination public 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_denom_pub (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
+ struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
+ const char *cipher;
+ bool age_mask_missing = false;
+ struct GNUNET_JSON_Specification dspec[] = {
+ GNUNET_JSON_spec_string ("cipher",
+ &cipher),
+ 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;
+ unsigned int eline;
+
+ (void) cls;
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (root,
+ dspec,
+ &emsg,
+ &eline))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+
+ 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 GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_rsa_public_key (
+ "rsa_public_key",
+ &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_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;
+ }
+ }
+ GNUNET_break_op (0);
+ GNUNET_free (bsign_pub);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Cleanup data left from parsing denomination public key.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_denom_pub (void *cls,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
+
+ (void) cls;
+ TALER_denom_pub_free (denom_pub);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_denom_pub (const char *field,
+ struct TALER_DenominationPublicKey *pk)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_denom_pub,
+ .cleaner = &clean_denom_pub,
+ .field = 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;
+}
+
+
+/**
+ * Parse given JSON object to denomination signature.
+ *
+ * @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_denom_sig (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_DenominationSignature *denom_sig = spec->ptr;
+ struct GNUNET_CRYPTO_UnblindedSignature *unblinded_sig;
+ 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;
+ }
+ unblinded_sig = GNUNET_new (struct GNUNET_CRYPTO_UnblindedSignature);
+ unblinded_sig->cipher = string_to_cipher (cipher);
+ unblinded_sig->rc = 1;
+ switch (unblinded_sig->cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_rsa_signature (
+ "rsa_signature",
+ &unblinded_sig->details.rsa_signature),
+ 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;
+ }
+ 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;
+ }
+ }
+ GNUNET_break_op (0);
+ GNUNET_free (unblinded_sig);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Cleanup data left from parsing denomination public key.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_denom_sig (void *cls,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_DenominationSignature *denom_sig = spec->ptr;
+
+ (void) cls;
+ TALER_denom_sig_free (denom_sig);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_denom_sig (const char *field,
+ struct TALER_DenominationSignature *sig)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_denom_sig,
+ .cleaner = &clean_denom_sig,
+ .field = field,
+ .ptr = sig
+ };
+
+ sig->unblinded_sig = NULL;
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object to blinded denomination signature.
+ *
+ * @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_denom_sig (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_BlindedDenominationSignature *denom_sig = spec->ptr;
+ struct GNUNET_CRYPTO_BlindedSignature *blinded_sig;
+ 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_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
+ blinded_sig->cipher = string_to_cipher (cipher);
+ blinded_sig->rc = 1;
+ switch (blinded_sig->cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ {
+ struct GNUNET_JSON_Specification ispec[] = {
+ GNUNET_JSON_spec_rsa_signature (
+ "blinded_rsa_signature",
+ &blinded_sig->details.blinded_rsa_signature),
+ 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;
+ }
+ 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;
+ }
+ }
+ GNUNET_break_op (0);
+ GNUNET_free (blinded_sig);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Cleanup data left from parsing denomination public key.
+ *
+ * @param cls closure, NULL
+ * @param[out] spec where to free the data
+ */
+static void
+clean_blinded_denom_sig (void *cls,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_BlindedDenominationSignature *denom_sig = spec->ptr;
+
+ (void) cls;
+ TALER_blinded_denom_sig_free (denom_sig);
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_blinded_denom_sig (
+ const char *field,
+ struct TALER_BlindedDenominationSignature *sig)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_blinded_denom_sig,
+ .cleaner = &clean_blinded_denom_sig,
+ .field = field,
+ .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;
+}
+
+
+/**
+ * Closure for #parse_i18n_string.
+ */
+struct I18nContext
+{
+ /**
+ * Language pattern to match.
+ */
+ char *lp;
+
+ /**
+ * Name of the field to match.
+ */
+ const char *field;
+};
+
+
+/**
+ * Parse given JSON object to internationalized string.
+ *
+ * @param cls closure, our `struct I18nContext *`
+ * @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_i18n_string (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct I18nContext *ctx = cls;
+ json_t *i18n;
+ json_t *val;
+
+ {
+ char *i18nf;
+
+ GNUNET_asprintf (&i18nf,
+ "%s_i18n",
+ ctx->field);
+ i18n = json_object_get (root,
+ i18nf);
+ GNUNET_free (i18nf);
+ }
+
+ val = json_object_get (root,
+ ctx->field);
+ if ( (NULL != i18n) &&
+ (NULL != ctx->lp) )
+ {
+ double best = 0.0;
+ json_t *pos;
+ const char *lang;
+
+ json_object_foreach (i18n, lang, pos)
+ {
+ double score;
+
+ score = TALER_language_matches (ctx->lp,
+ lang);
+ if (score > best)
+ {
+ best = score;
+ val = pos;
+ }
+ }
+ }
+
+ {
+ const char *str;
+
+ str = json_string_value (val);
+ *(const char **) spec->ptr = str;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called to clean up data from earlier parsing.
+ *
+ * @param cls closure
+ * @param spec our specification entry with data to clean.
+ */
+static void
+i18n_cleaner (void *cls,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct I18nContext *ctx = cls;
+
+ (void) spec;
+ if (NULL != ctx)
+ {
+ GNUNET_free (ctx->lp);
+ GNUNET_free (ctx);
+ }
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_i18n_string (const char *name,
+ const char *language_pattern,
+ const char **strptr)
+{
+ struct I18nContext *ctx = GNUNET_new (struct I18nContext);
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_i18n_string,
+ .cleaner = &i18n_cleaner,
+ .cls = ctx,
+ .field = NULL, /* we want the main object */
+ .ptr = strptr,
+ .ptr_size = 0,
+ .size_ptr = NULL
+ };
+
+ ctx->lp = (NULL != language_pattern)
+ ? GNUNET_strdup (language_pattern)
+ : NULL;
+ ctx->field = name;
+ *strptr = NULL;
+ return ret;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_i18n_str (const char *name,
+ const char **strptr)
+{
+ const char *lang = getenv ("LANG");
+ char *dot;
+ char *l;
+ struct GNUNET_JSON_Specification ret;
+
+ if (NULL != lang)
+ {
+ dot = strchr (lang,
+ '.');
+ if (NULL == dot)
+ l = GNUNET_strdup (lang);
+ else
+ l = GNUNET_strndup (lang,
+ dot - lang);
+ }
+ else
+ {
+ l = NULL;
+ }
+ ret = TALER_JSON_spec_i18n_string (name,
+ l,
+ strptr);
+ GNUNET_free (l);
+ return ret;
+}
+
+
+/**
+ * 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 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;
+}
+
+
+/* end of json/json_helper.c */
diff --git a/src/json/json_pack.c b/src/json/json_pack.c
new file mode 100644
index 0000000..4357f9f
--- /dev/null
+++ b/src/json/json_pack.c
@@ -0,0 +1,324 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2024 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 json/json_pack.c
+ * @brief helper functions for JSON object packing
+ * @author Christian Grothoff
+ */
+#include "taler/platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler/taler_util.h"
+#include "taler/taler_json_lib.h"
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_time_abs_human (const char *name,
+ struct GNUNET_TIME_Absolute at)
+{
+ struct GNUNET_JSON_PackSpec ps = {
+ .field_name = name,
+ .object = json_string (
+ GNUNET_STRINGS_absolute_time_to_string (at))
+ };
+
+ return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_econtract (
+ const char *name,
+ const struct TALER_EncryptedContract *econtract)
+{
+ struct GNUNET_JSON_PackSpec ps = {
+ .field_name = name,
+ };
+
+ if (NULL == econtract)
+ return ps;
+ ps.object
+ = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_data_varsize ("econtract",
+ econtract->econtract,
+ econtract->econtract_size),
+ GNUNET_JSON_pack_data_auto ("econtract_sig",
+ &econtract->econtract_sig),
+ GNUNET_JSON_pack_data_auto ("contract_pub",
+ &econtract->contract_pub));
+ return ps;
+}
+
+
+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)
+{
+ const struct GNUNET_CRYPTO_BlindSignPublicKey *bsp;
+ struct GNUNET_JSON_PackSpec ps = {
+ .field_name = name,
+ };
+
+ if (NULL == pk)
+ return ps;
+ bsp = pk->bsign_pub_key;
+ switch (bsp->cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ ps.object
+ = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "RSA"),
+ GNUNET_JSON_pack_uint64 ("age_mask",
+ pk->age_mask.bits),
+ GNUNET_JSON_pack_rsa_public_key ("rsa_public_key",
+ bsp->details.rsa_public_key));
+ return ps;
+ case GNUNET_CRYPTO_BSA_CS:
+ ps.object
+ = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "CS"),
+ GNUNET_JSON_pack_uint64 ("age_mask",
+ pk->age_mask.bits),
+ GNUNET_JSON_pack_data_varsize ("cs_public_key",
+ &bsp->details.cs_public_key,
+ sizeof (bsp->details.cs_public_key)));
+ return ps;
+ }
+ GNUNET_assert (0);
+ return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_denom_sig (
+ const char *name,
+ const struct TALER_DenominationSignature *sig)
+{
+ const struct GNUNET_CRYPTO_UnblindedSignature *bs;
+ struct GNUNET_JSON_PackSpec ps = {
+ .field_name = name,
+ };
+
+ if (NULL == sig)
+ return ps;
+ bs = sig->unblinded_sig;
+ switch (bs->cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ ps.object = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "RSA"),
+ GNUNET_JSON_pack_rsa_signature ("rsa_signature",
+ bs->details.rsa_signature));
+ return ps;
+ case GNUNET_CRYPTO_BSA_CS:
+ ps.object = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "CS"),
+ GNUNET_JSON_pack_data_auto ("cs_signature_r",
+ &bs->details.cs_signature.r_point),
+ GNUNET_JSON_pack_data_auto ("cs_signature_s",
+ &bs->details.cs_signature.s_scalar));
+ return ps;
+ }
+ GNUNET_assert (0);
+ return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_exchange_withdraw_values (
+ const char *name,
+ const struct TALER_ExchangeWithdrawValues *ewv)
+{
+ const struct GNUNET_CRYPTO_BlindingInputValues *biv;
+ struct GNUNET_JSON_PackSpec ps = {
+ .field_name = name,
+ };
+
+ if (NULL == ewv)
+ return ps;
+ biv = ewv->blinding_inputs;
+ switch (biv->cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ ps.object = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "RSA"));
+ return ps;
+ case GNUNET_CRYPTO_BSA_CS:
+ ps.object = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "CS"),
+ GNUNET_JSON_pack_data_varsize (
+ "r_pub_0",
+ &biv->details.cs_values.r_pub[0],
+ sizeof(struct GNUNET_CRYPTO_CsRPublic)),
+ GNUNET_JSON_pack_data_varsize (
+ "r_pub_1",
+ &biv->details.cs_values.r_pub[1],
+ sizeof(struct GNUNET_CRYPTO_CsRPublic))
+ );
+ return ps;
+ }
+ GNUNET_assert (0);
+ return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_blinded_denom_sig (
+ const char *name,
+ const struct TALER_BlindedDenominationSignature *sig)
+{
+ const struct GNUNET_CRYPTO_BlindedSignature *bs;
+ struct GNUNET_JSON_PackSpec ps = {
+ .field_name = name,
+ };
+
+ if (NULL == sig)
+ return ps;
+ bs = sig->blinded_sig;
+ switch (bs->cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ ps.object = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "RSA"),
+ GNUNET_JSON_pack_rsa_signature ("blinded_rsa_signature",
+ bs->details.blinded_rsa_signature));
+ return ps;
+ case GNUNET_CRYPTO_BSA_CS:
+ ps.object = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "CS"),
+ GNUNET_JSON_pack_uint64 ("b",
+ bs->details.blinded_cs_answer.b),
+ GNUNET_JSON_pack_data_auto ("s",
+ &bs->details.blinded_cs_answer.s_scalar));
+ return ps;
+ }
+ GNUNET_assert (0);
+ return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_blinded_planchet (
+ const char *name,
+ const struct TALER_BlindedPlanchet *blinded_planchet)
+{
+ const struct GNUNET_CRYPTO_BlindedMessage *bm;
+ struct GNUNET_JSON_PackSpec ps = {
+ .field_name = name,
+ };
+
+ if (NULL == blinded_planchet)
+ return ps;
+ bm = blinded_planchet->blinded_message;
+ switch (bm->cipher)
+ {
+ case GNUNET_CRYPTO_BSA_INVALID:
+ break;
+ case GNUNET_CRYPTO_BSA_RSA:
+ ps.object = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "RSA"),
+ GNUNET_JSON_pack_data_varsize (
+ "rsa_blinded_planchet",
+ bm->details.rsa_blinded_message.blinded_msg,
+ bm->details.rsa_blinded_message.blinded_msg_size));
+ return ps;
+ case GNUNET_CRYPTO_BSA_CS:
+ ps.object = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("cipher",
+ "CS"),
+ GNUNET_JSON_pack_data_auto (
+ "cs_nonce",
+ &bm->details.cs_blinded_message.nonce),
+ GNUNET_JSON_pack_data_auto (
+ "cs_blinded_c0",
+ &bm->details.cs_blinded_message.c[0]),
+ GNUNET_JSON_pack_data_auto (
+ "cs_blinded_c1",
+ &bm->details.cs_blinded_message.c[1]));
+ return ps;
+ }
+ GNUNET_assert (0);
+ return ps;
+}
+
+
+struct GNUNET_JSON_PackSpec
+TALER_JSON_pack_amount (const char *name,
+ const struct TALER_Amount *amount)
+{
+ struct GNUNET_JSON_PackSpec ps = {
+ .field_name = name,
+ .object = (NULL != amount)
+ ? TALER_JSON_from_amount (amount)
+ : NULL
+ };
+
+ return ps;
+}
+
+
+/* End of json/json_pack.c */
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.