api: New function gcry_get_config.
[libgcrypt.git] / tests / keygen.c
index 25f753e..6b6a60a 100644 (file)
@@ -1,5 +1,6 @@
 /* keygen.c  -  key generation regression tests
- *     Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+ * Copyright (C) 2003, 2005, 2012 Free Software Foundation, Inc.
+ * Copyright (C) 2013, 2015 g10 Code GmbH
  *
  * This file is part of Libgcrypt.
  *
@@ -14,8 +15,7 @@
  * 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 <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
-#include "../src/gcrypt.h"
+#include "../src/gcrypt-int.h"
 
 
+#define PGM "keygen"
+#include "t-common.h"
 
-static int verbose;
-static int debug;
-static int error_count;
+static int in_fips_mode;
 
-static void
-fail ( const char *format, ... )
-{
-    va_list arg_ptr ;
 
-    va_start( arg_ptr, format ) ;
-    vfprintf (stderr, format, arg_ptr );
-    va_end(arg_ptr);
-    error_count++;
-}
+/* static void */
+/* show_note (const char *format, ...) */
+/* { */
+/*   va_list arg_ptr; */
+
+/*   if (!verbose && getenv ("srcdir")) */
+/*     fputs ("      ", stderr);  /\* To align above "PASS: ".  *\/ */
+/*   else */
+/*     fprintf (stderr, "%s: ", PGM); */
+/*   va_start (arg_ptr, format); */
+/*   vfprintf (stderr, format, arg_ptr); */
+/*   if (*format && format[strlen(format)-1] != '\n') */
+/*     putc ('\n', stderr); */
+/*   va_end (arg_ptr); */
+/* } */
+
 
 static void
-die ( const char *format, ... )
+show_sexp (const char *prefix, gcry_sexp_t a)
 {
-    va_list arg_ptr ;
+  char *buf;
+  size_t size;
 
-    va_start( arg_ptr, format ) ;
-    vfprintf (stderr, format, arg_ptr );
-    va_end(arg_ptr);
-    exit (1);
+  fprintf (stderr, "%s: ", PGM);
+  if (prefix)
+    fputs (prefix, stderr);
+  size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0);
+  buf = xmalloc (size);
+
+  gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size);
+  fprintf (stderr, "%.*s", (int)size, buf);
+  gcry_free (buf);
 }
 
 
 static void
-print_mpi (const char *text, gcry_mpi_t a)
+show_mpi (const char *prefix, gcry_mpi_t a)
 {
   char *buf;
   void *bufaddr = &buf;
   gcry_error_t rc;
 
+  fprintf (stderr, "%s: ", PGM);
+  if (prefix)
+    fputs (prefix, stderr);
   rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a);
   if (rc)
-    fprintf (stderr, "%s=[error printing number: %s]\n",
-             text, gpg_strerror (rc));
+    fprintf (stderr, "[error printing number: %s]\n",  gpg_strerror (rc));
   else
     {
-      fprintf (stderr, "%s=0x%s\n", text, buf);
+      fprintf (stderr, "%s\n", buf);
       gcry_free (buf);
     }
 }
@@ -93,18 +108,18 @@ check_generated_rsa_key (gcry_sexp_t key, unsigned long expected_e)
       else if (!expected_e)
         {
           if (verbose)
-            print_mpi ("e", e);
+            show_mpi ("public exponent: ", e);
         }
-      else if ( gcry_mpi_cmp_ui (e, expected_e)) 
+      else if ( gcry_mpi_cmp_ui (e, expected_e))
         {
-          print_mpi ("e", e);
+          show_mpi ("public exponent: ", e);
           fail ("public exponent is not %lu\n", expected_e);
         }
       gcry_sexp_release (list);
       gcry_mpi_release (e);
       gcry_sexp_release (pkey);
     }
+
   skey = gcry_sexp_find_token (key, "private-key", 0);
   if (!skey)
     fail ("private part missing in return value\n");
@@ -115,23 +130,167 @@ check_generated_rsa_key (gcry_sexp_t key, unsigned long expected_e)
         fail ("gcry_pk_testkey failed: %s\n", gpg_strerror (rc));
       gcry_sexp_release (skey);
     }
