gnunet-svn
[Top][All Lists]
Advanced

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

[gnunet] 04/20: -conclude hello-uri implementation and test


From: gnunet
Subject: [gnunet] 04/20: -conclude hello-uri implementation and test
Date: Sat, 19 Feb 2022 16:20:44 +0100

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

grothoff pushed a commit to branch master
in repository gnunet.

commit af252f5c3d4e62f4db39bbc65f3eea4f853d04bc
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Wed Jan 12 20:30:37 2022 +0100

    -conclude hello-uri implementation and test
---
 src/hello/.gitignore               |   2 +
 src/hello/Makefile.am              |   7 +
 src/hello/hello-uri.c              | 459 ++++++++++++++++++++++++++++++++-----
 src/hello/test_hello-ng.c          |  23 +-
 src/hello/test_hello-uri.c         | 176 ++++++++++++++
 src/include/gnunet_hello_uri_lib.h |  13 +-
 src/include/gnunet_strings_lib.h   |   2 +-
 src/include/gnunet_time_lib.h      |  13 +-
 src/util/strings.c                 |   9 +-
 src/util/time.c                    |   7 +
 10 files changed, 649 insertions(+), 62 deletions(-)

diff --git a/src/hello/.gitignore b/src/hello/.gitignore
index bb49ceb20..d175d148e 100644
--- a/src/hello/.gitignore
+++ b/src/hello/.gitignore
@@ -1,3 +1,5 @@
 gnunet-hello
 test_friend_hello
 test_hello
+test_hello-uri
+test_hello-ng
diff --git a/src/hello/Makefile.am b/src/hello/Makefile.am
index f97ede97c..08d976260 100644
--- a/src/hello/Makefile.am
+++ b/src/hello/Makefile.am
@@ -25,6 +25,7 @@ noinst_PROGRAMS = \
 
 check_PROGRAMS = \
  test_hello \
+ test_hello-uri \
  test_friend_hello \
  test_hello-ng
 
@@ -45,6 +46,12 @@ test_hello_ng_LDADD = \
  libgnunethello.la \
  $(top_builddir)/src/util/libgnunetutil.la
 
+test_hello_uri_SOURCES = \
+ test_hello-uri.c
+test_hello_uri_LDADD = \
+ libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
 
 test_friend_hello_SOURCES = \
  test_friend_hello.c
diff --git a/src/hello/hello-uri.c b/src/hello/hello-uri.c
index 347c4bf0c..49e4f6ed3 100644
--- a/src/hello/hello-uri.c
+++ b/src/hello/hello-uri.c
@@ -22,6 +22,17 @@
  * @file hello/hello-uri.c
  * @brief helper library for handling URI-based HELLOs
  * @author Christian Grothoff
+ *
+ * Note:
+ * - Current API does not support deserializing HELLO of
+ *   another peer and then serializing it into another
+ *   format (we always require the private key).
+ *   Not sure if we need this, but if we do, we need
+ *   to extend the builder and the API.
+ * - Current API does not allow overriding the default
+ *   HELLO expiration time. We may want to add a function
+ *   that does this to create bootstrap HELLOs shipped with
+ *   the TGZ.
  */
 #include "platform.h"
 #include "gnunet_signatures.h"
@@ -29,15 +40,44 @@
 #include "gnunet_protocols.h"
 #include "gnunet_util_lib.h"
 
+/**
+ * For how long are HELLO signatures valid?
+ */
+#define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply ( \
+    GNUNET_TIME_UNIT_DAYS, 2)
+
+
 GNUNET_NETWORK_STRUCT_BEGIN
 
