This commit is contained in:
Christian Grothoff 2021-05-09 13:41:23 +02:00
parent 6ee58c990c
commit 684a234264
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
2 changed files with 163 additions and 4 deletions

View File

@ -17,6 +17,7 @@
* @file json/json.c * @file json/json.c
* @brief helper functions for JSON processing using libjansson * @brief helper functions for JSON processing using libjansson
* @author Sree Harsha Totakura <sreeharsha@totakura.in> * @author Sree Harsha Totakura <sreeharsha@totakura.in>
* @author Christian Grothoff
*/ */
#include "platform.h" #include "platform.h"
#include <gnunet/gnunet_util_lib.h> #include <gnunet/gnunet_util_lib.h>
@ -24,6 +25,41 @@
#include "taler_json_lib.h" #include "taler_json_lib.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. * Dump the @a json to a string and hash it.
* *
@ -41,7 +77,16 @@ dump_and_hash (const json_t *json,
char *wire_enc; char *wire_enc;
size_t len; size_t len;
GNUNET_break (NULL != json); if (NULL == json)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
if (contains_real (json))
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
if (NULL == (wire_enc = json_dumps (json, if (NULL == (wire_enc = json_dumps (json,
JSON_ENCODE_ANY JSON_ENCODE_ANY
| JSON_COMPACT | JSON_COMPACT
@ -79,7 +124,7 @@ dump_and_hash (const json_t *json,
/** /**
* Replace "forgettable" parts of a JSON object with its salted hash. * Replace "forgettable" parts of a JSON object with their salted hash.
* *
* @param[in] in some JSON value * @param[in] in some JSON value
* @return NULL on error * @return NULL on error
@ -87,6 +132,12 @@ dump_and_hash (const json_t *json,
static json_t * static json_t *
forget (const json_t *in) forget (const json_t *in)
{ {
if (json_is_real (in))
{
/* floating point is not allowed! */
GNUNET_break (0);
return NULL;
}
if (json_is_array (in)) if (json_is_array (in))
{ {
/* array is a JSON array */ /* array is a JSON array */
@ -202,6 +253,16 @@ forget (const json_t *in)
return NULL; return NULL;
} }
json_decref (t); json_decref (t);
/* scrub salt */
if (0 !=
json_object_del (fg,
key))
{
GNUNET_break (0);
json_decref (ret);
json_decref (rx);
return NULL;
}
if (NULL == rx) if (NULL == rx)
rx = json_object (); rx = json_object ();
if (NULL == rx) if (NULL == rx)
@ -268,8 +329,11 @@ TALER_JSON_contract_hash (const json_t *json,
{ {
int ret; int ret;
json_t *cjson; json_t *cjson;
json_t *dc;
cjson = forget (json); dc = json_deep_copy (json);
cjson = forget (dc);
json_decref (dc);
if (NULL == cjson) if (NULL == cjson)
{ {
GNUNET_break (0); GNUNET_break (0);
@ -295,9 +359,26 @@ TALER_JSON_contract_mark_forgettable (json_t *json,
GNUNET_break (0); GNUNET_break (0);
return GNUNET_SYSERR; 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, if (NULL == json_object_get (json,
field)) field))
{ {
/* field must exist */
GNUNET_break (0); GNUNET_break (0);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
@ -335,7 +416,7 @@ int
TALER_JSON_contract_part_forget (json_t *json, TALER_JSON_contract_part_forget (json_t *json,
const char *field) const char *field)
{ {
const json_t *fg; json_t *fg;
const json_t *part; const json_t *part;
json_t *fp; json_t *fp;
json_t *rx; json_t *rx;
@ -391,6 +472,15 @@ TALER_JSON_contract_part_forget (json_t *json,
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
json_decref (fp); json_decref (fp);
/* drop salt */
if (0 !=
json_object_del (fg,
field))
{
json_decref (fp);
GNUNET_break (0);
return GNUNET_SYSERR;
}
rx = json_object_get (json, rx = json_object_get (json,
"_forgotten"); "_forgotten");

View File

@ -104,12 +104,49 @@ test_contract (void)
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_JSON_contract_mark_forgettable (c1, TALER_JSON_contract_mark_forgettable (c1,
"k1")); "k1"));
GNUNET_assert (GNUNET_OK ==
TALER_JSON_contract_mark_forgettable (c1,
"k2"));
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_JSON_contract_hash (c1, TALER_JSON_contract_hash (c1,
&h1)); &h1));
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_JSON_contract_part_forget (c1, TALER_JSON_contract_part_forget (c1,
"k1")); "k1"));
/* check salt was forgotten */
GNUNET_assert (NULL ==
json_object_get (json_object_get (c1,
"_forgettable"),
"k1"));
GNUNET_assert (GNUNET_OK ==
TALER_JSON_contract_hash (c1,
&h2));
if (0 !=
GNUNET_memcmp (&h1,
&h2))
{
GNUNET_break (0);
json_decref (c1);
return 1;
}
GNUNET_assert (GNUNET_OK ==
TALER_JSON_contract_part_forget (json_object_get (c1,
"k2"),
"n1"));
GNUNET_assert (GNUNET_OK ==
TALER_JSON_contract_hash (c1,
&h2));
if (0 !=
GNUNET_memcmp (&h1,
&h2))
{
GNUNET_break (0);
json_decref (c1);
return 1;
}
GNUNET_assert (GNUNET_OK ==
TALER_JSON_contract_part_forget (c1,
"k2"));
GNUNET_assert (GNUNET_OK == GNUNET_assert (GNUNET_OK ==
TALER_JSON_contract_hash (c1, TALER_JSON_contract_hash (c1,
&h2)); &h2));
@ -121,6 +158,38 @@ test_contract (void)
GNUNET_break (0); GNUNET_break (0);
return 1; return 1;
} }
c1 = json_pack ("{s:I, s:{s:s}, s:{s:b, s:{s:s}}, s:{s:s}}",
"k1", 1,
"_forgettable", "k1", "SALT",
"k2", "n1", true,
/***/ "_forgettable", "n1", "salt",
"k3", "n1", "string");
GNUNET_assert (GNUNET_OK ==
TALER_JSON_contract_hash (c1,
&h1));
json_dumpf (c1, stderr, JSON_INDENT (2));
json_decref (c1);
{
char *s;
s = GNUNET_STRINGS_data_to_string_alloc (&h1,
sizeof (h1));
if (0 !=
strcmp (s,
"287VXK8T6PXKD05W8Y94QJNEFCMRXBC9S7KNKTWGH2G2J2D7RYKPSHNH1HG9NT1K2HRHGC67W6QM6GEC4BSN1DPNEBCS0AVDT2DBP5G"))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Invalid reference hash: %s\n",
s);
GNUNET_free (s);
return 1;
}
GNUNET_free (s);
}
c2 = json_pack ("{s:s}", c2 = json_pack ("{s:s}",
"n1", "n2"); "n1", "n2");
GNUNET_assert (NULL != c2); GNUNET_assert (NULL != c2);