work-around for crypto bug (to be documented more)
authorChristian Grothoff <christian@grothoff.org>
Thu, 17 May 2018 10:26:30 +0000 (12:26 +0200)
committerChristian Grothoff <christian@grothoff.org>
Thu, 17 May 2018 10:26:30 +0000 (12:26 +0200)
contrib/testing_hostkeys.ecc
src/cadet/gnunet-service-cadet_tunnels.c
src/util/Makefile.am
src/util/crypto_bug.c [new file with mode: 0644]
src/util/crypto_ecc.c
src/util/crypto_ecc_setup.c
src/util/test_crypto_ecdh_eddsa.c

index 194d0da78492aa13895b640e9e50e96de6a35f75..23e5d3379f826f114beb35b97d6c06315b594cd2 100644 (file)
Binary files a/contrib/testing_hostkeys.ecc and b/contrib/testing_hostkeys.ecc differ
index 2565b8f185b2c51151217d24612ee737b4f7e040..75d454522fa53d9bc748745ea535f71701b10aa9 100644 (file)
@@ -1889,9 +1889,11 @@ GCT_handle_kx_auth (struct CadetTConnection *ct,
                               GNUNET_NO);
     LOG (GNUNET_ERROR_TYPE_WARNING,
          "KX AUTH missmatch!\n");
-    send_kx (t,
-             ct,
-             &t->ax);
+    if (NULL == t->kx_task)
+      t->kx_task
+        = GNUNET_SCHEDULER_add_at (t->next_kx_attempt,
+                                   &retry_kx,
+                                   t);
     return;
   }
   /* Yep, we're good. */
index eb655157d834a27eafa9aa00565b3713d7bbb7bd..407f482df83661cad38b12123dce5a5b69bcbe85 100644 (file)
@@ -598,4 +598,5 @@ EXTRA_DIST = \
   test_resolver_api_data.conf \
   test_service_data.conf \
   test_speedup_data.conf \
-  gnunet-qr.py.in
+  gnunet-qr.py.in \
+  crypto_bug.c
diff --git a/src/util/crypto_bug.c b/src/util/crypto_bug.c
new file mode 100644 (file)
index 0000000..c25e79c
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+     This file is part of GNUnet.
+     Copyright (C) 2018 GNUnet e.V.
+
+     GNUnet 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 Foundation; either version 3, 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
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file util/crypto_bug.c
+ * @brief work around unidentified public key cryptography bug
+ * @author Christian Grothoff
+ */
+
+/**
+ * Enable work-around.  Will cause code to call #check_eddsa_key() to
+ * see if we have a bad key, and if so, create a new one.
+ */
+#define CRYPTO_BUG 1
+
+
+#if CRYPTO_BUG
+/**
+ * Check if ECDH works with @a priv_dsa and this version
+ * of libgcrypt.
+ *
+ * @param priv_dsa key to check
+ * @return #GNUNET_OK if key passes
+ */
+static int
+check_eddsa_key (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv_dsa)
+{
+  struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ecdh;
+  struct GNUNET_CRYPTO_EddsaPublicKey id1;
+  struct GNUNET_CRYPTO_EcdhePublicKey id2;
+  struct GNUNET_HashCode dh[2];
+
+  GNUNET_CRYPTO_eddsa_key_get_public (priv_dsa,
+                                      &id1);
+  for (unsigned int j=0;j<4;j++)
+  {
+    priv_ecdh = GNUNET_CRYPTO_ecdhe_key_create ();
+    /* Extract public keys */
+    GNUNET_CRYPTO_ecdhe_key_get_public (priv_ecdh,
+                                        &id2);
+    /* Do ECDH */
+    GNUNET_assert (GNUNET_OK ==
+                   GNUNET_CRYPTO_eddsa_ecdh (priv_dsa,
+                                             &id2,
+                                             &dh[0]));
+    GNUNET_assert (GNUNET_OK ==
+                   GNUNET_CRYPTO_ecdh_eddsa (priv_ecdh,
+                                             &id1,
+                                             &dh[1]));
+    /* Check that both DH results are equal. */
+    if (0 != memcmp (&dh[0],
+                     &dh[1],
+                     sizeof (struct GNUNET_HashCode)))
+    {
+      GNUNET_break (0); /* bad EdDSA key! */
+      return GNUNET_SYSERR;
+    }
+    GNUNET_free (priv_ecdh);
+  }
+  return GNUNET_OK;
+}
+#endif
index 8cc6c18cbdab5118fe51f2755e0e4e08c62aa6d3..1abf0fddc1c871065d1f75330e56bc00bb29306c 100644 (file)
@@ -52,6 +52,9 @@
 #define LOG_GCRY(level, cmd, rc) do { LOG(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, gcry_strerror(rc)); } while(0)
 
 