+/**
+ * Message signed as part of a HELLO block/URL.
+ */
+struct HelloSignaturePurpose
+{
+  /**
+   * Purpose must be #GNUNET_SIGNATURE_PURPOSE_HELLO
+   */
+  struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+
+  /**
+   * When does the signature expire?
+   */
+  struct GNUNET_TIME_AbsoluteNBO expiration_time;
+
+  /**
+   * Hash over all addresses.
+   */
+  struct GNUNET_HashCode h_addrs;
+
+};
+
 /**
  * Binary block we sign when we sign an address.
  */
 struct HelloUriMessage
 {
   /**
-   * Purpose must be #GNUNET_MESSAGE_TYPE_HELLO_URI
+   * Type must be #GNUNET_MESSAGE_TYPE_HELLO_URI
    */
   struct GNUNET_MessageHeader header;
 
@@ -51,11 +91,32 @@ struct HelloUriMessage
    */
   uint16_t url_counter GNUNET_PACKED;
 
+  /* followed by a 'block' */
+};
+
+
+/**
+ * Start of a 'block'.
+ */
+struct BlockHeader
+{
   /**
    * Public key of the peer.
    */
   struct GNUNET_PeerIdentity pid;
+
+  /**
+   * Signature over the block, of purpose #GNUNET_SIGNATURE_PURPOSE_HELLO.
+   */
+  struct GNUNET_CRYPTO_EddsaSignature sig;
+
+  /**
+   * When does the HELLO expire?
+   */
+  struct GNUNET_TIME_AbsoluteNBO expiration_time;
+
 };
+
 GNUNET_NETWORK_STRUCT_END
 
 
@@ -114,6 +175,98 @@ struct GNUNET_HELLO_Builder
 };
 
 
+/**
+ * Compute @a hash over addresses in @a builder.
+ *
+ * @param builder the builder to hash addresses of
+ * @param[out] hash where to write the hash
+ */
+static void
+hash_addresses (const struct GNUNET_HELLO_Builder *builder,
+                struct GNUNET_HashCode *hash)
+{
+  struct GNUNET_HashContext *hc;
+
+  hc = GNUNET_CRYPTO_hash_context_start ();
+  for (struct Address *a = builder->a_head;
+       NULL != a;
+       a = a->next)
+  {
+    GNUNET_CRYPTO_hash_context_read (hc,
+                                     a->uri,
+                                     a->uri_len);
+  }
+  GNUNET_CRYPTO_hash_context_finish (hc,
+                                     hash);
+
+}
+
+
+/**
+ * Create HELLO signature.
+ *
+ * @param builder the builder to use
+ * @param et expiration time to sign
+ * @param priv key to sign with
+ * @param[out] sig where to write the signature
+ */
+static void
+sign_hello (const struct GNUNET_HELLO_Builder *builder,
+            struct GNUNET_TIME_Timestamp et,
+            const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
+            struct GNUNET_CRYPTO_EddsaSignature *sig)
+{
+  struct HelloSignaturePurpose hsp = {
+    .purpose.size = htonl (sizeof (hsp)),
+    .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_HELLO),
+    .expiration_time = GNUNET_TIME_absolute_hton (et.abs_time)
+  };
+
+  hash_addresses (builder,
+                  &hsp.h_addrs);
+  GNUNET_CRYPTO_eddsa_sign (priv,
+                            &hsp,
+                            sig);
+}
+
+
+/**
+ * Verify HELLO signature.
+ *
+ * @param builder the builder to use
+ * @param et expiration time to verify
+ * @param sig signature to verify
+ * @return #GNUNET_OK if everything is ok, #GNUNET_NO if the
+ *    HELLO expired, #GNUNET_SYSERR if the signature is wrong
+ */
+static enum GNUNET_GenericReturnValue
+verify_hello (const struct GNUNET_HELLO_Builder *builder,
+              struct GNUNET_TIME_Absolute et,
+              const struct GNUNET_CRYPTO_EddsaSignature *sig)
+{
+  struct HelloSignaturePurpose hsp = {
+    .purpose.size = htonl (sizeof (hsp)),
+    .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_HELLO),
+    .expiration_time = GNUNET_TIME_absolute_hton (et)
+  };
+
+  hash_addresses (builder,
+                  &hsp.h_addrs);
+  if (GNUNET_OK !=
+      GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_HELLO,
+                                  &hsp,
+                                  sig,
+                                  &builder->pid.public_key))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  if (GNUNET_TIME_absolute_is_past (et))
+    return GNUNET_NO;
+  return GNUNET_OK;
+}
+
+
 struct GNUNET_HELLO_Builder *
 GNUNET_HELLO_builder_new (const struct GNUNET_PeerIdentity *pid)
 {
@@ -147,29 +300,45 @@ struct GNUNET_HELLO_Builder *
 GNUNET_HELLO_builder_from_msg (const struct GNUNET_MessageHeader *msg)
 {
   const struct HelloUriMessage *h;
-  struct GNUNET_HELLO_Builder *b;
   uint16_t size = ntohs (msg->size);
-  const char *pos;
 
   if (GNUNET_MESSAGE_TYPE_HELLO_URI != ntohs (msg->type))
   {
     GNUNET_break (0);
     return NULL;
   }
-  if (sizeof (struct HelloUriMessage) < size)
+  if (sizeof (struct HelloUriMessage) > size)
   {
     GNUNET_break_op (0);
     return NULL;
   }
   h = (const struct HelloUriMessage *) msg;
-  pos = (const char *) &h[1];
   size -= sizeof (*h);
-  b = GNUNET_HELLO_builder_new (&h->pid);
-  for (unsigned int i = 0; i<ntohs (h->url_counter); i++)
+  return GNUNET_HELLO_builder_from_block (&h[1],
+                                          size);
+}
+
+
+struct GNUNET_HELLO_Builder *
+GNUNET_HELLO_builder_from_block (const void *block,
+                                 size_t block_size)
+{
+  const struct BlockHeader *bh = block;
+  struct GNUNET_HELLO_Builder *b;
+
+  if (block_size < sizeof (*bh))
   {
-    const char *end = memchr (pos,
+    GNUNET_break_op (0);
+    return NULL;
+  }
+  b = GNUNET_HELLO_builder_new (&bh->pid);
+  block += sizeof (*bh);
+  block_size -= sizeof (*bh);
+  while (block_size > 0)
+  {
+    const void *end = memchr (block,
                               '\0',
-                              size);
+                              block_size);
 
     if (NULL == end)
     {
@@ -179,79 +348,174 @@ GNUNET_HELLO_builder_from_msg (const struct 
GNUNET_MessageHeader *msg)
     }
     if (GNUNET_OK !=
         GNUNET_HELLO_builder_add_address (b,
-                                          pos))
+                                          block))
     {
       GNUNET_break_op (0);
       GNUNET_HELLO_builder_free (b);
       return NULL;
     }
-    end++; /* skip '\0' */
-    size -= (end - pos);
-    pos = end;
+    end++;
+    block_size -= (end - block);
+    block = end;
   }
