tests: Prevent rare failure of gcry_pk_decrypt test.
[libgcrypt.git] / tests / pkbench.c
index 395bef5..15192f0 100644 (file)
@@ -1,5 +1,5 @@
 /* pkbench.c - Pubkey menchmarking
- *     Copyright (C) 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2004, 2005, 2008 Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
  * GNU Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
 #include <stdio.h>
 #include <gcrypt.h>
 #include <assert.h>
 #include <stdlib.h>
-#include <sys/mman.h>
+#include <ctype.h>
 #include <sys/stat.h>
-#include <sys/times.h>
+#ifndef HAVE_W32_SYSTEM
+# include <sys/times.h>
+#endif /*HAVE_W32_SYSTEM*/
 #include <unistd.h>
 #include <fcntl.h>
+#include <time.h>
+#include <errno.h>
+
+#define PGM "pkbench"
+
+
+static int verbose;
+static int debug;
+static int error_count;
+
 
 typedef struct context
 {
@@ -39,6 +53,88 @@ typedef struct context
 
 typedef int (*work_t) (context_t context, unsigned int final);
 
+
+static void
+fail (const char *format, ...)
+{
+  va_list arg_ptr;
+
+  fputs ( PGM ": ", stderr);
+  va_start (arg_ptr, format);
+  vfprintf (stderr, format, arg_ptr);
+  va_end (arg_ptr);
+  error_count++;
+}
+
+static void
+die (const char *format, ...)
+{
+  va_list arg_ptr;
+
+  putchar ('\n');
+  fputs ( PGM ": ", stderr);
+  va_start (arg_ptr, format);
+  vfprintf (stderr, format, arg_ptr);
+  va_end (arg_ptr);
+  exit (1);
+}
+
+static void
+show_sexp (const char *prefix, gcry_sexp_t a)
+{
+  char *buf;
+  size_t size;
+
+  fputs (prefix, stderr);
+  size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0);
+  buf = gcry_xmalloc (size);
+
+  gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size);
+  fprintf (stderr, "%.*s", (int)size, buf);
+  gcry_free (buf);
+}
+
+
+static void *
+read_file (const char *fname, size_t *r_length)
+{
+  FILE *fp;
+  struct stat st;
+  char *buf;
+  size_t buflen;
+
+  fp = fopen (fname, "rb");
+  if (!fp)
+    {
+      fail ("can't open `%s': %s\n", fname, strerror (errno));
+      return NULL;
+    }
+
+  if (fstat (fileno(fp), &st))
+    {
+      fail ("can't stat `%s': %s\n", fname, strerror (errno));
+      fclose (fp);
+      return NULL;
+    }
+
+  buflen = st.st_size;
+  buf = gcry_xmalloc (buflen+1);
+  if (fread (buf, buflen, 1, fp) != 1)
+    {
+      fail ("error reading `%s': %s\n", fname, strerror (errno));
+      fclose (fp);
+      gcry_free (buf);
+      return NULL;
+    }
+  fclose (fp);
+
+  if (r_length)
+    *r_length = buflen;
+  return buf;
+}
+
+
+
 static void
 benchmark (work_t worker, context_t context)
 {
@@ -48,16 +144,24 @@ benchmark (work_t worker, context_t context)
   struct tms timer;
   int ret = 0;
 
+#ifdef HAVE_W32_SYSTEM
+  timer_start = clock ();
+#else
   times (&timer);
   timer_start = timer.tms_utime;
+#endif
   for (i = 0; i < loop; i++)
     {
       ret = (*worker) (context, (i + 1) == loop);
       if (! ret)
        break;
     }
+#ifdef HAVE_W32_SYSTEM
+  timer_stop = clock ();
+#else
   times (&timer);
   timer_stop = timer.tms_utime;
+#endif
 
   if (ret)
     printf ("%.0f ms\n",
@@ -105,7 +209,7 @@ work_decrypt (context_t context, unsigned int final)
   else
     {
       gcry_sexp_t data_decrypted = NULL;
-      
+
       err = gcry_pk_decrypt (&data_decrypted,
                             context->data_encrypted,
                             context->key_secret);
@@ -135,10 +239,13 @@ work_sign (context_t context, unsigned int final)
       err = GPG_ERR_NO_ERROR;
       ret = 0;
     }
+  else if (err)
+    {
+      fail ("pk_sign failed: %s\n", gpg_strerror (err));
+      ret = 0;
+    }
   else
     {
-      assert (! err);
-
       if (final)
        context->data_signed = data_signed;
       else
@@ -154,19 +261,23 @@ work_verify (context_t context, unsigned int final)
   gcry_error_t err = GPG_ERR_NO_ERROR;
   int ret = 1;
 
-  if (! context->data_signed)
-    ret = 0;
-  else
+  if (!context->data_signed)
+    return 0;
+
+  err = gcry_pk_verify (context->data_signed,
+                        context->data,
+                        context->key_public);
+  if (err)
     {
-      err = gcry_pk_verify (context->data_signed,
-                           context->data,
-                           context->key_public);
-      assert (! err);
-      if (final)
-       {
-         gcry_sexp_release (context->data_signed);
-         context->data_signed = NULL;
-       }
+      show_sexp ("data_signed:\n", context->data_signed);
+      show_sexp ("data:\n", context->data);
+      fail ("pk_verify failed: %s\n", gpg_strerror (err));
+      ret = 0;
+    }
+  else if (final)
+    {
+      gcry_sexp_release (context->data_signed);
+      context->data_signed = NULL;
     }
 
   return ret;
@@ -238,23 +349,16 @@ process_key_pair_file (const char *key_pair_file)
   gcry_sexp_t key_secret_sexp = NULL;
   gcry_sexp_t key_public_sexp = NULL;
   struct context context = { NULL };
-  struct stat statbuf;
-  int key_pair_fd = -1;
-  int ret = 0;
-
-  ret = stat (key_pair_file, &statbuf);
-  assert (! ret);
+  size_t file_length;
 
-  key_pair_fd = open (key_pair_file, O_RDONLY);
-  assert (key_pair_fd != -1);
-
-  key_pair_buffer = mmap (NULL, statbuf.st_size, PROT_READ,
-                         MAP_PRIVATE, key_pair_fd, 0);
-  assert (key_pair_buffer != MAP_FAILED);
+  key_pair_buffer = read_file (key_pair_file, &file_length);
+  if (!key_pair_buffer)
+    die ("failed to open `%s'\n", key_pair_file);
 
   err = gcry_sexp_sscan (&key_pair_sexp, NULL,
-                        key_pair_buffer, statbuf.st_size);
-  assert (! err);
+                        key_pair_buffer, file_length);
+  if (err)
+    die ("gcry_sexp_sscan failed\n");
 
   key_secret_sexp = gcry_sexp_find_token (key_pair_sexp, "private-key", 0);
   assert (key_secret_sexp);
@@ -262,10 +366,6 @@ process_key_pair_file (const char *key_pair_file)
   assert (key_public_sexp);
 
   gcry_sexp_release (key_pair_sexp);
-  ret = munmap (key_pair_buffer, statbuf.st_size);
-  assert (! ret);
-  ret = close (key_pair_fd);
-  assert (! ret);
 
   context_init (&context, key_secret_sexp, key_public_sexp);
 
@@ -274,18 +374,9 @@ process_key_pair_file (const char *key_pair_file)
   printf ("\n");
 
   context_destroy (&context);
+  gcry_free (key_pair_buffer);
 }
 
-static const char *program_name = NULL;
-
-static void
-print_usage (int err)
-{
-  fprintf (err ? stderr : stdout,
-          "Usage: %s [--help ] [ --genkey <algorithm>,<size> ] <key files ...>\n\n",
-          program_name);
-  exit (err);
-}
 
 static void
 generate_key (const char *algorithm, const char *key_size)
@@ -296,64 +387,128 @@ generate_key (const char *algorithm, const char *key_size)
   gcry_sexp_t key_spec = NULL;
   gcry_sexp_t key_pair = NULL;
 
-  err = gcry_sexp_build (&key_spec, NULL,
-                        "(genkey (%s (nbits %s)))",
-                        algorithm, key_size);
-  assert (! err);
+  if (isdigit ((unsigned int)*key_size))
+    err = gcry_sexp_build (&key_spec, NULL,
+                           "(genkey (%s (nbits %s)))",
+                           algorithm, key_size);
+  else
+    err = gcry_sexp_build (&key_spec, NULL,
+                           "(genkey (%s (curve %s)))",
+                           algorithm, key_size);
+  if (err)
+    die ("sexp_build failed: %s\n", gpg_strerror (err));
 
   err = gcry_pk_genkey (&key_pair, key_spec);
-  assert (! err);
+  if (err)
+    {
+      show_sexp ("request:\n", key_spec);
+      die ("pk_genkey failed: %s\n", gpg_strerror (err));
+    }
 
   key_pair_buffer_size = gcry_sexp_sprint (key_pair, GCRYSEXP_FMT_ADVANCED,
                                           NULL, 0);
-  key_pair_buffer = malloc (key_pair_buffer_size);
-  assert (key_pair_buffer);
+  key_pair_buffer = gcry_xmalloc (key_pair_buffer_size);
 
   gcry_sexp_sprint (key_pair, GCRYSEXP_FMT_ADVANCED,
                    key_pair_buffer, key_pair_buffer_size);
 
-  printf ("%.*s", key_pair_buffer_size, key_pair_buffer);
+  printf ("%.*s", (int)key_pair_buffer_size, key_pair_buffer);
+  gcry_free (key_pair_buffer);
 }
 
