gnunet-svn
[Top][All Lists]
Advanced

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

[taler-anastasis] branch master updated: implement #6810: upload size li


From: gnunet
Subject: [taler-anastasis] branch master updated: implement #6810: upload size limit checks
Date: Sat, 10 Apr 2021 15:03:18 +0200

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

grothoff pushed a commit to branch master
in repository anastasis.

The following commit(s) were added to refs/heads/master by this push:
     new 40d9e2f  implement #6810: upload size limit checks
40d9e2f is described below

commit 40d9e2f08b27dab7789a848cb8cdff3f1abf23b0
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Sat Apr 10 15:03:16 2021 +0200

    implement #6810: upload size limit checks
---
 contrib/gana                             |   2 +-
 src/reducer/anastasis_api_backup_redux.c | 236 +++++++++++++++++++++++++++----
 src/reducer/anastasis_api_redux.c        |  36 +++--
 3 files changed, 232 insertions(+), 42 deletions(-)

diff --git a/contrib/gana b/contrib/gana
index df4206c..fd5f8ca 160000
--- a/contrib/gana
+++ b/contrib/gana
@@ -1 +1 @@
-Subproject commit df4206c1dc3481faa2e15d497036632229ac9071
+Subproject commit fd5f8ca01e319278ecdf7ee29df4ee4176f1e4c6
diff --git a/src/reducer/anastasis_api_backup_redux.c 
b/src/reducer/anastasis_api_backup_redux.c
index b8f98f5..d771cd4 100644
--- a/src/reducer/anastasis_api_backup_redux.c
+++ b/src/reducer/anastasis_api_backup_redux.c
@@ -100,6 +100,26 @@ ANASTASIS_backup_start (const struct 
GNUNET_CONFIGURATION_Handle *cfg)
 }
 
 