-  if (0 != size)
   {
-    GNUNET_break_op (0);
-    GNUNET_HELLO_builder_free (b);
-    return NULL;
+    enum GNUNET_GenericReturnValue ret;
+
+    ret = verify_hello (b,
+                        GNUNET_TIME_absolute_ntoh (bh->expiration_time),
+                        &bh->sig);
+    GNUNET_break (GNUNET_SYSERR != ret);
+    if (GNUNET_OK != ret)
+    {
+      GNUNET_HELLO_builder_free (b);
+      return NULL;
+    }
   }
   return b;
 }
 
 
 struct GNUNET_HELLO_Builder *
-GNUNET_HELLO_builder_from_block (const void *block,
-                                 size_t block_size)
+GNUNET_HELLO_builder_from_url (const char *url)
 {
-  const struct GNUNET_PeerIdentity *pid = block;
+  const char *q;
+  const char *s1;
+  const char *s2;
+  struct GNUNET_PeerIdentity pid;
+  struct GNUNET_CRYPTO_EddsaSignature sig;
+  struct GNUNET_TIME_Absolute et;
+  size_t len;
   struct GNUNET_HELLO_Builder *b;
 
-  if (block_size < sizeof (*pid))
+  if (0 != strncasecmp (url,
+                        "gnunet://hello/",
+                        strlen ("gnunet://hello/")))
+    return NULL;
+  url += strlen ("gnunet://hello/");
+  s1 = strchr (url, '/');
+  if (NULL == s1)
   {
     GNUNET_break_op (0);
     return NULL;
   }
-  b = GNUNET_HELLO_builder_new (pid);
-  block += sizeof (*pid);
-  block_size -= sizeof (*pid);
-  while (block_size > 0)
+  s2 = strchr (s1 + 1, '/');
+  if (NULL == s1)
   {
-    const void *end = memchr (block,
-                              '\0',
-                              block_size);
+    GNUNET_break_op (0);
+    return NULL;
+  }
+  q = strchr (url, '?');
+  if (NULL == q)
+    q = url + strlen (url);
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_string_to_data (url,
+                                     s1 - url,
+                                     &pid,
+                                     sizeof(pid)))
+  {
+    GNUNET_break_op (0);
+    return NULL;
+  }
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_string_to_data (s1 + 1,
+                                     s2 - (s1 + 1),
+                                     &sig,
+                                     sizeof(sig)))
+  {
+    GNUNET_break_op (0);
+    return NULL;
+  }
+  {
+    unsigned long long sec;
+    char dummy = '?';
+
+    if ( (0 == sscanf (s2 + 1,
+                       "%llu%c",
+                       &sec,
+                       &dummy)) ||
+         ('?' != dummy) )
+    {
+      GNUNET_break_op (0);
+      return NULL;
+    }
+    et = GNUNET_TIME_absolute_from_s (sec);
+  }
 