+
+
 int
 main (int argc, char **argv)
 {
-  program_name = argc ? argv[0] : "";
+  int last_argc = -1;
+  int genkey_mode = 0;
+  int fips_mode = 0;
+
+  if (argc)
+    { argc--; argv++; }
+
+  while (argc && last_argc != argc )
+    {
+      last_argc = argc;
+      if (!strcmp (*argv, "--"))
+        {
+          argc--; argv++;
+          break;
+        }
+      else if (!strcmp (*argv, "--help"))
+        {
+          puts ("Usage: " PGM " [OPTIONS] [FILES]\n"
+                "Various public key tests:\n\n"
+                "  Default is to process all given key files\n\n"
+                "  --genkey ALGONAME SIZE  Generate a public key\n"
+                "\n"
+                "  --verbose    enable extra informational output\n"
+                "  --debug      enable additional debug output\n"
+                "  --help       display this help and exit\n\n");
+          exit (0);
+        }
+      else if (!strcmp (*argv, "--verbose"))
+        {
+          verbose++;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--debug"))
+        {
+          verbose = debug = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--genkey"))
+        {
+          genkey_mode = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--fips"))
+        {
+          fips_mode = 1;
+          argc--; argv++;
+        }
+    }
+
+  gcry_control (GCRYCTL_SET_VERBOSITY, (int)verbose);
+
+  if (fips_mode)
+    gcry_control (GCRYCTL_FORCE_FIPS_MODE, 0);
 
   gcry_control (GCRYCTL_DISABLE_SECMEM);
-  
-  if (argv[1] && ((! strcmp (argv[1], "--help"))
-                 || (! strcmp (argv[1], "-h"))))
-    print_usage (0);
-  else if (argv[1] && ((! strcmp (argv[1], "--genkey"))
-                      || (! strcmp (argv[1], "-g"))))
+  if (!gcry_check_version (GCRYPT_VERSION))
     {
-      char *algorithm = NULL;
-      char *key_size = NULL;
+      fprintf (stderr, PGM ": version mismatch\n");
+      exit (1);
+    }
 
-      if (argv[2])
-       {
-         algorithm = argv[2];
-         key_size = strchr (algorithm, ',');
-         if (key_size)
-           {
-             *key_size = 0;
-             key_size++;
-           }
-       }
+  if (genkey_mode)
+    {
+      /* No valuable keys are create, so we can speed up our RNG. */
+      gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+    }
+  if (debug)
+    gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
+  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
 
-      if (algorithm && key_size)
-       generate_key (algorithm, key_size);
-      else
-       print_usage (EXIT_FAILURE);
+
+  if (genkey_mode && argc == 2)
+    {
+      generate_key (argv[0], argv[1]);
     }
-  else
+  else if (!genkey_mode && argc)
     {
-      unsigned int i = 0;
+      int i;
 
-      for (i = 1; (i < argc); i++)
+      for (i = 0; i < argc; i++)
        process_key_pair_file (argv[i]);
     }
+  else
+    {
+      fprintf (stderr, "usage: " PGM
+               " [OPTIONS] [FILES] (try --help for more information)\n");
+      exit (1);
+    }
 
-  return EXIT_SUCCESS;
+  return error_count ? 1 : 0;
 }