+}
 
- }
 
 static void
 check_rsa_keys (void)
 {
   gcry_sexp_t keyparm, key;
   int rc;
+
+  if (verbose)
+    info ("creating 2048 bit RSA key\n");
+  rc = gcry_sexp_new (&keyparm,
+                      "(genkey\n"
+                      " (rsa\n"
+                      "  (nbits 4:2048)\n"
+                      " ))", 0, 1);
+  if (rc)
+    die ("error creating S-expression: %s\n", gpg_strerror (rc));
+  rc = gcry_pk_genkey (&key, keyparm);
+  gcry_sexp_release (keyparm);
+  if (rc)
+    die ("error generating RSA key: %s\n", gpg_strerror (rc));
+
+  if (verbose)
+    info ("creating 1024 bit RSA key\n");
+  rc = gcry_sexp_new (&keyparm,
+                      "(genkey\n"
+                      " (rsa\n"
+                      "  (nbits 4:1024)\n"
+                      " ))", 0, 1);
+  if (rc)
+    die ("error creating S-expression: %s\n", gpg_strerror (rc));
+
+  gcry_sexp_release (key);
+  rc = gcry_pk_genkey (&key, keyparm);
+  gcry_sexp_release (keyparm);
+  if (rc && !in_fips_mode)
+    fail ("error generating RSA key: %s\n", gpg_strerror (rc));
+  else if (!rc && in_fips_mode)
+    fail ("generating 1024 bit RSA key must not work!");
+
+  if (!rc)
+    {
+      if (verbose > 1)
+        show_sexp ("1024 bit RSA key:\n", key);
+      check_generated_rsa_key (key, 65537);
+    }
+  gcry_sexp_release (key);
+
+  if (verbose)
+    info ("creating 2048 bit RSA key with e=65539\n");
+  rc = gcry_sexp_new (&keyparm,
+                      "(genkey\n"
+                      " (rsa\n"
+                      "  (nbits 4:2048)\n"
+                      "  (rsa-use-e 5:65539)\n"
+                      " ))", 0, 1);
+  if (rc)
+    die ("error creating S-expression: %s\n", gpg_strerror (rc));
+  rc = gcry_pk_genkey (&key, keyparm);
+  gcry_sexp_release (keyparm);
+  if (rc)
+    fail ("error generating RSA key: %s\n", gpg_strerror (rc));
+
+  if (!rc)
+    check_generated_rsa_key (key, 65539);
+  gcry_sexp_release (key);
+
+
+  if (verbose)
+    info ("creating 512 bit RSA key with e=257\n");
+  rc = gcry_sexp_new (&keyparm,
+                      "(genkey\n"
+                      " (rsa\n"
+                      "  (nbits 3:512)\n"
+                      "  (rsa-use-e 3:257)\n"
+                      " ))", 0, 1);
+  if (rc)
+    die ("error creating S-expression: %s\n", gpg_strerror (rc));
+  rc = gcry_pk_genkey (&key, keyparm);
+  gcry_sexp_release (keyparm);
+  if (rc && !in_fips_mode)
+    fail ("error generating RSA key: %s\n", gpg_strerror (rc));
+  else if (!rc && in_fips_mode)
+    fail ("generating 512 bit RSA key must not work!");
+
+  if (verbose && rc && in_fips_mode)
+    info ("... correctly rejected key creation in FIPS mode (%s)\n",
+          gpg_strerror (rc));
+
+  if (!rc)
+    check_generated_rsa_key (key, 257);
+  gcry_sexp_release (key);
+
+  if (verbose)
+    info ("creating 512 bit RSA key with default e\n");
+  rc = gcry_sexp_new (&keyparm,
+                      "(genkey\n"
+                      " (rsa\n"
+                      "  (nbits 3:512)\n"
+                      "  (rsa-use-e 1:0)\n"
+                      " ))", 0, 1);
+  if (rc)
+    die ("error creating S-expression: %s\n", gpg_strerror (rc));
+  rc = gcry_pk_genkey (&key, keyparm);
+  gcry_sexp_release (keyparm);
+  if (rc && !in_fips_mode)
+    fail ("error generating RSA key: %s\n", gpg_strerror (rc));
+  else if (!rc && in_fips_mode)
+    fail ("generating 512 bit RSA key must not work!");
+
+  if (verbose && rc && in_fips_mode)
+    info ("... correctly rejected key creation in FIPS mode (%s)\n",
+          gpg_strerror (rc));
+
+
+  if (!rc)
+    check_generated_rsa_key (key, 0); /* We don't expect a constant exponent. */
+  gcry_sexp_release (key);
+}
+
+
+static void
+check_elg_keys (void)
+{
+  gcry_sexp_t keyparm, key;
+  int rc;
+
+  if (verbose)
+    info ("creating 1024 bit Elgamal key\n");
+  rc = gcry_sexp_new (&keyparm,
+                      "(genkey\n"
+                      " (elg\n"
+                      "  (nbits 4:1024)\n"
+                      " ))", 0, 1);
+  if (rc)
+    die ("error creating S-expression: %s\n", gpg_strerror (rc));
+  rc = gcry_pk_genkey (&key, keyparm);
+  gcry_sexp_release (keyparm);
+  if (rc)
+    die ("error generating Elgamal key: %s\n", gpg_strerror (rc));
+  if (verbose > 1)
+    show_sexp ("1024 bit Elgamal key:\n", key);
+  gcry_sexp_release (key);
+}
+
+
+static void
+check_dsa_keys (void)
+{
+  gcry_sexp_t keyparm, key;
+  int rc;
   int i;
 
   /* Check that DSA generation works and that it can grok the qbits
      argument. */
   if (verbose)
-    fprintf (stderr, "creating 5 1024 bit DSA keys\n");
+    info ("creating 5 1024 bit DSA keys\n");
   for (i=0; i < 5; i++)
     {
-      rc = gcry_sexp_new (&keyparm, 
+      rc = gcry_sexp_new (&keyparm,
                           "(genkey\n"
                           " (dsa\n"
                           "  (nbits 4:1024)\n"
@@ -140,16 +299,18 @@ check_rsa_keys (void)
         die ("error creating S-expression: %s\n", gpg_strerror (rc));
       rc = gcry_pk_genkey (&key, keyparm);
       gcry_sexp_release (keyparm);
-      if (rc)
+      if (rc && !in_fips_mode)
         die ("error generating DSA key: %s\n", gpg_strerror (rc));
+      else if (!rc && in_fips_mode)
+        die ("generating 1024 bit DSA key must not work!");
+      if (!i && verbose > 1)
+        show_sexp ("1024 bit DSA key:\n", key);
       gcry_sexp_release (key);
-      if (verbose)
-        fprintf (stderr, "  done\n");
     }
 
   if (verbose)
-    fprintf (stderr, "creating 1536 bit DSA key\n");
-  rc = gcry_sexp_new (&keyparm, 
+    info ("creating 1536 bit DSA key\n");
+  rc = gcry_sexp_new (&keyparm,
                       "(genkey\n"
                       " (dsa\n"
                       "  (nbits 4:1536)\n"
@@ -159,72 +320,289 @@ check_rsa_keys (void)
     die ("error creating S-expression: %s\n", gpg_strerror (rc));
   rc = gcry_pk_genkey (&key, keyparm);
   gcry_sexp_release (keyparm);
-  if (rc)
+  if (rc && !in_fips_mode)
     die ("error generating DSA key: %s\n", gpg_strerror (rc));
-  if (debug)
-    {
-      char buffer[20000];
-      gcry_sexp_sprint (key, GCRYSEXP_FMT_ADVANCED, buffer, sizeof buffer);
-      if (verbose)
-        printf ("=============================\n%s\n"
-                "=============================\n", buffer);
-    }
+  else if (!rc && in_fips_mode)
+    die ("generating 1536 bit DSA key must not work!");
+  if (verbose > 1)
+    show_sexp ("1536 bit DSA key:\n", key);
   gcry_sexp_release (key);
 
   if (verbose)
-    fprintf (stderr, "creating 1024 bit RSA key\n");
-  rc = gcry_sexp_new (&keyparm, 
+    info ("creating 3072 bit DSA key\n");
+  rc = gcry_sexp_new (&keyparm,
                       "(genkey\n"
-                      " (rsa\n"
-                      "  (nbits 4:1024)\n"
+                      " (dsa\n"
+                      "  (nbits 4:3072)\n"
+                      "  (qbits 3:256)\n"
                       " ))", 0, 1);
   if (rc)
     die ("error creating S-expression: %s\n", gpg_strerror (rc));
   rc = gcry_pk_genkey (&key, keyparm);
   gcry_sexp_release (keyparm);
   if (rc)
-    die ("error generating RSA key: %s\n", gpg_strerror (rc));
-
-  check_generated_rsa_key (key, 65537);
+    die ("error generating DSA key: %s\n", gpg_strerror (rc));
+  if (verbose > 1)
+    show_sexp ("3072 bit DSA key:\n", key);
   gcry_sexp_release (key);
 
-
   if (verbose)
-    fprintf (stderr, "creating 512 bit RSA key with e=257\n");
-  rc = gcry_sexp_new (&keyparm, 
+    info ("creating 2048/256 bit DSA key\n");
+  rc = gcry_sexp_new (&keyparm,
                       "(genkey\n"
-                      " (rsa\n"
-                      "  (nbits 3:512)\n"
-                      "  (rsa-use-e 3:257)\n"
+                      " (dsa\n"
+                      "  (nbits 4:2048)\n"
+                      "  (qbits 3:256)\n"
                       " ))", 0, 1);
   if (rc)
     die ("error creating S-expression: %s\n", gpg_strerror (rc));
   rc = gcry_pk_genkey (&key, keyparm);
   gcry_sexp_release (keyparm);
   if (rc)
-    die ("error generating RSA key: %s\n", gpg_strerror (rc));
-
-  check_generated_rsa_key (key, 257);
+    die ("error generating DSA key: %s\n", gpg_strerror (rc));
+  if (verbose > 1)
+    show_sexp ("2048 bit DSA key:\n", key);
   gcry_sexp_release (key);
 
   if (verbose)
-    fprintf (stderr, "creating 512 bit RSA key with default e\n");
-  rc = gcry_sexp_new (&keyparm, 
+    info ("creating 2048/224 bit DSA key\n");
+  rc = gcry_sexp_new (&keyparm,
                       "(genkey\n"
-                      " (rsa\n"
-                      "  (nbits 3:512)\n"
-                      "  (rsa-use-e 1:0)\n"
+                      " (dsa\n"
+                      "  (nbits 4:2048)\n"
+                      "  (qbits 3:224)\n"
                       " ))", 0, 1);
   if (rc)
     die ("error creating S-expression: %s\n", gpg_strerror (rc));
   rc = gcry_pk_genkey (&key, keyparm);
   gcry_sexp_release (keyparm);
   if (rc)
-    die ("error generating RSA key: %s\n", gpg_strerror (rc));
+    die ("error generating DSA key: %s\n", gpg_strerror (rc));
+  if (verbose > 1)
+    show_sexp ("2048 bit DSA key:\n", key);
+  gcry_sexp_release (key);
+}
+
+
+static void
+check_generated_ecc_key (gcry_sexp_t key)
+{
+  gcry_sexp_t skey, pkey;
+
+  pkey = gcry_sexp_find_token (key, "public-key", 0);
+  if (!pkey)
+    fail ("public part missing in return value\n");
+  else
+    {
+      /* Fixme: Check more stuff.  */
+      gcry_sexp_release (pkey);
+    }
 
-  check_generated_rsa_key (key, 0); /* We don't expect a constant exponent. */
+  skey = gcry_sexp_find_token (key, "private-key", 0);
+  if (!skey)
+    fail ("private part missing in return value\n");
+  else
+    {
+      int rc = gcry_pk_testkey (skey);
+      if (rc)
+        fail ("gcry_pk_testkey failed: %s\n", gpg_strerror (rc));
+      gcry_sexp_release (skey);
+    }
+
+  /* Finally check that gcry_pk_testkey also works on the entire
+     S-expression.  */
+  {
+    int rc = gcry_pk_testkey (key);
+    if (rc)
+      fail ("gcry_pk_testkey failed on key pair: %s\n", gpg_strerror (rc));
+  }
+}
+
+
+static void
+check_ecc_keys (void)
+{
+  const char *curves[] = { "NIST P-521", "NIST P-384", "NIST P-256",
+                           "Ed25519", NULL };
+  int testno;
+  gcry_sexp_t keyparm, key;
+  int rc;
+
+  for (testno=0; curves[testno]; testno++)
+    {
+      if (verbose)
+        info ("creating ECC key using curve %s\n", curves[testno]);
+      if (!strcmp (curves[testno], "Ed25519"))
+        {
+          /* Ed25519 isn't allowed in fips mode */
+          if (in_fips_mode)
+            continue;
+          rc = gcry_sexp_build (&keyparm, NULL,
+                                "(genkey(ecc(curve %s)(flags param eddsa)))",
+                                curves[testno]);
+        }
+      else
+        rc = gcry_sexp_build (&keyparm, NULL,
+                              "(genkey(ecc(curve %s)(flags param)))",
+                              curves[testno]);
+      if (rc)
+        die ("error creating S-expression: %s\n", gpg_strerror (rc));
+      rc = gcry_pk_genkey (&key, keyparm);
+      gcry_sexp_release (keyparm);
+      if (rc)
+        die ("error generating ECC key using curve %s: %s\n",
+             curves[testno], gpg_strerror (rc));
+
+      if (verbose > 1)
+        show_sexp ("ECC key:\n", key);
+
+      check_generated_ecc_key (key);
+
+      gcry_sexp_release (key);
+    }
+
+  if (verbose)
+    info ("creating ECC key using curve Ed25519 for ECDSA\n");
+  rc = gcry_sexp_build (&keyparm, NULL, "(genkey(ecc(curve Ed25519)))");
+  if (rc)
+    die ("error creating S-expression: %s\n", gpg_strerror (rc));
+  rc = gcry_pk_genkey (&key, keyparm);
+  gcry_sexp_release (keyparm);
+  if (rc && !in_fips_mode)
+    die ("error generating ECC key using curve Ed25519 for ECDSA: %s\n",
+         gpg_strerror (rc));
+  else if (!rc && in_fips_mode)
+    fail ("generating Ed25519 key must not work!");
+
+  if (verbose && rc && in_fips_mode)
+    info ("... correctly rejected key creation in FIPS mode (%s)\n",
+          gpg_strerror (rc));
+
+  if (!rc)
+    {
+      if (verbose > 1)
+        show_sexp ("ECC key:\n", key);
+
+      check_generated_ecc_key (key);
+    }
   gcry_sexp_release (key);
 
+  if (verbose)
+    info ("creating ECC key using curve Ed25519 for ECDSA (nocomp)\n");
+  rc = gcry_sexp_build (&keyparm, NULL,
+                        "(genkey(ecc(curve Ed25519)(flags nocomp)))");
+  if (rc)
+    die ("error creating S-expression: %s\n", gpg_strerror (rc));
+  rc = gcry_pk_genkey (&key, keyparm);
+  gcry_sexp_release (keyparm);
+  if (rc && !in_fips_mode)
+    die ("error generating ECC key using curve Ed25519 for ECDSA"
+         " (nocomp): %s\n",
+         gpg_strerror (rc));
+  else if (!rc && in_fips_mode)
+    fail ("generating Ed25519 key must not work in FIPS mode!");
+
+  if (verbose && rc && in_fips_mode)
+    info ("... correctly rejected key creation in FIPS mode (%s)\n",
+          gpg_strerror (rc));
+  gcry_sexp_release (key);
+
+  if (verbose)
+    info ("creating ECC key using curve NIST P-384 for ECDSA\n");
+
+  /* Must be specified as nistp384 (one word), because ecc_generate
+   * uses _gcry_sexp_nth_string which takes the first word of the name
+   * and thus libgcrypt can't find it later in its curves table.  */
+  rc = gcry_sexp_build (&keyparm, NULL, "(genkey(ecc(curve nistp384)))");
+  if (rc)
+    die ("error creating S-expression: %s\n", gpg_strerror (rc));
+  rc = gcry_pk_genkey (&key, keyparm);
+  gcry_sexp_release (keyparm);
+  if (rc)
+    die ("error generating ECC key using curve NIST P-384 for ECDSA: %s\n",
+         gpg_strerror (rc));
+
+  if (verbose > 1)
+    show_sexp ("ECC key:\n", key);
+
+  check_generated_ecc_key (key);
+  gcry_sexp_release (key);
+
+  if (verbose)
+    info ("creating ECC key using curve NIST P-384 for ECDSA (nocomp)\n");
+  rc = gcry_sexp_build (&keyparm, NULL,
+                        "(genkey(ecc(curve nistp384)(flags nocomp)))");
+  if (rc)
+    die ("error creating S-expression: %s\n", gpg_strerror (rc));
+  rc = gcry_pk_genkey (&key, keyparm);
+  gcry_sexp_release (keyparm);
+  if (rc)
+    die ("error generating ECC key using curve NIST P-384 for ECDSA"
+         " (nocomp): %s\n",
+         gpg_strerror (rc));
+
+  if (verbose > 1)
+    show_sexp ("ECC key:\n", key);
+
+  check_generated_ecc_key (key);
+  gcry_sexp_release (key);
+
+
+  if (verbose)
+    info ("creating ECC key using curve Ed25519 for ECDSA (transient-key)\n");
+  rc = gcry_sexp_build (&keyparm, NULL,
+                        "(genkey(ecc(curve Ed25519)(flags transient-key)))");
+  if (rc)
+    die ("error creating S-expression: %s\n", gpg_strerror (rc));
+  rc = gcry_pk_genkey (&key, keyparm);
+  gcry_sexp_release (keyparm);
+  if (rc && !in_fips_mode)
+    die ("error generating ECC key using curve Ed25519 for ECDSA"
+         " (transient-key): %s\n",
+         gpg_strerror (rc));
+  else if (!rc && in_fips_mode)
+    fail ("generating Ed25519 key must not work in FIPS mode!");
+
+  if (verbose && rc && in_fips_mode)
+    info ("... correctly rejected key creation in FIPS mode (%s)\n",
+          gpg_strerror (rc));
+
+  if (!rc)
+    {
+      if (verbose > 1)
+        show_sexp ("ECC key:\n", key);
+      check_generated_ecc_key (key);
+    }
+  gcry_sexp_release (key);
+
+  if (verbose)
+    info ("creating ECC key using curve Ed25519 for ECDSA "
+          "(transient-key no-keytest)\n");
+  rc = gcry_sexp_build (&keyparm, NULL,
+                        "(genkey(ecc(curve Ed25519)"
+                        "(flags transient-key no-keytest)))");
+  if (rc)
+    die ("error creating S-expression: %s\n", gpg_strerror (rc));
+  rc = gcry_pk_genkey (&key, keyparm);
+  gcry_sexp_release (keyparm);
+  if (rc && !in_fips_mode)
+    die ("error generating ECC key using curve Ed25519 for ECDSA"
+         " (transient-key no-keytest): %s\n",
+         gpg_strerror (rc));
+  else if (!rc && in_fips_mode)
+    fail ("generating Ed25519 key must not work in FIPS mode!");
+
+  if (verbose && rc && in_fips_mode)
+    info ("... correctly rejected key creation in FIPS mode (%s)\n",
+          gpg_strerror (rc));
+
+  if (!rc)
+    {
+      if (verbose > 1)
+        show_sexp ("ECC key:\n", key);
+      check_generated_ecc_key (key);
+    }
+  gcry_sexp_release (key);
 }
 
 
@@ -236,20 +614,20 @@ check_nonce (void)
   int oops=0;
 
   if (verbose)
-    fprintf (stderr, "checking gcry_create_nonce\n");
+    info ("checking gcry_create_nonce\n");
 
   gcry_create_nonce (a, sizeof a);
   for (i=0; i < 10; i++)
     {
       gcry_create_nonce (b, sizeof b);
       if (!memcmp (a, b, sizeof a))
-        die ("identical nounce found\n");
+        die ("identical nonce found\n");
     }
   for (i=0; i < 10; i++)
     {
       gcry_create_nonce (a, sizeof a);
       if (!memcmp (a, b, sizeof a))
-        die ("identical nounce found\n");
+        die ("identical nonce found\n");
     }
 
  again:
@@ -271,33 +649,139 @@ static void
 progress_cb (void *cb_data, const char *what, int printchar,
                  int current, int total)
 {
-  putchar (printchar);
+  (void)cb_data;
+  (void)what;
+  (void)current;
+  (void)total;
+
+  if (printchar == '\n')
+    fputs ( "<LF>", stdout);
+  else
+    putchar (printchar);
   fflush (stdout);
 }
 
 
+static void
+usage (int mode)
+{
+  fputs ("usage: " PGM " [options] [{rsa|elg|dsa|ecc|nonce}]\n"
+         "Options:\n"
+         "  --verbose       be verbose\n"
+         "  --debug         flyswatter\n"
+         "  --fips          run in FIPS mode\n"
+         "  --no-quick      To not use the quick RNG hack\n"
+         "  --progress      print progress indicators\n",
+         mode? stderr : stdout);
+  if (mode)
+    exit (1);
+}
+
 int
 main (int argc, char **argv)
 {
-  if (argc > 1 && !strcmp (argv[1], "--verbose"))
-    verbose = 1;
-  else if (argc > 1 && !strcmp (argv[1], "--debug"))
-    verbose = debug = 1;
+  int last_argc = -1;
+  int opt_fips = 0;
+  int with_progress = 0;
+  int no_quick = 0;
+
+  if (argc)
+    { argc--; argv++; }
+
+  while (argc && last_argc != argc )
+    {
+      last_argc = argc;
+      if (!strcmp (*argv, "--"))
+        {
+          argc--; argv++;
+          break;
+        }
+      else if (!strcmp (*argv, "--help"))
+        {
+          usage (0);
+          exit (0);
+        }
+      else if (!strcmp (*argv, "--verbose"))
+        {
+          verbose++;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--debug"))
+        {
+          verbose += 2;
+          debug++;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--fips"))
+        {
+          argc--; argv++;
+          opt_fips = 1;
+        }
+      else if (!strcmp (*argv, "--progress"))
+        {
+          argc--; argv++;
+          with_progress = 1;
+        }
+      else if (!strcmp (*argv, "--no-quick"))
+        {
+          argc--; argv++;
+          no_quick = 1;
+        }
+      else if (!strncmp (*argv, "--", 2))
+        die ("unknown option '%s'", *argv);
+      else
+        break;
+    }
+
+  xgcry_control (GCRYCTL_SET_VERBOSITY, (int)verbose);
+  if (opt_fips)
+    xgcry_control (GCRYCTL_FORCE_FIPS_MODE, 0);
 
   if (!gcry_check_version (GCRYPT_VERSION))
     die ("version mismatch\n");
-  gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
-  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+
+  if (!opt_fips)
+    xgcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+
+  xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
   if (debug)
-    gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
+    xgcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
   /* No valuable keys are create, so we can speed up our RNG. */
-  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
-  if (verbose)
-    gcry_set_progress_handler ( progress_cb, NULL );
+  if (!no_quick)
+    xgcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+  if (with_progress)
+    gcry_set_progress_handler (progress_cb, NULL);
+
+  if ( gcry_fips_mode_active () )
+    in_fips_mode = 1;
+
+  if (opt_fips && !in_fips_mode)
+    die ("failed to switch into FIPS mode\n");
+
+  if (!argc)
+    {
+      check_rsa_keys ();
+      check_elg_keys ();
+      check_dsa_keys ();
+      check_ecc_keys ();
+      check_nonce ();
+    }
+  else
+    {
+      for (; argc; argc--, argv++)
+        if (!strcmp (*argv, "rsa"))
+          check_rsa_keys ();
+        else if (!strcmp (*argv, "elg"))
+          check_elg_keys ();
+        else if (!strcmp (*argv, "dsa"))
+          check_dsa_keys ();
+        else if (!strcmp (*argv, "ecc"))
+          check_ecc_keys ();
+        else if (!strcmp (*argv, "nonce"))
+          check_nonce ();
+        else
+          usage (1);
+    }
 
-  check_rsa_keys ();
-  check_nonce ();
-  
   return error_count? 1:0;
 }
-