+/**
+ * Test if @a challenge_size is small enough for the provider's
+ * @a size_limit_in_mb.
+ *
+ * We add 1024 to @a challenge_size here as a "safety margin" as
+ * the encrypted challenge has some additional headers around it
+ *
+ * @param size_limit_in_mb provider's upload limit
+ * @param challenge_size actual binary size of the challenge
+ * @return true if this fits
+ */
+static bool
+challenge_size_ok (uint32_t size_limit_in_mb,
+                   size_t challenge_size)
+{
+  return (size_limit_in_mb * 1024LLU * 1024LLU >=
+          challenge_size + 1024LLU);
+}
+
+
 /**
  * DispatchHandler/Callback function which is called for a
  * "add_authentication" action.
@@ -120,6 +140,16 @@ add_authentication (json_t *state,
   json_t *auth_providers;
   json_t *method;
   const char *method_type;
+  void *challenge;
+  size_t challenge_size;
+  struct GNUNET_JSON_Specification spec[] = {
+    GNUNET_JSON_spec_string ("type",
+                             &method_type),
+    GNUNET_JSON_spec_varsize ("challenge",
+                              &challenge,
+                              &challenge_size),
+    GNUNET_JSON_spec_end ()
+  };
 
   auth_providers = json_object_get (state,
                                     "authentication_providers");
@@ -142,28 +172,21 @@ add_authentication (json_t *state,
                            "'authentication_method' required");
     return NULL;
   }
-  method_type = json_string_value (json_object_get (method,
-                                                    "type"));
-  if (NULL == method_type)
-  {
-    ANASTASIS_redux_fail_ (cb,
-                           cb_cls,
-                           TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-                           "'type' field must be a valid string");
-    return NULL;
-  }
-  if (! json_object_get (method,
-                         "challenge"))
+  if (GNUNET_OK !=
+      GNUNET_JSON_parse (method,
+                         spec,
+                         NULL, NULL))
   {
     ANASTASIS_redux_fail_ (cb,
                            cb_cls,
                            TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
-                           "'challenge' field missing from 
'authentication_method'");
+                           "'authentication_method' content malformed");
     return NULL;
   }
   /* Check we know at least one provider that supports this method */
   {
     bool found = false;
+    bool too_big = false;
     json_t *details;
     const char *url;
 
@@ -172,10 +195,19 @@ add_authentication (json_t *state,
       json_t *methods;
       json_t *method;
       size_t index;
+      uint32_t size_limit_in_mb;
+      struct GNUNET_JSON_Specification ispec[] = {
+        GNUNET_JSON_spec_uint32 ("storage_limit_in_megabytes",
+                                 &size_limit_in_mb),
+        GNUNET_JSON_spec_json ("methods",
+                               &methods),
+        GNUNET_JSON_spec_end ()
+      };
 
-      methods = json_object_get (details,
-                                 "methods");
-      if (NULL == methods)
+      if (GNUNET_OK !=
+          GNUNET_JSON_parse (details,
+                             ispec,
+                             NULL, NULL))
       {
         GNUNET_break (0);
         continue;
@@ -195,18 +227,40 @@ add_authentication (json_t *state,
           break;
         }
       }
+      GNUNET_JSON_parse_free (ispec);
+      if (! challenge_size_ok (size_limit_in_mb,
+                               challenge_size))
+      {
+        /* Challenge data too big for this provider. Try to find another one.
+           Note: we add 1024 to challenge-size here as a "safety margin" as
+           the encrypted challenge has some additional headers around it */
+        too_big = true;
+        found = false;
+      }
       if (found)
         break;
     }
     if (! found)
     {
-      ANASTASIS_redux_fail_ (cb,
-                             cb_cls,
-                             
TALER_EC_ANASTASIS_REDUCER_AUTHENTICATION_METHOD_NOT_SUPPORTED,
-                             method_type);
+      if (too_big)
+      {
+        ANASTASIS_redux_fail_ (cb,
+                               cb_cls,
+                               
TALER_EC_ANASTASIS_REDUCER_CHALLENGE_DATA_TOO_BIG,
+                               method_type);
+      }
+      else
+      {
+        ANASTASIS_redux_fail_ (cb,
+                               cb_cls,
+                               
TALER_EC_ANASTASIS_REDUCER_AUTHENTICATION_METHOD_NOT_SUPPORTED,
+                               method_type);
+      }
+      GNUNET_JSON_parse_free (spec);
       return NULL;
     }
   }
