From 6680f9b4ef37db66880d774d7dc9f97e7d639f13 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 16 Jun 2021 23:12:21 +0200 Subject: [PATCH] implement logic to replace 'true' forgettable salts with random salts, fix object deletion when forgetting --- src/include/taler_json_lib.h | 13 +++++ src/json/json.c | 98 ++++++++++++++++++++++++++++++++++-- src/json/test_json.c | 15 +++++- 3 files changed, 121 insertions(+), 5 deletions(-) diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h index bf8c22177..aefc28061 100644 --- a/src/include/taler_json_lib.h +++ b/src/include/taler_json_lib.h @@ -198,6 +198,19 @@ TALER_JSON_contract_hash (const json_t *json, struct GNUNET_HashCode *hc); +/** + * Take a given contract with "forgettable" fields marked + * but with 'True' instead of a real salt. Replaces all + * 'True' values with proper random salts. Fails if any + * forgettable markers are neither 'True' nor valid salts. + * + * @param[in,out] json JSON to transform + * @return #GNUNET_OK on success + */ +int +TALER_JSON_contract_seed_forgettable (json_t *json); + + /** * Mark part of a contract object as 'forgettable'. * diff --git a/src/json/json.c b/src/json/json.c index faae36d62..fe2ea8382 100644 --- a/src/json/json.c +++ b/src/json/json.c @@ -506,9 +506,8 @@ TALER_JSON_contract_part_forget (json_t *json, } /* finally, set 'forgotten' field to null */ if (0 != - json_object_set_new (json, - field, - json_null ())) + json_object_del (json, + field)) { GNUNET_break (0); return GNUNET_SYSERR; @@ -517,6 +516,99 @@ TALER_JSON_contract_part_forget (json_t *json, } +/** + * Look over all of the values of a '$forgettable' object. Replace 'True' + * values with proper random salts. Fails if any forgettable values are + * neither 'True' nor valid salts (strings). + * + * @param[in,out] f JSON to transform + * @return #GNUNET_OK on success + */ +static int +seed_forgettable (json_t *f) +{ + const char *key; + json_t *val; + + json_object_foreach (f, + key, + val) + { + if (json_is_string (val)) + continue; + if (json_is_true (val)) + { + struct GNUNET_ShortHashCode sh; + + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, + &sh, + sizeof (sh)); + json_object_set_new (f, + key, + GNUNET_JSON_from_data_auto (&sh)); + continue; + } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Forgettable field `%s' has invalid value\n", + key); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Take a given contract with "forgettable" fields marked + * but with 'True' instead of a real salt. Replaces all + * 'True' values with proper random salts. Fails if any + * forgettable markers are neither 'True' nor valid salts. + * + * @param[in,out] json JSON to transform + * @return #GNUNET_OK on success + */ +int +TALER_JSON_contract_seed_forgettable (json_t *json) +{ + if (json_is_object (json)) + { + const char *key; + json_t *val; + + json_object_foreach (json, + key, + val) + { + if (0 == strcmp ("$forgettable", + key)) + { + if (GNUNET_OK != + seed_forgettable (val)) + return GNUNET_SYSERR; + continue; + } + if (GNUNET_OK != + TALER_JSON_contract_seed_forgettable (val)) + return GNUNET_SYSERR; + } + } + if (json_is_array (json)) + { + size_t index; + json_t *val; + + json_array_foreach (json, + index, + val) + { + if (GNUNET_OK != + TALER_JSON_contract_seed_forgettable (val)) + return GNUNET_SYSERR; + } + } + return GNUNET_OK; +} + + /** * Parse a json path. * diff --git a/src/json/test_json.c b/src/json/test_json.c index b3c36837f..bedea76ac 100644 --- a/src/json/test_json.c +++ b/src/json/test_json.c @@ -96,6 +96,17 @@ test_contract (void) json_t *c3; json_t *c4; + c1 = json_pack ("{s:s, s:{s:s, s:{s:b}}}", + "k1", "v1", + "k2", "n1", "n2", + /***/ "$forgettable", "n1", true); + GNUNET_assert (GNUNET_OK == + TALER_JSON_contract_seed_forgettable (c1)); + GNUNET_assert (GNUNET_OK == + TALER_JSON_contract_hash (c1, + &h1)); + json_decref (c1); + c1 = json_pack ("{s:s, s:{s:s, s:{s:s}}}", "k1", "v1", "k2", "n1", "n2", @@ -147,6 +158,7 @@ test_contract (void) GNUNET_assert (GNUNET_OK == TALER_JSON_contract_part_forget (c1, "k2")); + json_dumpf (c1, stderr, JSON_INDENT (2)); GNUNET_assert (GNUNET_OK == TALER_JSON_contract_hash (c1, &h2)); @@ -159,7 +171,6 @@ test_contract (void) return 1; } - c1 = json_pack ("{s:I, s:{s:s}, s:{s:b, s:{s:s}}, s:{s:s}}", "k1", 1, "$forgettable", "k1", "SALT", @@ -178,7 +189,7 @@ test_contract (void) sizeof (h1)); if (0 != strcmp (s, - "48YVST0SZJXWNG3KAD14SSK3AD0T5V01W5AE6E76DYKMJSC5BQ19M0FZ7CZP5JY26FC4AFXTXRGEVSQ1NSKPQ1DQ4GS9C4SAECG5RZ8")) + "VDE8JPX0AEEE3EX1K8E11RYEWSZQKGGZCV6BWTE4ST1C8711P7H850Z7F2Q2HSSYETX87ERC2JNHWB7GTDWTDWMM716VKPSRBXD7SRR")) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid reference hash: %s\n",