gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-exchange] branch master updated: first draft for #6365, test pend


From: gnunet
Subject: [taler-exchange] branch master updated: first draft for #6365, test pending
Date: Thu, 16 Jul 2020 01:51:52 +0200

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository exchange.

The following commit(s) were added to refs/heads/master by this push:
     new e1ad498b first draft for #6365, test pending
e1ad498b is described below

commit e1ad498bff48c3975b386680493d6f1445582cfa
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Thu Jul 16 01:51:45 2020 +0200

    first draft for #6365, test pending
---
 src/include/taler_json_lib.h |  25 +++
 src/json/json.c              | 402 +++++++++++++++++++++++++++++++++++++++++--
 src/json/test_json.c         |   2 +-
 3 files changed, 417 insertions(+), 12 deletions(-)

diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h
index 8550fd42..cfab56fd 100644
--- a/src/include/taler_json_lib.h
+++ b/src/include/taler_json_lib.h
@@ -158,6 +158,31 @@ int
 TALER_JSON_contract_hash (const json_t *json,
                           struct GNUNET_HashCode *hc);
 
+
+/**
+ * Mark part of a contract object as 'forgettable'.
+ *
+ * @param[in,out] json some JSON object to modify
+ * @param field name of the field to mark as forgettable
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+int
+TALER_JSON_contract_mark_forgettable (json_t *json,
+                                      const char *field);
+
+
+/**
+ * Forget part of a contract object.
+ *
+ * @param[in,out] json some JSON object to modify
+ * @param field name of the field to forget
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+int
+TALER_JSON_contract_part_forget (json_t *json,
+                                 const char *field);
+
+
 /**
  * Extract the Taler error code from the given @a json object.
  * Note that #TALER_EC_NONE is returned if no "code" is present.
diff --git a/src/json/json.c b/src/json/json.c
index a1a2c6fb..4874f0c2 100644
--- a/src/json/json.c
+++ b/src/json/json.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014, 2015, 2016 Taler Systems SA
+  Copyright (C) 2014, 2015, 2016, 2020 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
@@ -25,7 +25,235 @@
 
 
 /**
- * Hash a JSON object for binary signing.
+ * 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_SYSERR on failure
+ */
+static int
+dump_and_hash (const json_t *json,
+               const char *salt,
+               struct GNUNET_HashCode *hc)
+{
+  char *wire_enc;
+  size_t len;
+
+  if (NULL == (wire_enc = json_dumps (json,
+                                      JSON_COMPACT | JSON_SORT_KEYS)))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  len = strlen (wire_enc) + 1;
+  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))
+    {
+      free (wire_enc);
+      return GNUNET_SYSERR;
+    }
+  }
+  free (wire_enc);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Replace "forgettable" parts of a JSON object with its salted hash.
+ *
+ * @param[in] in some JSON value
+ * @return NULL on error
+ */
+static json_t *
+forget (const json_t *in)
+{
+  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 NULL;
+    }
+    json_array_foreach (in, index, value) {
+      json_t *t;
+
+      t = forget (value);
+      if (NULL == t)
+      {
+        GNUNET_break (0);
+        json_decref (ret);
+        return NULL;
+      }
+      if (0 != json_array_append_new (ret, t))
+      {
+        GNUNET_break (0);
+        json_decref (ret);
+        return NULL;
+      }
+    }
+    return ret;
+  }
+  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 */
+    ret = json_object ();
+    if (NULL == ret)
+    {
+      GNUNET_break (0);
+      return NULL;
+    }
+    json_object_foreach ((json_t*) in, key, value) {
+      json_t *t;
+      json_t *salt;
+
+      if (0 == strcmp (key,
+                       "_forgettable"))
+        continue; /* skip! */
+      if (rx == value)
+        continue; /* skip! */
+      t = forget (value);
+      if (NULL == t)
+      {
+        GNUNET_break (0);
+        json_decref (ret);
+        json_decref (rx);
+        return NULL;
+      }
+      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 (0);
+          json_decref (ret);
+          json_decref (rx);
+          return NULL;
+        }
+        if (GNUNET_OK !=
+            dump_and_hash (t,
+                           json_string_value (salt),
+                           &hc))
+        {
+          GNUNET_break (0);
+          json_decref (ret);
+          json_decref (rx);
+          return NULL;
+        }
+        if (NULL == rx)
+          rx = json_object ();
+        if (NULL == rx)
+        {
+          GNUNET_break (0);
+          json_decref (ret);
+          json_decref (rx);
+          return NULL;
+        }
+        if (0 !=
+            json_object_set_new (rx,
+                                 key,
+                                 GNUNET_JSON_from_data_auto (&hc)))
+        {
+          GNUNET_break (0);
+          json_decref (ret);
+          json_decref (rx);
+          return NULL;
+        }
+        if (0 !=
+            json_object_set_new (ret,
+                                 key,
+                                 json_null ()))
+        {
+          GNUNET_break (0);
+          json_decref (ret);
+          json_decref (rx);
+          return NULL;
+        }
+
+      }
+      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 NULL;
+        }
+      }
+    } /* json_object_foreach */
+    if (0 !=
+        json_object_set_new (ret,
+                             "_forgotten",
+                             rx))
+    {
+      GNUNET_break (0);
+      json_decref (ret);
+      return NULL;
+    }
+    return ret;
+  }
+  return json_incref ((json_t *) in);
+}
+
+
+/**
+ * Hash a JSON contract for binary signing.
+ *
+ * Contracts can contain "forgettable" parts. Those components of the JSON
+ * object are indicated in a "_forgettable" field containing key-value
+ * pairs. The keys are the names of other fields that are forgettable, and the
+ * values are salt values to be used in the HKDF when hashing the forgettable
+ * field. To compute the overall hash, the values of all "_forgettable" fields
+ * are replaced with 'null', and the "_forgettable" field itself is removed,
+ * and a special "_forgotten" field is added with a map of forgotten entries
+ * to the respective HKDF values (see also #6365).
+ *
+ * Forgetting parts is not only applied at the top-level entry of the
+ * contract, but recursively to all entries.
  *
  * See 
https://tools.ietf.org/html/draft-rundgren-json-canonicalization-scheme-15
  * for fun JSON canonicalization problems.  Callers must ensure that
@@ -41,20 +269,172 @@ int
 TALER_JSON_contract_hash (const json_t *json,
                           struct GNUNET_HashCode *hc)
 {
-  char *wire_enc;
-  size_t len;
+  int ret;
+  json_t *cjson;
 
-  if (NULL == (wire_enc = json_dumps (json,
-                                      JSON_COMPACT | JSON_SORT_KEYS)))
+  cjson = forget (json);
+  if (NULL == cjson)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  ret = dump_and_hash (cjson,
+                       NULL,
+                       hc);
+  json_decref (cjson);
+  return ret;
+}
+
+
+/**
+ * Mark part of a contract object as 'forgettable'.
+ *
+ * @param[in,out] json some JSON object to modify
+ * @param field name of the field to mark as forgettable
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+int
+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;
+  }
+  if (NULL == json_object_get (json,
+                               field))
+  {
+    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;
+}
+
+
+/**
+ * Forget part of a contract object.
+ *
+ * @param[in,out] json some JSON object to modify
+ * @param field name of the field to forget
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+int
+TALER_JSON_contract_part_forget (json_t *json,
+                                 const char *field)
+{
+  const json_t *fg;
+  const json_t *part;
+  json_t *fp;
+  json_t *rx;
+  struct GNUNET_HashCode hc;
+  const char *salt;
+
+  if (! json_is_object (json))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (NULL == (part = json_object_get (json,
+                                       field)))
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  fg = json_object_get (json,
+                        "_forgettable");
+  if (NULL == fg)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  salt = json_string_value (json_object_get (fg,
+                                             field));
+  if (NULL == salt)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+
+  /* need to recursively forget to compute 'hc' */
+  fp = forget (part);
+  if (NULL == fp)
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  if (GNUNET_OK !=
+      dump_and_hash (fp,
+                     salt,
+                     &hc))
+  {
+    json_decref (fp);
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
+  json_decref (fp);
+
+  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;
+    }
+  }
+  /* 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_set_new (json,
+                           field,
+                           json_null ()))
   {
     GNUNET_break (0);
     return GNUNET_SYSERR;
   }
-  len = strlen (wire_enc) + 1;
-  GNUNET_CRYPTO_hash (wire_enc,
-                      len,
-                      hc);
-  free (wire_enc);
   return GNUNET_OK;
 }
 
diff --git a/src/json/test_json.c b/src/json/test_json.c
index 732a3d77..2e7aba50 100644
--- a/src/json/test_json.c
+++ b/src/json/test_json.c
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  (C) 2015, 2016 Taler Systems SA
+  (C) 2015, 2016, 2020 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

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]