-    if (NULL == end)
+  b = GNUNET_HELLO_builder_new (&pid);
+  len = strlen (q);
+  while (len > 0)
+  {
+    const char *eq;
+    const char *amp;
+    char *addr = NULL;
+    char *uri;
+
+    /* skip ?/& separator */
+    len--;
+    q++;
+    eq = strchr (q, '=');
+    if ( (eq == q) ||
+         (NULL == eq) )
     {
       GNUNET_break_op (0);
       GNUNET_HELLO_builder_free (b);
       return NULL;
     }
+    amp = strchr (eq, '&');
+    if (NULL == amp)
+      amp = &q[len];
+    GNUNET_STRINGS_urldecode (eq + 1,
+                              amp - (eq + 1),
+                              &addr);
+    if ( (NULL == addr) ||
+         (0 == strlen (addr)) )
+    {
+      GNUNET_free (addr);
+      GNUNET_break_op (0);
+      GNUNET_HELLO_builder_free (b);
+      return NULL;
+    }
+    GNUNET_asprintf (&uri,
+                     "%.*s://%s",
+                     (int) (eq - q),
+                     q,
+                     addr);
+    GNUNET_free (addr);
     if (GNUNET_OK !=
         GNUNET_HELLO_builder_add_address (b,
-                                          block))
+                                          uri))
     {
       GNUNET_break_op (0);
+      GNUNET_free (uri);
       GNUNET_HELLO_builder_free (b);
       return NULL;
     }
-    end++;
-    block_size -= (end - block);
-    block = end;
+    GNUNET_free (uri);
+    /* move to next URL */
+    len -= (amp - q);
+    q = amp;
   }
-  return b;
-}
 
+  {
+    enum GNUNET_GenericReturnValue ret;
 
-struct GNUNET_HELLO_Builder *
-GNUNET_HELLO_builder_from_url (const char *url)
-{
-  // FIXME!
-  return NULL;
+    ret = verify_hello (b,
+                        et,
+                        &sig);
+    GNUNET_break (GNUNET_SYSERR != ret);
+    if (GNUNET_OK != ret)
+    {
+      GNUNET_HELLO_builder_free (b);
+      return NULL;
+    }
+  }
+  return b;
 }
 
 
 struct GNUNET_MQ_Envelope *