+#include "crypto_bug.c"
+
+
 /**
  * Extract values from an S-expression.
  *
@@ -455,7 +458,7 @@ GNUNET_CRYPTO_eddsa_public_key_from_string (const char *enc,
 int
 GNUNET_CRYPTO_eddsa_private_key_from_string (const char *enc,
                                              size_t enclen,
-                                             struct GNUNET_CRYPTO_EddsaPrivateKey *pub)
+                                             struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
 {
   size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
 
@@ -465,10 +468,19 @@ GNUNET_CRYPTO_eddsa_private_key_from_string (const char *enc,
   if (enclen != keylen)
     return GNUNET_SYSERR;
 
-  if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
-                                                 pub,
-                                                 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_string_to_data (enc, enclen,
+                                     priv,
+                                     sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
     return GNUNET_SYSERR;
+#if CRYPTO_BUG
+  if (GNUNET_OK !=
+      check_eddsa_key (priv))
+  {
+    GNUNET_break (0);
+    return GNUNET_OK;
+  }
+#endif
   return GNUNET_OK;
 }
 
@@ -651,6 +663,9 @@ GNUNET_CRYPTO_eddsa_key_create ()
   gcry_mpi_t d;
   int rc;
 
+#if CRYPTO_BUG
+ again:
+#endif
   if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
                                   "(genkey(ecc(curve \"" CURVE "\")"
                                   "(flags eddsa)))")))
@@ -683,6 +698,17 @@ GNUNET_CRYPTO_eddsa_key_create ()
   priv = GNUNET_new (struct GNUNET_CRYPTO_EddsaPrivateKey);
   GNUNET_CRYPTO_mpi_print_unsigned (priv->d, sizeof (priv->d), d);
   gcry_mpi_release (d);
+
+#if CRYPTO_BUG
+  if (GNUNET_OK !=
+      check_eddsa_key (priv))
+  {
+    GNUNET_break (0);
+    GNUNET_free (priv);
+    goto again;
+  }
+#endif
+
   return priv;
 }
 
index e7caf9ded3a5348f940ac7f6510a2399c21096aa..76c25dc70def897da08806359914d2ddcafad8e7 100644 (file)
@@ -41,6 +41,9 @@
 #define LOG_GCRY(level, cmd, rc) do { LOG(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, gcry_strerror(rc)); } while(0)
 
 
+#include "crypto_bug.c"
+
+
 /**
  * Wait for a short time (we're trying to lock a file or want
  * to give another process a shot at finishing a disk write, etc.).
@@ -221,6 +224,15 @@ GNUNET_CRYPTO_eddsa_key_create_from_file (const char *filename)
                       filename);
   GNUNET_assert (GNUNET_YES ==
                 GNUNET_DISK_file_close (fd));
+#if CRYPTO_BUG
+  if (GNUNET_OK !=
+      check_eddsa_key (priv))
+  {
+    GNUNET_break (0);
+    GNUNET_free (priv);
+    return NULL;
+  }
+#endif
   return priv;
 }
 
@@ -248,7 +260,7 @@ GNUNET_CRYPTO_ecdsa_key_create_from_file (const char *filename)
   int ec;
   uint64_t fs;
   ssize_t sret;
-  
+
   if (GNUNET_SYSERR ==
       GNUNET_DISK_directory_create_for_file (filename))
     return NULL;
index 246cec27f84a90f6cc243a7aec00e165781d7e02..356c64bf175a705d84367fa8196f1386ccabd0c2 100644 (file)
@@ -36,31 +36,35 @@ test_ecdh()
   struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ecdh;
   struct GNUNET_CRYPTO_EddsaPublicKey id1;
   struct GNUNET_CRYPTO_EcdhePublicKey id2;
-  struct GNUNET_HashCode dh[3];
+  struct GNUNET_HashCode dh[2];
 
   /* Generate keys */
   priv_dsa = GNUNET_CRYPTO_eddsa_key_create ();
-  priv_ecdh = GNUNET_CRYPTO_ecdhe_key_create ();
-  /* Extract public keys */
   GNUNET_CRYPTO_eddsa_key_get_public (priv_dsa,
                                       &id1);
-  GNUNET_CRYPTO_ecdhe_key_get_public (priv_ecdh,
-                                      &id2);
-  /* Do ECDH */
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CRYPTO_eddsa_ecdh (priv_dsa,
-                                           &id2,
-                                           &dh[0]));
-  GNUNET_assert (GNUNET_OK ==
-                 GNUNET_CRYPTO_ecdh_eddsa (priv_ecdh,
-                                           &id1,
-                                           &dh[1]));
-  /* Check that both DH results are equal. */
-  GNUNET_assert (0 == memcmp (&dh[0],
-                              &dh[1],
-                             sizeof (struct GNUNET_HashCode)));
+  for (unsigned int j=0;j<10;j++)
+  {
+    fprintf (stderr, ",");
+    priv_ecdh = GNUNET_CRYPTO_ecdhe_key_create ();
+    /* Extract public keys */
+    GNUNET_CRYPTO_ecdhe_key_get_public (priv_ecdh,
+                                        &id2);
+    /* Do ECDH */
+    GNUNET_assert (GNUNET_OK ==
+                   GNUNET_CRYPTO_eddsa_ecdh (priv_dsa,
+                                             &id2,
+                                             &dh[0]));
+    GNUNET_assert (GNUNET_OK ==
+                   GNUNET_CRYPTO_ecdh_eddsa (priv_ecdh,
+                                             &id1,
+                                             &dh[1]));
+    /* Check that both DH results are equal. */
+    GNUNET_assert (0 == memcmp (&dh[0],
+                                &dh[1],
+                                sizeof (struct GNUNET_HashCode)));
+    GNUNET_free (priv_ecdh);
+  }
   GNUNET_free (priv_dsa);
-  GNUNET_free (priv_ecdh);
   return 0;
 }
 
@@ -78,7 +82,7 @@ main (int argc, char *argv[])
   if (getenv ("GNUNET_GCRYPT_DEBUG"))
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
   GNUNET_log_setup ("test-crypto-ecdh-eddsa", "WARNING", NULL);
-  for (unsigned int i=0;i<10000;i++)
+  for (unsigned int i=0;i<100;i++)
   {
     fprintf (stderr,
              ".");