+  GNUNET_JSON_parse_free (spec);
 
   /* append provided method to our array */
   {
@@ -393,20 +447,50 @@ eval_provider_selection (struct PolicyBuilder *pb,
   {
     const json_t *method_obj = json_array_get (pb->methods,
                                                pb->m_idx[i]);
-    const char *method_type = json_string_value (json_object_get (method_obj,
-                                                                  "type"));
     const json_t *provider_cfg = json_object_get (pb->providers,
                                                   prov_sel[i]);
-    json_t *provider_methods = json_object_get (provider_cfg,
-                                                "methods");
+    json_t *provider_methods;
+    const char *method_type;
     json_t *md;
     size_t index;
     bool found = false;
+    uint32_t size_limit_in_mb;
+    struct GNUNET_JSON_Specification pspec[] = {
+      GNUNET_JSON_spec_uint32 ("storage_limit_in_megabytes",
+                               &size_limit_in_mb),
+      GNUNET_JSON_spec_json ("methods",
+                             &provider_methods),
+      GNUNET_JSON_spec_end ()
+    };
+    void *challenge;
+    size_t challenge_size;
+    struct GNUNET_JSON_Specification mspec[] = {
+      GNUNET_JSON_spec_string ("type",
+                               &method_type),
+      GNUNET_JSON_spec_varsize ("challenge",
+                                &challenge,
+                                &challenge_size),
+      GNUNET_JSON_spec_end ()
+    };
+
+    if (GNUNET_OK !=
+        GNUNET_JSON_parse (method_obj,
+                           mspec,
+                           NULL, NULL))
+    {
+      pb->ec = TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID;
+      pb->hint = "'authentication_method' content malformed";
+      return;
+    }
 
-    if (NULL == provider_methods)
+    if (GNUNET_OK !=
+        GNUNET_JSON_parse (provider_cfg,
+                           pspec,
+                           NULL, NULL))
     {
       pb->ec = TALER_EC_ANASTASIS_REDUCER_STATE_INVALID;
       pb->hint = "'methods' of provider not found";
+      GNUNET_JSON_parse_free (mspec);
       return;
     }
     json_array_foreach (provider_methods, index, md)
@@ -428,10 +512,13 @@ eval_provider_selection (struct PolicyBuilder *pb,
       {
         pb->ec = TALER_EC_ANASTASIS_REDUCER_STATE_INVALID;
         pb->hint = "'methods' of provider";
+        GNUNET_JSON_parse_free (pspec);
         return;
       }
-      if (0 == strcmp (type,
-                       method_type))
+      if ( (0 == strcmp (type,
+                         method_type)) &&
+           (challenge_size_ok (size_limit_in_mb,
+                               challenge_size) ) )
       {
         found = true;
       }
@@ -440,8 +527,12 @@ eval_provider_selection (struct PolicyBuilder *pb,
     {
       /* Provider does not OFFER this method, combination not possible.
          Cost is basically 'infinite', but we simply then skip this. */
+      GNUNET_JSON_parse_free (pspec);
+      GNUNET_JSON_parse_free (mspec);
       return;
     }
+    GNUNET_JSON_parse_free (mspec);
+    GNUNET_JSON_parse_free (pspec);
   }
 
   /* calculate provider diversity by counting number of different providers 
selected */
@@ -2441,6 +2532,36 @@ upload (json_t *state,
 }
 
 
+/**
+ * Test if the core secret @a secret_size is small enough to be stored
+ * at all providers, which have a minimum upload limit of @a min_limit_in_mb.
+ *
+ * For now, we do not precisely calculate the size of the recovery document,
+ * and simply assume that the instructions (i.e. security questions) are all
+ * relatively small (aka sane), and that the number of authentication methods
+ * and recovery policies is similarly small so that all of this meta data
+ * fits in 512 kb (which is VERY big).
+ *
+ * Even with the minimum permitted upload limit of 1 MB (which is likely,
+ * given that there is hardly a reason for providers to offer more), this
+ * leaves 512 kb for the @a secret_size, which should be plenty (given
+ * that this is supposed to be for a master key, and not the actual data).
+ *
+ * @param state our state, could be used in the future to calculate the
+ *        size of the recovery document without the core secret
+ * @param secret_size size of the core secret
+ * @param min_limit_in_mb minimum upload size of all providers
+ */
+static bool
+core_secret_fits (const json_t *state,
+                  size_t secret_size,
+                  uint32_t min_limit_in_mb)
+{
+  return (min_limit_in_mb * 1024LL * 1024LL >
+          512LLU * 1024LLU + secret_size);
+}
+
+
 /**
  * DispatchHandler/Callback function which is called for a
  * "enter_secret" action.
@@ -2489,12 +2610,73 @@ enter_secret (json_t *state,
                        JSON_COMPACT | JSON_SORT_KEYS);
   GNUNET_assert (NULL != secret);
   secret_size = strlen (secret);
+
+  /* check upload size limit */
+  {
+    uint32_t min_limit = UINT32_MAX;
+    json_t *aps = json_object_get (state,
+                                   "authentication_providers");
+    const char *url;
+    json_t *ap;
+
+    /* We calculate the minimum upload limit of all possible providers;
+       this is under the (simplified) assumption that we store the
+       recovery document at all providers; this may be changed later,
+       see #6760. */
+    json_object_foreach (aps, url, ap)
+    {
+      uint32_t limit;
+      struct GNUNET_JSON_Specification spec[] = {
+        GNUNET_JSON_spec_uint32 ("storage_limit_in_megabytes",
+                                 &limit),
+        GNUNET_JSON_spec_end ()
+      };
+
+      if (GNUNET_OK !=
+          GNUNET_JSON_parse (ap,
+                             spec,
+                             NULL, NULL))
+      {
+        ANASTASIS_redux_fail_ (cb,
+                               cb_cls,
+                               TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                               "'authentication_method' content malformed");
+        GNUNET_free (secret);
+        return NULL;
+      }
+      if (0 == limit)
+      {
+        ANASTASIS_redux_fail_ (cb,
+                               cb_cls,
+                               TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID,
+                               "provider has an upload limit of 0");
+        GNUNET_free (secret);
+        return NULL;
+      }
+      min_limit = GNUNET_MIN (min_limit,
+                              limit);
+    }
+    if (! core_secret_fits (state,
+                            secret_size,
+                            min_limit))
+    {
+      ANASTASIS_redux_fail_ (cb,
+                             cb_cls,
+                             TALER_EC_ANASTASIS_REDUCER_SECRET_TOO_BIG,
+                             NULL);
+      GNUNET_free (secret);
+      return NULL;
+    }
+  }
+
+
   GNUNET_assert (0 ==
                  json_object_set_new (state,
                                       "core_secret",
                                       GNUNET_JSON_from_data (secret,
                                                              secret_size)));
   GNUNET_free (secret);
+
   GNUNET_JSON_parse_free (spec);
   return upload (state,
                  cb,
diff --git a/src/reducer/anastasis_api_redux.c 
b/src/reducer/anastasis_api_redux.c
index 2c93ad9..14712d8 100644
--- a/src/reducer/anastasis_api_redux.c
+++ b/src/reducer/anastasis_api_redux.c
@@ -570,22 +570,30 @@ config_cb (void *cls,
   }
   else if (NULL != acfg)
   {
-    cr->currency = GNUNET_strdup (acfg->currency);
-    cr->business_name = GNUNET_strdup (acfg->business_name);
-    cr->methods = GNUNET_new_array (acfg->methods_length,
-                                    struct AuthorizationMethodConfig);
-    for (unsigned int i = 0; i<acfg->methods_length; i++)
+    if (0 == acfg->storage_limit_in_megabytes)
     {
-      cr->methods[i].type = GNUNET_strdup (acfg->methods[i].type);
-      cr->methods[i].usage_fee = acfg->methods[i].usage_fee;
+      cr->http_status = 0;
+      cr->ec = TALER_EC_ANASTASIS_REDUCER_PROVIDER_INVALID_CONFIG;
+    }
+    else
+    {
+      cr->currency = GNUNET_strdup (acfg->currency);
+      cr->business_name = GNUNET_strdup (acfg->business_name);
+      cr->methods = GNUNET_new_array (acfg->methods_length,
+                                      struct AuthorizationMethodConfig);
+      for (unsigned int i = 0; i<acfg->methods_length; i++)
+      {
+        cr->methods[i].type = GNUNET_strdup (acfg->methods[i].type);
+        cr->methods[i].usage_fee = acfg->methods[i].usage_fee;
+      }
+      cr->methods_length = acfg->methods_length;
+      cr->storage_limit_in_megabytes = acfg->storage_limit_in_megabytes;
+      cr->annual_fee = acfg->annual_fee;
+      cr->truth_upload_fee = acfg->truth_upload_fee;
+      cr->truth_lifetime = acfg->truth_lifetime;
+      cr->liability_limit = acfg->liability_limit;
+      cr->salt = acfg->salt;
     }
-    cr->methods_length = acfg->methods_length;
-    cr->storage_limit_in_megabytes = acfg->storage_limit_in_megabytes;
-    cr->annual_fee = acfg->annual_fee;
-    cr->truth_upload_fee = acfg->truth_upload_fee;
-    cr->truth_lifetime = acfg->truth_lifetime;
-    cr->liability_limit = acfg->liability_limit;
-    cr->salt = acfg->salt;
   }
   notify_waiting (cr);
 }

-- 
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]