-GNUNET_HELLO_builder_to_env (struct GNUNET_HELLO_Builder *builder)
+GNUNET_HELLO_builder_to_env (const struct GNUNET_HELLO_Builder *builder,
+                             const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
 {
   struct GNUNET_MQ_Envelope *env;
   struct HelloUriMessage *msg;
@@ -260,14 +524,15 @@ GNUNET_HELLO_builder_to_env (struct GNUNET_HELLO_Builder 
*builder)
   blen = 0;
   GNUNET_assert (GNUNET_NO ==
                  GNUNET_HELLO_builder_to_block (builder,
+                                                priv,
                                                 NULL,
                                                 &blen));
   env = GNUNET_MQ_msg_extra (msg,
                              blen,
                              GNUNET_MESSAGE_TYPE_HELLO_URI);
-  msg->pid = builder->pid;
   GNUNET_assert (GNUNET_OK ==
                  GNUNET_HELLO_builder_to_block (builder,
+                                                priv,
                                                 &msg[1],
                                                 &blen));
   return env;
@@ -275,20 +540,80 @@ GNUNET_HELLO_builder_to_env (struct GNUNET_HELLO_Builder 
*builder)
 
 
 char *
-GNUNET_HELLO_builder_to_url (struct GNUNET_HELLO_Builder *builder)
+GNUNET_HELLO_builder_to_url (const struct GNUNET_HELLO_Builder *builder,
+                             const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
 {
-  // FIXME!
-  return NULL;
+  struct GNUNET_CRYPTO_EddsaSignature sig;
+  struct GNUNET_TIME_Timestamp et;
+  char *result;
+  char *pids;
+  char *sigs;
+  const char *sep = "?";
+
+  et = GNUNET_TIME_relative_to_timestamp (HELLO_ADDRESS_EXPIRATION);
+  sign_hello (builder,
+              et,
+              priv,
+              &sig);
+  pids = GNUNET_STRINGS_data_to_string_alloc (&builder->pid,
+                                              sizeof (builder->pid));
+  sigs = GNUNET_STRINGS_data_to_string_alloc (&sig,
+                                              sizeof (sig));
+  GNUNET_asprintf (&result,
+                   "gnunet://hello/%s/%s/%llu",
+                   pids,
+                   sigs,
+                   (unsigned long long) GNUNET_TIME_timestamp_to_s (et));
+  GNUNET_free (sigs);
+  GNUNET_free (pids);
+  for (struct Address *a = builder->a_head;
+       NULL != a;
+       a = a->next)
+  {
+    char *ue;
+    char *tmp;
+    int pfx_len;
+    const char *eou;
+
+    eou = strstr (a->uri,
+                  "://");
+    if (NULL == eou)
+    {
+      GNUNET_break (0);
+      GNUNET_free (result);
+      return NULL;
+    }
+    pfx_len = eou - a->uri;
+    eou += 3;
+    GNUNET_STRINGS_urlencode (eou,
+                              a->uri_len - 4 - pfx_len,
+                              &ue);
+    GNUNET_asprintf (&tmp,
+                     "%s%s%.*s=%s",
+                     result,
+                     sep,
+                     pfx_len,
+                     a->uri,
+                     ue);
+    GNUNET_free (ue);
+    GNUNET_free (result);
+    result = tmp;
+    sep = "&";
+  }
+  return result;
 }
 
 
 enum GNUNET_GenericReturnValue
-GNUNET_HELLO_builder_to_block (struct GNUNET_HELLO_Builder *builder,
+GNUNET_HELLO_builder_to_block (const struct GNUNET_HELLO_Builder *builder,
+                               const struct GNUNET_CRYPTO_EddsaPrivateKey 
*priv,
                                void *block,
                                size_t *block_size)
 {
-  size_t needed = sizeof (struct GNUNET_PeerIdentity);
+  struct BlockHeader bh;
+  size_t needed = sizeof (bh);
   char *pos;
+  struct GNUNET_TIME_Timestamp et;
 
   for (struct Address *a = builder->a_head;
        NULL != a;
@@ -303,10 +628,17 @@ GNUNET_HELLO_builder_to_block (struct 
GNUNET_HELLO_Builder *builder,
     *block_size = needed;
     return GNUNET_NO;
   }
+  bh.pid = builder->pid;
+  et = GNUNET_TIME_relative_to_timestamp (HELLO_ADDRESS_EXPIRATION);
+  bh.expiration_time = GNUNET_TIME_absolute_hton (et.abs_time);
+  sign_hello (builder,
+              et,
+              priv,
+              &bh.sig);
   memcpy (block,
-          &builder->pid,
-          sizeof (builder->pid));
-  pos = block + sizeof (builder->pid);
+          &bh,
+          sizeof (bh));
+  pos = block + sizeof (bh);
   for (struct Address *a = builder->a_head;
        NULL != a;
        a = a->next)
@@ -327,7 +659,26 @@ GNUNET_HELLO_builder_add_address (struct 
GNUNET_HELLO_Builder *builder,
 {
   size_t alen = strlen (address) + 1;
   struct Address *a;
+  const char *e;
 
+  if (NULL == (e = strstr (address,
+                           "://")))
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  if (e == address)
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  for (const char *p = address; p != e; p++)
+    if ( (! isalpha ((unsigned char) *p)) &&
+         ('+' != *p) )
+    {
+      GNUNET_break_op (0);
+      return GNUNET_SYSERR;
+    }
   /* check for duplicates */
   for (a = builder->a_head;
        NULL != a;
@@ -341,9 +692,10 @@ GNUNET_HELLO_builder_add_address (struct 
GNUNET_HELLO_Builder *builder,
           address,
           alen);
   a->uri = (const char *) &a[1];
-  GNUNET_CONTAINER_DLL_insert (builder->a_head,
-                               builder->a_tail,
-                               a);
+  GNUNET_CONTAINER_DLL_insert_tail (builder->a_head,
+                                    builder->a_tail,
+                                    a);
+  builder->a_length++;
   return GNUNET_OK;
 }
 
@@ -366,6 +718,7 @@ GNUNET_HELLO_builder_del_address (struct 
GNUNET_HELLO_Builder *builder,
   GNUNET_CONTAINER_DLL_remove (builder->a_head,
                                builder->a_tail,
                                a);
+  builder->a_length--;
   GNUNET_free (a);
   return GNUNET_OK;
 }
diff --git a/src/hello/test_hello-ng.c b/src/hello/test_hello-ng.c
index e6b1d42a0..4ace9439f 100644
--- a/src/hello/test_hello-ng.c
+++ b/src/hello/test_hello-ng.c
@@ -1,3 +1,22 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2022 GNUnet e.V.
+
+     GNUnet is free software: you can redistribute it and/or modify it
+     under the terms of the GNU Affero General Public License as published
+     by the Free Software Foundation, either version 3 of the License,
+     or (at your option) any later version.
+
+     GNUnet 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
+     Affero General Public License for more details.
+
+     You should have received a copy of the GNU Affero General Public License
+     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+     SPDX-License-Identifier: AGPL3.0-or-later
+ */
 #include "platform.h"
 #include "gnunet_util_lib.h"
 #include "gnunet_nt_lib.h"
@@ -23,12 +42,12 @@ main (int argc,
                              GNUNET_NT_LAN,
                              t,
                              &privKey,
-                             (void**)&res,
+                             (void**) &res,
                              &res_len);
   GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
               "%s\n", res);
   GNUNET_assert (NULL !=
-                 GNUNET_HELLO_extract_address ((void**)res,
+                 GNUNET_HELLO_extract_address ((void**) res,
                                                res_len,
                                                &pid,
                                                &nt,
diff --git a/src/hello/test_hello-uri.c b/src/hello/test_hello-uri.c
new file mode 100644
index 000000000..295c08ea3
--- /dev/null
+++ b/src/hello/test_hello-uri.c
@@ -0,0 +1,176 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2022 GNUnet e.V.
+
+     GNUnet is free software: you can redistribute it and/or modify it
+     under the terms of the GNU Affero General Public License as published
+     by the Free Software Foundation, either version 3 of the License,
+     or (at your option) any later version.
+
+     GNUnet 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
+     Affero General Public License for more details.
+
+     You should have received a copy of the GNU Affero General Public License
+     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+     SPDX-License-Identifier: AGPL3.0-or-later
+ */
+/**
+ * @file hello/test_hello-uri.c
+ * @brief test for helper library for handling URI-based HELLOs
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_signatures.h"
+#include "gnunet_hello_uri_lib.h"
+#include "gnunet_util_lib.h"
+
+
+/**
+ * Check for expected URIs.
+ *
+ * @param cls a `unsigned int*`, bitmask set to found URIs
+ * @param uri URI to check for
+ */
+static void
+check_uris (void *cls,
+            const char *uri)
+{
+  unsigned int *found = cls;
+
+  if (0 == strcmp (uri,
+                   "test://address"))
+    *found |= 1;
+  else if (0 == strcmp (uri,
+                   "test://more"))
+    *found |= 2;
+  else
+    *found = (unsigned int) -1;
+}
+
+
+int
+main (int argc,
+      char *argv[])
+{
+  struct GNUNET_PeerIdentity pid;
+  struct GNUNET_HELLO_Builder *b;
+  struct GNUNET_CRYPTO_EddsaPrivateKey priv;
+
+  GNUNET_log_setup ("test-hell-uri",
+                    "WARNING",
+                    NULL);
+  GNUNET_CRYPTO_eddsa_key_create (&priv);
+  GNUNET_CRYPTO_eddsa_key_get_public (&priv,
+                                      &pid.public_key);
+  b = GNUNET_HELLO_builder_new (&pid);
+  GNUNET_assert (GNUNET_SYSERR ==
+                 GNUNET_HELLO_builder_add_address (b,
+                                                   "invalid"));
+  GNUNET_assert (GNUNET_SYSERR ==
+                 GNUNET_HELLO_builder_add_address (b,
+                                                   "i%v://bla"));
+  GNUNET_assert (GNUNET_SYSERR ==
+                 GNUNET_HELLO_builder_add_address (b,
+                                                   "://empty"));
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_HELLO_builder_add_address (b,
+                                                   "test://address"));
+  GNUNET_assert (GNUNET_NO ==
+                 GNUNET_HELLO_builder_add_address (b,
+                                                   "test://address"));
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_HELLO_builder_add_address (b,
+                                                   "test://more"));
+  {
+    void *block;
+    size_t block_size = 0;
+    struct GNUNET_HELLO_Builder *b2;
+    struct GNUNET_PeerIdentity p2;
+    unsigned int found;
+
+    GNUNET_assert (GNUNET_NO ==
+                   GNUNET_HELLO_builder_to_block (b,
+                                                  &priv,
+                                                  NULL,
+                                                  &block_size));
+    GNUNET_assert (GNUNET_NO ==
+                   GNUNET_HELLO_builder_to_block (b,
+                                                  &priv,
+                                                  NULL,
+                                                  &block_size));
+    GNUNET_assert (0 != block_size);
+    block = GNUNET_malloc (block_size);
+    GNUNET_assert (GNUNET_OK ==
+                   GNUNET_HELLO_builder_to_block (b,
+                                                  &priv,
+                                                  block,
+                                                  &block_size));
+    b2 = GNUNET_HELLO_builder_from_block (block,
+                                          block_size);
+    GNUNET_free (block);
+    GNUNET_assert (NULL != b2);
+    found = 0;
+    GNUNET_HELLO_builder_iterate (b2,
+                                  &p2,
+                                  &check_uris,
+                                  &found);
+    GNUNET_assert (3 == found);
+    GNUNET_assert (0 ==
+                   GNUNET_memcmp (&p2,
+                                  &pid));
+    GNUNET_HELLO_builder_free (b2);
+  }
+
+  {
+    char *url;
+    struct GNUNET_HELLO_Builder *b2;
+    struct GNUNET_PeerIdentity p2;
+    unsigned int found;
+
+    url = GNUNET_HELLO_builder_to_url (b,
+                                       &priv);
+    b2 = GNUNET_HELLO_builder_from_url (url);
+    GNUNET_free (url);
+    GNUNET_assert (NULL != b2);
+    found = 0;
+    GNUNET_HELLO_builder_iterate (b2,
+                                  &p2,
+                                  &check_uris,
+                                  &found);
+    GNUNET_assert (3 == found);
+    GNUNET_assert (0 ==
+                   GNUNET_memcmp (&p2,
+                                  &pid));
+    GNUNET_HELLO_builder_free (b2);
+  }
+
+  {
+    struct GNUNET_MQ_Envelope *env;
+    struct GNUNET_HELLO_Builder *b2;
+    struct GNUNET_PeerIdentity p2;
+    unsigned int found;
+
+    env = GNUNET_HELLO_builder_to_env (b,
+                                       &priv);
+    b2 = GNUNET_HELLO_builder_from_msg (GNUNET_MQ_env_get_msg (env));
+    GNUNET_free (env);
+    GNUNET_assert (NULL != b2);
+    found = 0;
+    GNUNET_HELLO_builder_iterate (b2,
+                                  &p2,
+                                  &check_uris,
+                                  &found);
+    GNUNET_assert (3 == found);
+    GNUNET_assert (0 ==
+                   GNUNET_memcmp (&p2,
+                                  &pid));
+    GNUNET_HELLO_builder_free (b2);
+  }
+
+
+  GNUNET_HELLO_builder_free (b);
+  return 0;
+}
diff --git a/src/include/gnunet_hello_uri_lib.h 
b/src/include/gnunet_hello_uri_lib.h
index dbf4dc35e..ec9cdfa5e 100644
--- a/src/include/gnunet_hello_uri_lib.h
+++ b/src/include/gnunet_hello_uri_lib.h
@@ -103,26 +103,30 @@ GNUNET_HELLO_builder_from_url (const char *url);
  * Generate HELLO message from a @a builder
  *
  * @param builder builder to serialize
+ * @param priv private key to use to sign the result
  * @return HELLO message matching @a builder
  */
 struct GNUNET_MQ_Envelope *
-GNUNET_HELLO_builder_to_env (struct GNUNET_HELLO_Builder *builder);
+GNUNET_HELLO_builder_to_env (const struct GNUNET_HELLO_Builder *builder,
+                             const struct GNUNET_CRYPTO_EddsaPrivateKey *priv);
 
 
 /**
  * Generate GNUnet HELLO URI from a @a builder
  *
  * @param builder builder to serialize
+ * @param priv private key to use to sign the result
  * @return hello URI
  */
 char *
-GNUNET_HELLO_builder_to_url (struct GNUNET_HELLO_Builder *builder);
-
+GNUNET_HELLO_builder_to_url (const struct GNUNET_HELLO_Builder *builder,
+                             const struct GNUNET_CRYPTO_EddsaPrivateKey *priv);
 
 /**
  * Generate DHT block from a @a builder
  *
  * @param builder the builder to serialize
+ * @param priv private key to use to sign the result
  * @param[out] block where to write the block, NULL to only calculate @a 
block_size
  * @param[in,out] block_size input is number of bytes available in @a block,
  *                           output is number of bytes needed in @a block
@@ -130,7 +134,8 @@ GNUNET_HELLO_builder_to_url (struct GNUNET_HELLO_Builder 
*builder);
  *      or if @a block was NULL
  */
 enum GNUNET_GenericReturnValue
-GNUNET_HELLO_builder_to_block (struct GNUNET_HELLO_Builder *builder,
+GNUNET_HELLO_builder_to_block (const struct GNUNET_HELLO_Builder *builder,
+                               const struct GNUNET_CRYPTO_EddsaPrivateKey 
*priv,
                                void *block,
                                size_t *block_size);
 
diff --git a/src/include/gnunet_strings_lib.h b/src/include/gnunet_strings_lib.h
index 09c547b09..bb8577b7a 100644
--- a/src/include/gnunet_strings_lib.h
+++ b/src/include/gnunet_strings_lib.h
@@ -458,7 +458,7 @@ GNUNET_STRINGS_base64url_decode (const char *data,
  *
  * @param data the data to encode
  * @param len the length of the input
- * @param output where to write the output (*output should be NULL,
+ * @param[out] out where to write the output (*output should be NULL,
  *   is allocated)
  * @return the size of the output
  */
diff --git a/src/include/gnunet_time_lib.h b/src/include/gnunet_time_lib.h
index b14439462..96413c3cc 100644
--- a/src/include/gnunet_time_lib.h
+++ b/src/include/gnunet_time_lib.h
@@ -762,10 +762,21 @@ GNUNET_TIME_absolute_from_s (uint64_t s_after_epoch);
  *
  * @param s_after_epoch seconds after epoch to convert
  * @return converted time value
- */struct GNUNET_TIME_Timestamp
+ */
+struct GNUNET_TIME_Timestamp
 GNUNET_TIME_timestamp_from_s (uint64_t s_after_epoch);
 
 
+/**
+ * Convert timestamp to number of seconds after the UNIX epoch.
+ *
+ * @param ts timestamp to convert
+ * @return converted time value
+ */
+uint64_t
+GNUNET_TIME_timestamp_to_s (struct GNUNET_TIME_Timestamp ts);
+
+
 /**
  * Convert absolute time from network byte order.
  *
diff --git a/src/util/strings.c b/src/util/strings.c
index a77f09022..7e218cc59 100644
--- a/src/util/strings.c
+++ b/src/util/strings.c
@@ -1813,12 +1813,19 @@ GNUNET_STRINGS_urldecode (const char *data,
   char *wpos = *out;
   size_t resl = 0;
 
-  while ('\0' != *rpos)
+  while ( ('\0' != *rpos) &&
+          (data + len != rpos) )
   {
     unsigned int num;
     switch (*rpos)
     {
     case '%':
+      if (rpos + 3 > data + len)
+      {
+        GNUNET_break_op (0);
+        GNUNET_free (*out);
+        return 0;
+      }
       if (1 != sscanf (rpos + 1, "%2x", &num))
         break;
       *wpos = (char) ((unsigned char) num);
diff --git a/src/util/time.c b/src/util/time.c
index 83b39b4e8..68a6937a0 100644
--- a/src/util/time.c
+++ b/src/util/time.c
@@ -695,6 +695,13 @@ GNUNET_TIME_timestamp_from_s (uint64_t s_after_epoch)
 }
 
 
+uint64_t
+GNUNET_TIME_timestamp_to_s (struct GNUNET_TIME_Timestamp ts)
+{
+  return ts.abs_time.abs_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us;
+}
+
+
 struct GNUNET_TIME_Absolute
 GNUNET_TIME_absolute_ntoh (struct GNUNET_TIME_AbsoluteNBO a)
 {

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