api: New function gcry_get_config.
[libgcrypt.git] / tests / fipsdrv.c
index 2501880..f9d9c45 100644 (file)
@@ -2,17 +2,17 @@
    Copyright (C) 2008 Free Software Foundation, Inc.
 
    This file is part of Libgcrypt.
-  
+
    Libgcrypt is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as
    published by the Free Software Foundation; either version 2.1 of
    the License, or (at your option) any later version.
-  
+
    Libgcrypt 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 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, see <http://www.gnu.org/licenses/>.
  */
 #include <stdarg.h>
 #include <errno.h>
 #include <ctype.h>
-#ifndef HAVE_W32_SYSTEM
+#ifdef HAVE_W32_SYSTEM
+# include <fcntl.h> /* We need setmode().  */
+#else
 # include <signal.h>
 #endif
 #include <assert.h>
 #include <unistd.h>
 
-#include <gcrypt.h>
+#ifndef _GCRYPT_IN_LIBGCRYPT
+# include <gcrypt.h>
+# define PACKAGE_BUGREPORT "devnull@example.org"
+# define PACKAGE_VERSION "[build on " __DATE__ " " __TIME__ "]"
+#endif
+#include "../src/gcrypt-testapi.h"
 
 #define PGM "fipsdrv"
-
-#define my_isascii(c) (!((c) & 0x80))
-#define digitp(p)   (*(p) >= '0' && *(p) <= '9')
-#define hexdigitp(a) (digitp (a)                     \
-                      || (*(a) >= 'A' && *(a) <= 'F')  \
-                      || (*(a) >= 'a' && *(a) <= 'f'))
-#define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
-                     *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
-#define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
-#define DIM(v)               (sizeof(v)/sizeof((v)[0]))
-#define DIMof(type,member)   DIM(((type *)0)->member)
+#include "t-common.h"
 
 
-/* Verbose mode flag.  */
-static int verbose;
-
 /* Binary input flag.  */
 static int binary_input;
 
@@ -60,9 +54,14 @@ static int binary_output;
 /* Base64 output flag.  */
 static int base64_output;
 
-/* We need to know whetehr we are in loop_mode.  */
+/* We need to know whether we are in loop_mode.  */
 static int loop_mode;
 
+/* If true some functions are modified to print the output in the CAVS
+   response file format.  */
+static int standalone_mode;
+
+
 /* ASN.1 classes.  */
 enum
 {
@@ -108,32 +107,17 @@ enum
 };
 
 /* ASN.1 Parser object.  */
-struct tag_info 
+struct tag_info
 {
   int class;             /* Object class.  */
   unsigned long tag;     /* The tag of the object.  */
   unsigned long length;  /* Length of the values.  */
   int nhdr;              /* Length of the header (TL).  */
   unsigned int ndef:1;   /* The object has an indefinite length.  */
-  unsigned int cons:1;   /* This is a constructed object.  */ 
+  unsigned int cons:1;   /* This is a constructed object.  */
 };
 
 
-
-/* Print a error message and exit the process with an error code.  */
-static void
-die (const char *format, ...)
-{
-  va_list arg_ptr;
-
-  va_start (arg_ptr, format);
-  fputs (PGM ": ", stderr);
-  vfprintf (stderr, format, arg_ptr);
-  va_end (arg_ptr);
-  exit (1);
-}
-
-
 static void
 showhex (const char *prefix, const void *buffer, size_t length)
 {
@@ -147,6 +131,22 @@ showhex (const char *prefix, const void *buffer, size_t length)
     putc ('\n', stderr);
 }
 
+/* static void */
+/* show_sexp (const char *prefix, gcry_sexp_t a) */
+/* { */
+/*   char *buf; */
+/*   size_t size; */
+
+/*   if (prefix) */
+/*     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); */
+/* } */
+
 
 /* Convert STRING consisting of hex characters into its binary
    representation and store that at BUFFER.  BUFFER needs to be of
@@ -201,6 +201,80 @@ hex2buffer (const char *string, size_t *r_length)
   return buffer;
 }
 
+
+static char *
+read_textline (FILE *fp)
+{
+  char line[256];
+  char *p;
+  int any = 0;
+
+  /* Read line but skip over initial empty lines.  */
+  do
+    {
+      do
+        {
+          if (!fgets (line, sizeof line, fp))
+            {
+              if (feof (fp))
+                return NULL;
+              die ("error reading input line: %s\n", strerror (errno));
+            }
+          p = strchr (line, '\n');
+          if (p)
+            *p = 0;
+          p = line + (*line? (strlen (line)-1):0);
+          for ( ;p > line; p--)
+            if (my_isascii (*p) && isspace (*p))
+              *p = 0;
+        }
+      while (!any && !*line);
+      any = 1;
+    }
+  while (*line == '#');  /* Always skip comment lines.  */
+  if (verbose > 1)
+    fprintf (stderr, PGM ": received line: %s\n", line);
+  return gcry_xstrdup (line);
+}
+
+static char *
+read_hexline (FILE *fp, size_t *retlen)
+{
+  char *line, *p;
+
+  line = read_textline (fp);
+  if (!line)
+    return NULL;
+  p = hex2buffer (line, retlen);
+  if (!p)
+    die ("error decoding hex string on input\n");
+  gcry_free (line);
+  return p;
+}
+
+static void
+skip_to_empty_line (FILE *fp)
+{
+  char line[256];
+  char *p;
+
+  do
+    {
+      if (!fgets (line, sizeof line, fp))
+        {
+          if (feof (fp))
+            return;
+          die ("error reading input line: %s\n", strerror (errno));
+        }
+      p = strchr (line, '\n');
+      if (p)
+        *p =0;
+    }
+  while (*line);
+}
+
+
+
 /* Read a file from stream FP into a newly allocated buffer and return
    that buffer.  The valid length of the buffer is stored at R_LENGTH.
    Returns NULL on failure.  If decode is set, the file is assumed to
@@ -219,14 +293,14 @@ read_file (FILE *fp, int decode, size_t *r_length)
 #endif
   buffer = NULL;
   buflen = 0;
-  do 
+  do
     {
       bufsize += NCHUNK;
       if (!buffer)
         buffer = gcry_xmalloc (bufsize);
       else
         buffer = gcry_xrealloc (buffer, bufsize);
-      
+
       nread = fread (buffer + buflen, 1, NCHUNK, fp);
       if (nread < NCHUNK && ferror (fp))
         {
@@ -268,7 +342,7 @@ read_file (FILE *fp, int decode, size_t *r_length)
 static size_t
 base64_decode (char *buffer, size_t length)
 {
-  static unsigned char const asctobin[128] = 
+  static unsigned char const asctobin[128] =
     {
       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
@@ -280,7 +354,7 @@ base64_decode (char *buffer, size_t length)
       0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
       0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
       0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
-      0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff 
+      0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
     };
 
   int idx = 0;
@@ -297,7 +371,7 @@ base64_decode (char *buffer, size_t length)
           for (; length && *s != '\n'; length--, s++)
             ;
           break;
-        } 
+        }
       lfseen = (*s == '\n');
     }
 
@@ -352,7 +426,7 @@ base64_decode (char *buffer, size_t length)
    from the TLV triplet.  Update BUFFER and BUFLEN on success.  Checks
    that the encoded length does not exhaust the length of the provided
    buffer. */
-static int 
+static int
 parse_tag (unsigned char const **buffer, size_t *buflen, struct tag_info *ti)
 {
   int c;
@@ -418,13 +492,13 @@ parse_tag (unsigned char const **buffer, size_t *buflen, struct tag_info *ti)
         }
       ti->length = len;
     }
-  
+
   if (ti->class == UNIVERSAL && !ti->tag)
     ti->length = 0;
 
   if (ti->length > length)
     return -1; /* Data larger than buffer.  */
-  
+
   *buffer = buf;
   *buflen = length;
   return 0;
@@ -435,7 +509,7 @@ parse_tag (unsigned char const **buffer, size_t *buflen, struct tag_info *ti)
    and return an S-expression.  With SHOW set, the key parameters are
    printed.  */
 static gcry_sexp_t
-read_key_file (const char *fname, int show)
+read_private_key_file (const char *fname, int show)
 {
   gcry_error_t err;
   FILE *fp;
@@ -445,6 +519,7 @@ read_key_file (const char *fname, int show)
   size_t derlen;
   struct tag_info ti;
   gcry_mpi_t keyparms[8];
+  int n_keyparms = 8;
   int idx;
   gcry_sexp_t s_key;
 
@@ -457,7 +532,7 @@ read_key_file (const char *fname, int show)
   fclose (fp);
 
   buflen = base64_decode (buffer, buflen);
-  
+
   /* Parse the ASN.1 structure.  */
   der = (const unsigned char*)buffer;
   derlen = buflen;
@@ -469,9 +544,9 @@ read_key_file (const char *fname, int show)
     goto bad_asn1;
   if (ti.length != 1 || *der)
     goto bad_asn1;  /* The value of the first integer is no 0. */
-  der += ti.length; derlen += ti.length;
+  der += ti.length; derlen -= ti.length;
 
-  for (idx=0; idx < DIM(keyparms); idx++)
+  for (idx=0; idx < n_keyparms; idx++)
     {
       if ( parse_tag (&der, &derlen, &ti)
            || ti.tag != TAG_INTEGER || ti.class || ti.cons || ti.ndef)
@@ -487,15 +562,15 @@ read_key_file (const char *fname, int show)
       err = gcry_mpi_scan (keyparms+idx, GCRYMPI_FMT_USG, der, ti.length,NULL);
       if (err)
         die ("error scanning RSA parameter %d: %s\n", idx, gpg_strerror (err));
-      der += ti.length; derlen += ti.length;
+      der += ti.length; derlen -= ti.length;
     }
-  if (idx != DIM(keyparms))
+  if (idx != n_keyparms)
     die ("not enough RSA key parameters\n");
 
   gcry_free (buffer);
 
   /* Convert from OpenSSL parameter ordering to the OpenPGP order. */
-  /* First check that p < q; if not swap p and q and recompute u.  */ 
+  /* First check that p < q; if not swap p and q and recompute u.  */
   if (gcry_mpi_cmp (keyparms[3], keyparms[4]) > 0)
     {
       gcry_mpi_swap (keyparms[3], keyparms[4]);
@@ -504,13 +579,107 @@ read_key_file (const char *fname, int show)
 
   /* Build the S-expression.  */
   err = gcry_sexp_build (&s_key, NULL,
-                        "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
+                         "(private-key(rsa(n%m)(e%m)"
+                         /**/            "(d%m)(p%m)(q%m)(u%m)))",
                          keyparms[0], keyparms[1], keyparms[2],
                          keyparms[3], keyparms[4], keyparms[7] );
   if (err)
     die ("error building S-expression: %s\n", gpg_strerror (err));
 
-  for (idx=0; idx < DIM(keyparms); idx++)
+  for (idx=0; idx < n_keyparms; idx++)
+    gcry_mpi_release (keyparms[idx]);
+
+  return s_key;
+
+ bad_asn1:
+  die ("invalid ASN.1 structure in `%s'\n", fname);
+  return NULL; /*NOTREACHED*/
+}
+
+
+/* Read the file FNAME assuming it is a PEM encoded public key file
+   and return an S-expression.  With SHOW set, the key parameters are
+   printed.  */
+static gcry_sexp_t
+read_public_key_file (const char *fname, int show)
+{
+  gcry_error_t err;
+  FILE *fp;
+  char *buffer;
+  size_t buflen;
+  const unsigned char *der;
+  size_t derlen;
+  struct tag_info ti;
+  gcry_mpi_t keyparms[2];
+  int n_keyparms = 2;
+  int idx;
+  gcry_sexp_t s_key;
+
+  fp = fopen (fname, binary_input?"rb":"r");
+  if (!fp)
+    die ("can't open `%s': %s\n", fname, strerror (errno));
+  buffer = read_file (fp, 0, &buflen);
+  if (!buffer)
+    die ("error reading `%s'\n", fname);
+  fclose (fp);
+
+  buflen = base64_decode (buffer, buflen);
+
+  /* Parse the ASN.1 structure.  */
+  der = (const unsigned char*)buffer;
+  derlen = buflen;
+  if ( parse_tag (&der, &derlen, &ti)
+       || ti.tag != TAG_SEQUENCE || ti.class || !ti.cons || ti.ndef)
+    goto bad_asn1;
+  if ( parse_tag (&der, &derlen, &ti)
+       || ti.tag != TAG_SEQUENCE || ti.class || !ti.cons || ti.ndef)
+    goto bad_asn1;
+  /* We skip the description of the key parameters and assume it is RSA.  */
+  der += ti.length; derlen -= ti.length;
+
+  if ( parse_tag (&der, &derlen, &ti)
+       || ti.tag != TAG_BIT_STRING || ti.class || ti.cons || ti.ndef)
+    goto bad_asn1;
+  if (ti.length < 1 || *der)
+    goto bad_asn1;  /* The number of unused bits needs to be 0. */
+  der += 1; derlen -= 1;
+
+  /* Parse the BIT string.  */
+  if ( parse_tag (&der, &derlen, &ti)
+       || ti.tag != TAG_SEQUENCE || ti.class || !ti.cons || ti.ndef)
+    goto bad_asn1;
+
+  for (idx=0; idx < n_keyparms; idx++)
+    {
+      if ( parse_tag (&der, &derlen, &ti)
+           || ti.tag != TAG_INTEGER || ti.class || ti.cons || ti.ndef)
+        goto bad_asn1;
+      if (show)
+        {
+          char prefix[2];
+
+          prefix[0] = idx < 2? "ne"[idx] : '?';
+          prefix[1] = 0;
+          showhex (prefix, der, ti.length);
+        }
+      err = gcry_mpi_scan (keyparms+idx, GCRYMPI_FMT_USG, der, ti.length,NULL);
+      if (err)
+        die ("error scanning RSA parameter %d: %s\n", idx, gpg_strerror (err));
+      der += ti.length; derlen -= ti.length;
+    }
+  if (idx != n_keyparms)
+    die ("not enough RSA key parameters\n");
+
+  gcry_free (buffer);
+
+  /* Build the S-expression.  */
+  err = gcry_sexp_build (&s_key, NULL,
+                         "(public-key(rsa(n%m)(e%m)))",
+                         keyparms[0], keyparms[1] );
+  if (err)
+    die ("error building S-expression: %s\n", gpg_strerror (err));
+
+  for (idx=0; idx < n_keyparms; idx++)
     gcry_mpi_release (keyparms[idx]);
 
   return s_key;
@@ -521,6 +690,68 @@ read_key_file (const char *fname, int show)
 }
 
 
+
+/* Read the file FNAME assuming it is a binary signature result and
+   return an an S-expression suitable for gcry_pk_verify.  */
+static gcry_sexp_t
+read_sig_file (const char *fname)
+{
+  gcry_error_t err;
+  FILE *fp;
+  char *buffer;
+  size_t buflen;
+  gcry_mpi_t tmpmpi;
+  gcry_sexp_t s_sig;
+
+  fp = fopen (fname, "rb");
+  if (!fp)
+    die ("can't open `%s': %s\n", fname, strerror (errno));
+  buffer = read_file (fp, 0, &buflen);
+  if (!buffer)
+    die ("error reading `%s'\n", fname);
+  fclose (fp);
+
+  err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, buffer, buflen, NULL);
+  if (!err)
+    err = gcry_sexp_build (&s_sig, NULL,
+                           "(sig-val(rsa(s %m)))", tmpmpi);
+  if (err)
+    die ("error building S-expression: %s\n", gpg_strerror (err));
+  gcry_mpi_release (tmpmpi);
+  gcry_free (buffer);
+
+  return s_sig;
+}
+
+
+/* Read an S-expression from FNAME.  */
+static gcry_sexp_t
+read_sexp_from_file (const char *fname)
+{
+  gcry_error_t err;
+  FILE *fp;
+  char *buffer;
+  size_t buflen;
+  gcry_sexp_t sexp;
+
+  fp = fopen (fname, "rb");
+  if (!fp)
+    die ("can't open `%s': %s\n", fname, strerror (errno));
+  buffer = read_file (fp, 0, &buflen);
+  if (!buffer)
+    die ("error reading `%s'\n", fname);
+  fclose (fp);
+  if (!buflen)
+    die ("error: file `%s' is empty\n", fname);
+
+  err = gcry_sexp_create (&sexp, buffer, buflen, 1, gcry_free);
+  if (err)
+    die ("error parsing `%s': %s\n", fname, gpg_strerror (err));
+
+  return sexp;
+}
+
+
 static void
 print_buffer (const void *buffer, size_t length)
 {
@@ -528,10 +759,10 @@ print_buffer (const void *buffer, size_t length)
 
   if (base64_output)
     {
-      static const unsigned char bintoasc[64+1] = 
-        ("ABCDEFGHIJKLMNOPQRSTUVWXYZ" 
-         "abcdefghijklmnopqrstuvwxyz" 
-         "0123456789+/"); 
+      static const unsigned char bintoasc[64+1] =
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+        "abcdefghijklmnopqrstuvwxyz"
+        "0123456789+/";
       const unsigned char *p;
       unsigned char inbuf[4];
       char outbuf[4];
@@ -552,7 +783,7 @@ print_buffer (const void *buffer, size_t length)
               if (fwrite (outbuf, 4, 1, stdout) != 1)
                 writerr = 1;
               idx = 0;
-              if (++quads >= (64/4)) 
+              if (++quads >= (64/4))
                 {
                   if (fwrite ("\n", 1, 1, stdout) != 1)
                     writerr = 1;
@@ -568,8 +799,8 @@ print_buffer (const void *buffer, size_t length)
               outbuf[1] = bintoasc[((*inbuf<<4)&060)&077];
               outbuf[2] = outbuf[3] = '=';
             }
-          else 
-            { 
+          else
+            {
               outbuf[1] = bintoasc[(((*inbuf<<4)&060)
                                     |((inbuf[1]>>4)&017))&077];
               outbuf[2] = bintoasc[((inbuf[1]<<2)&074)&077];
@@ -590,7 +821,9 @@ print_buffer (const void *buffer, size_t length)
   else
     {
       const unsigned char *p = buffer;
-      
+
+      if (verbose > 1)
+        showhex ("sent line", buffer, length);
       while (length-- && !ferror (stdout) )
         printf ("%02X", *p++);
       if (ferror (stdout))
@@ -610,15 +843,77 @@ print_buffer (const void *buffer, size_t length)
 }
 
 
+/* Print an MPI on a line.  */
+static void
+print_mpi_line (gcry_mpi_t a, int no_lz)
+{
+  unsigned char *buf, *p;
+  gcry_error_t err;
+  int writerr = 0;
+
+  err = gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buf, NULL, a);
+  if (err)
+    die ("gcry_mpi_aprint failed: %s\n", gpg_strerror (err));
+
+  p = buf;
+  if (no_lz && p[0] == '0' && p[1] == '0' && p[2])
+    p += 2;
+
+  printf ("%s\n", p);
+  if (ferror (stdout))
+    writerr++;
+  if (!writerr && fflush (stdout) == EOF)
+    writerr++;
+  if (writerr)
+    die ("writing output failed: %s\n", strerror (errno));
+  gcry_free (buf);
+}
+
+
+/* Print some data on hex format on a line.  */
+static void
+print_data_line (const void *data, size_t datalen)
+{
+  const unsigned char *p = data;
+  int writerr = 0;
+
+  while (data && datalen-- && !ferror (stdout) )
+    printf ("%02X", *p++);
+  putchar ('\n');
+  if (ferror (stdout))
+    writerr++;
+  if (!writerr && fflush (stdout) == EOF)
+    writerr++;
+  if (writerr)
+    die ("writing output failed: %s\n", strerror (errno));
+}
+
+/* Print the S-expression A to the stream FP.  */
+static void
+print_sexp (gcry_sexp_t a, FILE *fp)
+{
+  char *buf;
+  size_t size;
+
+  size = gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, NULL, 0);
+  buf = gcry_xmalloc (size);
+  gcry_sexp_sprint (a, GCRYSEXP_FMT_ADVANCED, buf, size);
+  if (fwrite (buf, size, 1, fp) != 1)
+    die ("error writing to stream: %s\n", strerror (errno));
+  gcry_free (buf);
+}
+
+
+
 
 static gcry_error_t
-init_external_rng_test (void **r_context, 
+init_external_rng_test (void **r_context,
                     unsigned int flags,
                     const void *key, size_t keylen,
                     const void *seed, size_t seedlen,
                     const void *dt, size_t dtlen)
 {
-  return gcry_control (58, 
+  return gcry_control (PRIV_CTL_INIT_EXTRNG_TEST,
                        r_context, flags,
                        key, keylen,
                        seed, seedlen,
@@ -628,27 +923,27 @@ init_external_rng_test (void **r_context,
 static gcry_error_t
 run_external_rng_test (void *context, void *buffer, size_t buflen)
 {
-  return gcry_control (59, context, buffer, buflen);
+  return gcry_control (PRIV_CTL_RUN_EXTRNG_TEST, context, buffer, buflen);
 }
 
 static void
 deinit_external_rng_test (void *context)
 {
-  gcry_control (60, context);
+  xgcry_control (PRIV_CTL_DEINIT_EXTRNG_TEST, context);
 }
 
 
 /* Given an OpenSSL cipher name NAME, return the Libgcrypt algirithm
    identified and store the libgcrypt mode at R_MODE.  Returns 0 on
    error.  */
-static int 
+static int
 map_openssl_cipher_name (const char *name, int *r_mode)
 {
   static struct {
     const char *name;
     int algo;
     int mode;
-  } table[] = 
+  } table[] =
     {
       { "bf-cbc",       GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC },
       { "bf",           GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC },
@@ -670,8 +965,8 @@ map_openssl_cipher_name (const char *name, int *r_mode)
       { "des-ecb",      GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB },
 
       { "des-ede3-cbc", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC },
-      { "des-ede3    ", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_ECB },
-      { "des3        ", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC },
+      { "des-ede3",     GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_ECB },
+      { "des3",         GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC },
       { "des-ede3-cfb", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CFB },
       { "des-ede3-ofb", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_OFB },
 
@@ -688,7 +983,7 @@ map_openssl_cipher_name (const char *name, int *r_mode)
       { "aes-192-cfb",  GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CFB },
       { "aes-192-ecb",  GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_ECB },
       { "aes-192-ofb",  GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_OFB },
-      
+
       { "aes-256-cbc",  GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC },
       { "aes-256",      GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC },
       { "aes-256-cfb",  GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CFB },
@@ -716,7 +1011,7 @@ map_openssl_cipher_name (const char *name, int *r_mode)
    processes it and writes it out until EOF.  */
 static void
 run_encrypt_decrypt (int encrypt_mode,
-                     int cipher_algo, int cipher_mode, 
+                     int cipher_algo, int cipher_mode,
                      const void *iv_buffer, size_t iv_buflen,
                      const void *key_buffer, size_t key_buflen,
                      const void *data, size_t datalen, FILE *fp)
@@ -727,25 +1022,34 @@ run_encrypt_decrypt (int encrypt_mode,
   size_t outbuflen;
   void *inbuf;
   size_t inbuflen;
+  size_t blocklen;
 
   err = gcry_cipher_open (&hd, cipher_algo, cipher_mode, 0);
   if (err)
-    die ("gcry_cipher_open failed for algo %d, mode %d: %s\n", 
+    die ("gcry_cipher_open failed for algo %d, mode %d: %s\n",
          cipher_algo, cipher_mode, gpg_strerror (err));
 
+  blocklen = gcry_cipher_get_algo_blklen (cipher_algo);
+  assert (blocklen);
+
+  gcry_cipher_ctl (hd, PRIV_CIPHERCTL_DISABLE_WEAK_KEY, NULL, 0);
+
   err = gcry_cipher_setkey (hd, key_buffer, key_buflen);
   if (err)
     die ("gcry_cipher_setkey failed with keylen %u: %s\n",
          (unsigned int)key_buflen, gpg_strerror (err));
 
-  err = gcry_cipher_setiv (hd, iv_buffer, iv_buflen);
-  if (err)
-    die ("gcry_cipher_setiv failed with ivlen %u: %s\n",
-         (unsigned int)iv_buflen, gpg_strerror (err));
+  if (iv_buffer)
+    {
+      err = gcry_cipher_setiv (hd, iv_buffer, iv_buflen);
+      if (err)
+        die ("gcry_cipher_setiv failed with ivlen %u: %s\n",
+             (unsigned int)iv_buflen, gpg_strerror (err));
+    }
 
   inbuf = data? NULL : gcry_xmalloc (datalen);
   outbuflen = datalen;
-  outbuf = gcry_xmalloc (outbuflen);
+  outbuf = gcry_xmalloc (outbuflen < blocklen? blocklen:outbuflen);
 
   do
     {
@@ -767,6 +1071,7 @@ run_encrypt_decrypt (int encrypt_mode,
       if (err)
         die ("gcry_cipher_%scrypt failed: %s\n",
              encrypt_mode? "en":"de", gpg_strerror (err));
+
       print_buffer (outbuf, outbuflen);
     }
   while (inbuf);
@@ -777,60 +1082,300 @@ run_encrypt_decrypt (int encrypt_mode,
 }
 
 
-\f
-/* Run a digest operation.  */
 static void
-run_digest (int digest_algo,  const void *data, size_t datalen)
+get_current_iv (gcry_cipher_hd_t hd, void *buffer, size_t buflen)
 {
-  gpg_error_t err;
-  gcry_md_hd_t hd;
-  const unsigned char *digest;
-  unsigned int digestlen;
-
-  err = gcry_md_open (&hd, digest_algo, 0);
-  if (err)
-    die ("gcry_md_open failed for algo %d: %s\n", 
-         digest_algo,  gpg_strerror (err));
+  unsigned char tmp[17];
 
-  gcry_md_write (hd, data, datalen);
-  digest = gcry_md_read (hd, digest_algo);
-  digestlen = gcry_md_get_algo_dlen (digest_algo);
-  print_buffer (digest, digestlen);
-  gcry_md_close (hd);
+  if (gcry_cipher_ctl (hd, PRIV_CIPHERCTL_GET_INPUT_VECTOR, tmp, sizeof tmp))
+    die ("error getting current input vector\n");
+  if (buflen > *tmp)
+    die ("buffer too short to store the current input vector\n");
+  memcpy (buffer, tmp+1, *tmp);
 }
 
-\f
-/* Run a HMAC operation.  */
+/* Run the inner loop of the CAVS monte carlo test.  */
 static void
-run_hmac (int digest_algo, const void *key, size_t keylen, 
-          const void *data, size_t datalen)
+run_cipher_mct_loop (int encrypt_mode, int cipher_algo, int cipher_mode,
+                     const void *iv_buffer, size_t iv_buflen,
+                     const void *key_buffer, size_t key_buflen,
+                     const void *data, size_t datalen, int iterations)
 {
   gpg_error_t err;
-  gcry_md_hd_t hd;
-  const unsigned char *digest;
-  unsigned int digestlen;
+  gcry_cipher_hd_t hd;
+  size_t blocklen;
+  int count;
+  char input[16];
+  char output[16];
+  char last_output[16];
+  char last_last_output[16];
+  char last_iv[16];
 
-  err = gcry_md_open (&hd, digest_algo, GCRY_MD_FLAG_HMAC);
-  if (err)
-    die ("gcry_md_open failed for HMAC algo %d: %s\n", 
-         digest_algo,  gpg_strerror (err));
 
-  gcry_md_setkey (hd, key, keylen);
+  err = gcry_cipher_open (&hd, cipher_algo, cipher_mode, 0);
   if (err)
-    die ("gcry_md_setkey failed for HMAC algo %d: %s\n", 
-         digest_algo,  gpg_strerror (err));
+    die ("gcry_cipher_open failed for algo %d, mode %d: %s\n",
+         cipher_algo, cipher_mode, gpg_strerror (err));
 
-  gcry_md_write (hd, data, datalen);
-  digest = gcry_md_read (hd, digest_algo);
-  digestlen = gcry_md_get_algo_dlen (digest_algo);
-  print_buffer (digest, digestlen);
-  gcry_md_close (hd);
-}
+  blocklen = gcry_cipher_get_algo_blklen (cipher_algo);
+  if (!blocklen || blocklen > sizeof output)
+    die ("invalid block length %d\n", (int)blocklen);
 
-\f
-static size_t
+
+  gcry_cipher_ctl (hd, PRIV_CIPHERCTL_DISABLE_WEAK_KEY, NULL, 0);
+
+  err = gcry_cipher_setkey (hd, key_buffer, key_buflen);
+  if (err)
+    die ("gcry_cipher_setkey failed with keylen %u: %s\n",
+         (unsigned int)key_buflen, gpg_strerror (err));
+
+  if (iv_buffer)
+    {
+      err = gcry_cipher_setiv (hd, iv_buffer, iv_buflen);
+      if (err)
+        die ("gcry_cipher_setiv failed with ivlen %u: %s\n",
+             (unsigned int)iv_buflen, gpg_strerror (err));
+    }
+
+  if (datalen != blocklen)
+    die ("length of input (%u) does not match block length (%u)\n",
+         (unsigned int)datalen, (unsigned int)blocklen);
+  memcpy (input, data, datalen);
+  memset (output, 0, sizeof output);
+  for (count=0; count < iterations; count++)
+    {
+      memcpy (last_last_output, last_output, sizeof last_output);
+      memcpy (last_output, output, sizeof output);
+
+      get_current_iv (hd, last_iv, blocklen);
+
+      if (encrypt_mode)
+        err = gcry_cipher_encrypt (hd, output, blocklen, input, blocklen);
+      else
+        err = gcry_cipher_decrypt (hd, output, blocklen, input, blocklen);
+      if (err)
+        die ("gcry_cipher_%scrypt failed: %s\n",
+             encrypt_mode? "en":"de", gpg_strerror (err));
+
+
+      if (encrypt_mode && (cipher_mode == GCRY_CIPHER_MODE_CFB
+                           || cipher_mode == GCRY_CIPHER_MODE_CBC))
+        memcpy (input, last_iv, blocklen);
+      else if (cipher_mode == GCRY_CIPHER_MODE_OFB)
+        memcpy (input, last_iv, blocklen);
+      else if (!encrypt_mode && cipher_mode == GCRY_CIPHER_MODE_CFB)
+        {
+          /* Reconstruct the output vector.  */
+          int i;
+          for (i=0; i < blocklen; i++)
+            input[i] ^= output[i];
+        }
+      else
+        memcpy (input, output, blocklen);
+    }
+
+  print_buffer (output, blocklen);
+  putchar ('\n');
+  print_buffer (last_output, blocklen);
+  putchar ('\n');
+  print_buffer (last_last_output, blocklen);
+  putchar ('\n');
+  get_current_iv (hd, last_iv, blocklen);
+  print_buffer (last_iv, blocklen); /* Last output vector.  */
+  putchar ('\n');
+  print_buffer (input, blocklen);   /* Next input text. */
+  putchar ('\n');
+  if (verbose > 1)
+    showhex ("sent line", "", 0);
+  putchar ('\n');
+  fflush (stdout);
+
+  gcry_cipher_close (hd);
+}
+
+
+\f
+/* Run a digest operation.  */
+static void
+run_digest (int digest_algo,  const void *data, size_t datalen)
+{
+  gpg_error_t err;
+  gcry_md_hd_t hd;
+  const unsigned char *digest;
+  unsigned int digestlen;
+
+  err = gcry_md_open (&hd, digest_algo, 0);
+  if (err)
+    die ("gcry_md_open failed for algo %d: %s\n",
+         digest_algo,  gpg_strerror (err));
+
+  gcry_md_write (hd, data, datalen);
+  digest = gcry_md_read (hd, digest_algo);
+  digestlen = gcry_md_get_algo_dlen (digest_algo);
+  print_buffer (digest, digestlen);
+  gcry_md_close (hd);
+}
+
+\f
+/* Run a HMAC operation.  */
+static void
+run_hmac (int digest_algo, const void *key, size_t keylen,
+          const void *data, size_t datalen)
+{
+  gpg_error_t err;
+  gcry_md_hd_t hd;
+  const unsigned char *digest;
+  unsigned int digestlen;
+
+  err = gcry_md_open (&hd, digest_algo, GCRY_MD_FLAG_HMAC);
+  if (err)
+    die ("gcry_md_open failed for HMAC algo %d: %s\n",
+         digest_algo,  gpg_strerror (err));
+
+  gcry_md_setkey (hd, key, keylen);
+  if (err)
+    die ("gcry_md_setkey failed for HMAC algo %d: %s\n",
+         digest_algo,  gpg_strerror (err));
+
+  gcry_md_write (hd, data, datalen);
+  digest = gcry_md_read (hd, digest_algo);
+  digestlen = gcry_md_get_algo_dlen (digest_algo);
+  print_buffer (digest, digestlen);
+  gcry_md_close (hd);
+}
+
+
+\f
+/* Derive an RSA key using the S-expression in (DATA,DATALEN).  This
+   S-expression is used directly as input to gcry_pk_genkey.  The
+   result is printed to stdout with one parameter per line in hex
+   format and in this order: p, q, n, d.  */
+static void
+run_rsa_derive (const void *data, size_t datalen)
+{
+  gpg_error_t err;
+  gcry_sexp_t s_keyspec, s_key, s_top, l1;
+  gcry_mpi_t mpi;
+  const char *parmlist;
+  int idx;
+
+  if (!datalen)
+    err = gpg_error (GPG_ERR_NO_DATA);
+  else
+    err = gcry_sexp_new (&s_keyspec, data, datalen, 1);
+  if (err)
+    die ("gcry_sexp_new failed for RSA key derive: %s\n",
+         gpg_strerror (err));
+
+  err = gcry_pk_genkey (&s_key, s_keyspec);
+  if (err)
+    die ("gcry_pk_genkey failed for RSA: %s\n", gpg_strerror (err));
+
+  gcry_sexp_release (s_keyspec);
+
+  /* P and Q might have been swapped but we need to to return them in
+     the proper order.  Build the parameter list accordingly.  */
+  parmlist = "pqnd";
+  s_top = gcry_sexp_find_token (s_key, "misc-key-info", 0);
+  if (s_top)
+    {
+      l1 = gcry_sexp_find_token (s_top, "p-q-swapped", 0);
+      if (l1)
+        parmlist = "qpnd";
+      gcry_sexp_release (l1);
+      gcry_sexp_release (s_top);
+    }
+
+  /* Parse and print the parameters.  */
+  l1 = gcry_sexp_find_token (s_key, "private-key", 0);
+  s_top = gcry_sexp_find_token (l1, "rsa", 0);
+  gcry_sexp_release (l1);
+  if (!s_top)
+    die ("private-key part not found in result\n");
+
+  for (idx=0; parmlist[idx]; idx++)
+    {
+      l1 = gcry_sexp_find_token (s_top, parmlist+idx, 1);
+      mpi = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+      gcry_sexp_release (l1);
+      if (!mpi)
+        die ("parameter %c missing in private-key\n", parmlist[idx]);
+      print_mpi_line (mpi, 1);
+      gcry_mpi_release (mpi);
+    }
+
+  gcry_sexp_release (s_top);
+  gcry_sexp_release (s_key);
+}
+
+
+/* Generate RSA key using the S-expression in (DATA,DATALEN).  This
+   S-expression is used directly as input to gcry_pk_genkey.  The
+   result is printed to stdout with one parameter per line in hex
+   format and in this order: e, p, q, n, d.  */
+static void
+run_rsa_keygen (const void *data, size_t datalen, int test)
+{
+  gpg_error_t err;
+  gcry_sexp_t s_keyspec, s_key, s_top, l1;
+  gcry_mpi_t mpi;
+  const char *parmlist;
+  int idx;
+
+  if (!datalen)
+    err = gpg_error (GPG_ERR_NO_DATA);
+  else
+    err = gcry_sexp_new (&s_keyspec, data, datalen, 1);
+  if (err)
+    die ("gcry_sexp_new failed for RSA key generation: %s\n",
+         gpg_strerror (err));
+
+  err = gcry_pk_genkey (&s_key, s_keyspec);
+
+  gcry_sexp_release (s_keyspec);
+
+  if (test) {
+       if (err)
+               printf("F\n");
+       else {
+               gcry_sexp_release (s_key);
+               printf("P\n");
+       }
+       return;
+  }
+
+  if (err)
+    die ("gcry_pk_genkey failed for RSA: %s\n", gpg_strerror (err));
+
+  parmlist = "epqnd";
+
+  /* Parse and print the parameters.  */
+  l1 = gcry_sexp_find_token (s_key, "private-key", 0);
+  s_top = gcry_sexp_find_token (l1, "rsa", 0);
+  gcry_sexp_release (l1);
+  if (!s_top)
+    die ("private-key part not found in result\n");
+
+  for (idx=0; parmlist[idx]; idx++)
+    {
+      l1 = gcry_sexp_find_token (s_top, parmlist+idx, 1);
+      mpi = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+      gcry_sexp_release (l1);
+      if (!mpi)
+        die ("parameter %c missing in private-key\n", parmlist[idx]);
+      print_mpi_line (mpi, 1);
+      gcry_mpi_release (mpi);
+    }
+
+  gcry_sexp_release (s_top);
+  gcry_sexp_release (s_key);
+}
+
+
+\f
+static size_t
 compute_tag_length (size_t n)
-{     
+{
   int needed = 0;
 
   if (n < 128)
@@ -847,7 +1392,7 @@ compute_tag_length (size_t n)
 
 static unsigned char *
 store_tag_length (unsigned char *p, int tag, size_t n)
-{     
+{
   if (tag == TAG_SEQUENCE)
     tag |= 0x20; /* constructed */
 
@@ -875,11 +1420,11 @@ store_tag_length (unsigned char *p, int tag, size_t n)
    is:
 
        SEQUENCE {
-         INTEGER (0)  -- Unknown constant. 
+         INTEGER (0)  -- Unknown constant.
          INTEGER      -- n
          INTEGER      -- e
          INTEGER      -- d
-         INTEGER      -- p     
+         INTEGER      -- p
          INTEGER      -- q      (with p < q)
          INTEGER      -- dmp1 = d mod (p-1)
          INTEGER      -- dmq1 = d mod (q-1)
@@ -899,7 +1444,7 @@ run_rsa_gen (int keysize, int pubexp)
   size_t derlen, needed, n;
   unsigned char *derbuf, *der;
 
-  err = gcry_sexp_build (&keyspec, NULL, 
+  err = gcry_sexp_build (&keyspec, NULL,
                          "(genkey (rsa (nbits %d)(rsa-use-e %d)))",
                          keysize, pubexp);
   if (err)
@@ -909,7 +1454,7 @@ run_rsa_gen (int keysize, int pubexp)
   err = gcry_pk_genkey (&key, keyspec);
   if (err)
     die ("gcry_pk_genkey failed for RSA: %s\n", gpg_strerror (err));
-  
+
   gcry_sexp_release (keyspec);
 
   l1 = gcry_sexp_find_token (key, "private-key", 0);
@@ -926,7 +1471,7 @@ run_rsa_gen (int keysize, int pubexp)
 
   /* Extract the parameters from the S-expression and store them in a
      well defined order in KEYPARMS.  */
-  for (idx=0; idx < DIM(keyparms); idx++) 
+  for (idx=0; idx < DIM(keyparms); idx++)
     {
       if (keyelems[idx] == '.')
         {
@@ -945,7 +1490,7 @@ run_rsa_gen (int keysize, int pubexp)
 
   gcry_sexp_release (key);
 
-  /* Check that p < q; if not swap p and q and recompute u.  */ 
+  /* Check that p < q; if not swap p and q and recompute u.  */
   if (gcry_mpi_cmp (keyparms[3], keyparms[4]) > 0)
     {
       gcry_mpi_swap (keyparms[3], keyparms[4]);
@@ -958,131 +1503,754 @@ run_rsa_gen (int keysize, int pubexp)
   gcry_mpi_sub_ui (keyparms[6], keyparms[4], 1);
   gcry_mpi_mod (keyparms[6], keyparms[2], keyparms[6]);
 
-  /* Compute the length of the DER encoding.  */
-  needed = compute_tag_length (1) + 1;  
-  for (idx=0; idx < DIM(keyparms); idx++) 
-    {
-      err = gcry_mpi_print (GCRYMPI_FMT_STD, NULL, 0, &n, keyparms[idx]);
-      if (err)
-        die ("error formatting parameter: %s\n", gpg_strerror (err));
-      keyparmslen[idx] = n;
-      needed += compute_tag_length (n) + n;
-    }
-  
-  /* Store the key parameters. */
-  derlen = compute_tag_length (needed) + needed;
-  der = derbuf = gcry_xmalloc (derlen);
+  /* Compute the length of the DER encoding.  */
+  needed = compute_tag_length (1) + 1;
+  for (idx=0; idx < DIM(keyparms); idx++)
+    {
+      err = gcry_mpi_print (GCRYMPI_FMT_STD, NULL, 0, &n, keyparms[idx]);
+      if (err)
+        die ("error formatting parameter: %s\n", gpg_strerror (err));
+      keyparmslen[idx] = n;
+      needed += compute_tag_length (n) + n;
+    }
+
+  /* Store the key parameters. */
+  derlen = compute_tag_length (needed) + needed;
+  der = derbuf = gcry_xmalloc (derlen);
+
+  der = store_tag_length (der, TAG_SEQUENCE, needed);
+  der = store_tag_length (der, TAG_INTEGER, 1);
+  *der++ = 0;
+  for (idx=0; idx < DIM(keyparms); idx++)
+    {
+      der = store_tag_length (der, TAG_INTEGER, keyparmslen[idx]);
+      err = gcry_mpi_print (GCRYMPI_FMT_STD, der,
+                           keyparmslen[idx], NULL, keyparms[idx]);
+      if (err)
+        die ("error formatting parameter: %s\n", gpg_strerror (err));
+      der += keyparmslen[idx];
+    }
+
+  /* Print the stuff.  */
+  for (idx=0; idx < DIM(keyparms); idx++)
+    gcry_mpi_release (keyparms[idx]);
+
+  assert (der - derbuf == derlen);
+
+  if (base64_output)
+    puts ("-----BEGIN RSA PRIVATE KEY-----");
+  print_buffer (derbuf, derlen);
+  if (base64_output)
+    puts ("-----END RSA PRIVATE KEY-----");
+
+  gcry_free (derbuf);
+}
+
+
+\f
+/* Sign DATA of length DATALEN using the key taken from the PEM
+   encoded KEYFILE and the hash algorithm HASHALGO.  */
+static void
+run_rsa_sign (const void *data, size_t datalen,
+              int hashalgo, int pkcs1, int pss, const char *keyfile)
+
+{
+  gpg_error_t err;
+  gcry_sexp_t s_data, s_key, s_sig, s_tmp;
+  gcry_mpi_t sig_mpi = NULL;
+  unsigned char *outbuf;
+  size_t outlen;
+
+/*   showhex ("D", data, datalen); */
+  if (pkcs1)
+    {
+      unsigned char hash[64];
+      unsigned int hashsize;
+
+      hashsize = gcry_md_get_algo_dlen (hashalgo);
+      if (!hashsize || hashsize > sizeof hash)
+        die ("digest too long for buffer or unknown hash algorithm\n");
+      gcry_md_hash_buffer (hashalgo, hash, data, datalen);
+      err = gcry_sexp_build (&s_data, NULL,
+                             "(data (flags pkcs1)(hash %s %b))",
+                             gcry_md_algo_name (hashalgo),
+                             (int)hashsize, hash);
+    }
+  else if (pss)
+    {
+      unsigned char hash[64];
+      unsigned int hashsize;
+
+      hashsize = gcry_md_get_algo_dlen (hashalgo);
+      if (!hashsize || hashsize > sizeof hash)
+        die ("digest too long for buffer or unknown hash algorithm\n");
+      gcry_md_hash_buffer (hashalgo, hash, data, datalen);
+      err = gcry_sexp_build (&s_data, NULL,
+                             "(data (flags pss)(salt-length #00#)(hash %s %b))",
+                             gcry_md_algo_name (hashalgo),
+                             (int)hashsize, hash);
+    }
+  else
+    {
+      gcry_mpi_t tmp;
+
+      err = gcry_mpi_scan (&tmp, GCRYMPI_FMT_USG, data, datalen,NULL);
+      if (!err)
+        {
+          err = gcry_sexp_build (&s_data, NULL,
+                                 "(data (flags raw)(value %m))", tmp);
+          gcry_mpi_release (tmp);
+        }
+    }
+  if (err)
+    die ("gcry_sexp_build failed for RSA data input: %s\n",
+         gpg_strerror (err));
+
+  s_key = read_private_key_file (keyfile, 0);
+
+  err = gcry_pk_sign (&s_sig, s_data, s_key);
+  if (err)
+    {
+      gcry_sexp_release (read_private_key_file (keyfile, 1));
+      die ("gcry_pk_signed failed (datalen=%d,keyfile=%s): %s\n",
+           (int)datalen, keyfile, gpg_strerror (err));
+    }
+  gcry_sexp_release (s_key);
+  gcry_sexp_release (s_data);
+
+  s_tmp = gcry_sexp_find_token (s_sig, "sig-val", 0);
+  if (s_tmp)
+    {
+      gcry_sexp_release (s_sig);
+      s_sig = s_tmp;
+      s_tmp = gcry_sexp_find_token (s_sig, "rsa", 0);
+      if (s_tmp)
+        {
+          gcry_sexp_release (s_sig);
+          s_sig = s_tmp;
+          s_tmp = gcry_sexp_find_token (s_sig, "s", 0);
+          if (s_tmp)
+            {
+              gcry_sexp_release (s_sig);
+              s_sig = s_tmp;
+              sig_mpi = gcry_sexp_nth_mpi (s_sig, 1, GCRYMPI_FMT_USG);
+            }
+        }
+    }
+  gcry_sexp_release (s_sig);
+
+  if (!sig_mpi)
+    die ("no value in returned S-expression\n");
+  err = gcry_mpi_aprint (GCRYMPI_FMT_STD, &outbuf, &outlen, sig_mpi);
+  if (err)
+    die ("gcry_mpi_aprint failed: %s\n", gpg_strerror (err));
+  gcry_mpi_release (sig_mpi);
+
+  print_buffer (outbuf, outlen);
+  gcry_free (outbuf);
+}
+
+
+\f
+/* Verify DATA of length DATALEN using the public key taken from the
+   PEM encoded KEYFILE and the hash algorithm HASHALGO against the
+   binary signature in SIGFILE.  */
+static void
+run_rsa_verify (const void *data, size_t datalen, int hashalgo, int pkcs1,
+                int pss, const char *keyfile, const char *sigfile)
+
+{
+  gpg_error_t err;
+  gcry_sexp_t s_data, s_key, s_sig;
+
+  if (pkcs1)
+    {
+      unsigned char hash[64];
+      unsigned int hashsize;
+
+      hashsize = gcry_md_get_algo_dlen (hashalgo);
+      if (!hashsize || hashsize > sizeof hash)
+        die ("digest too long for buffer or unknown hash algorithm\n");
+      gcry_md_hash_buffer (hashalgo, hash, data, datalen);
+      err = gcry_sexp_build (&s_data, NULL,
+                             "(data (flags pkcs1)(hash %s %b))",
+                             gcry_md_algo_name (hashalgo),
+                             (int)hashsize, hash);
+    }
+  else if (pss)
+    {
+      unsigned char hash[64];
+      unsigned int hashsize;
+
+      hashsize = gcry_md_get_algo_dlen (hashalgo);
+      if (!hashsize || hashsize > sizeof hash)
+        die ("digest too long for buffer or unknown hash algorithm\n");
+      gcry_md_hash_buffer (hashalgo, hash, data, datalen);
+      err = gcry_sexp_build (&s_data, NULL,
+                             "(data (flags pss)(salt-length #00#)(hash %s %b))",
+                             gcry_md_algo_name (hashalgo),
+                             (int)hashsize, hash);
+    }
+  else
+    {
+      gcry_mpi_t tmp;
+
+      err = gcry_mpi_scan (&tmp, GCRYMPI_FMT_USG, data, datalen,NULL);
+      if (!err)
+        {
+          err = gcry_sexp_build (&s_data, NULL,
+                                 "(data (flags raw)(value %m))", tmp);
+          gcry_mpi_release (tmp);
+        }
+    }
+  if (err)
+    die ("gcry_sexp_build failed for RSA data input: %s\n",
+         gpg_strerror (err));
+
+  s_key = read_public_key_file (keyfile, 0);
+
+  s_sig = read_sig_file (sigfile);
+
+  err = gcry_pk_verify (s_sig, s_data, s_key);
+  if (!err)
+    puts ("GOOD signature");
+  else if (gpg_err_code (err) == GPG_ERR_BAD_SIGNATURE)
+    puts ("BAD signature");
+  else
+    printf ("ERROR (%s)\n", gpg_strerror (err));
+
+  gcry_sexp_release (s_sig);
+  gcry_sexp_release (s_key);
+  gcry_sexp_release (s_data);
+}
+
+
+\f
+/* Generate a DSA key of size KEYSIZE and return the complete
+   S-expression.  */
+static gcry_sexp_t
+dsa_gen (int keysize)
+{
+  gpg_error_t err;
+  gcry_sexp_t keyspec, key;
+
+  err = gcry_sexp_build (&keyspec, NULL,
+                         "(genkey (dsa (nbits %d)(use-fips186-2)))",
+                         keysize);
+  if (err)
+    die ("gcry_sexp_build failed for DSA key generation: %s\n",
+         gpg_strerror (err));
+
+  err = gcry_pk_genkey (&key, keyspec);
+  if (err)
+    die ("gcry_pk_genkey failed for DSA: %s\n", gpg_strerror (err));
+
+  gcry_sexp_release (keyspec);
+
+  return key;
+}
+
+
+/* Generate a DSA key of size KEYSIZE and return the complete
+   S-expression.  */
+static gcry_sexp_t
+dsa_gen_with_seed (int keysize, const void *seed, size_t seedlen)
+{
+  gpg_error_t err;
+  gcry_sexp_t keyspec, key;
+
+  err = gcry_sexp_build (&keyspec, NULL,
+                         "(genkey"
+                         "  (dsa"
+                         "    (nbits %d)"
+                         "    (use-fips186-2)"
+                         "    (derive-parms"
+                         "      (seed %b))))",
+                         keysize, (int)seedlen, seed);
+  if (err)
+    die ("gcry_sexp_build failed for DSA key generation: %s\n",
+         gpg_strerror (err));
+
+  err = gcry_pk_genkey (&key, keyspec);
+  if (err)
+    die ("gcry_pk_genkey failed for DSA: %s\n", gpg_strerror (err));
+
+  gcry_sexp_release (keyspec);
+
+  return key;
+}
+
+
+/* Generate an ECDSA key on the specified curve and return the complete
+   S-expression. */
+static gcry_sexp_t
+ecdsa_gen_key (const char *curve)
+{
+  gpg_error_t err;
+  gcry_sexp_t keyspec, key;
+
+  err = gcry_sexp_build (&keyspec, NULL,
+                         "(genkey"
+                         "  (ecc"
+                         "    (use-fips186)"
+                         "    (curve %s)))",
+                         curve);
+  if (err)
+    die ("gcry_sexp_build failed for ECDSA key generation: %s\n",
+         gpg_strerror (err));
+  err = gcry_pk_genkey (&key, keyspec);
+  if (err)
+    die ("gcry_pk_genkey failed for ECDSA: %s\n", gpg_strerror (err));
+
+  gcry_sexp_release (keyspec);
+
+  return key;
+}
+
+
+/* Print the domain parameter as well as the derive information.  KEY
+   is the complete key as returned by dsa_gen.  We print to stdout
+   with one parameter per line in hex format using this order: p, q,
+   g, seed, counter, h. */
+static void
+print_dsa_domain_parameters (gcry_sexp_t key)
+{
+  gcry_sexp_t l1, l2;
+  gcry_mpi_t mpi;
+  int idx;
+  const void *data;
+  size_t datalen;
+  char *string;
+
+  l1 = gcry_sexp_find_token (key, "public-key", 0);
+  if (!l1)
+    die ("public key not found in genkey result\n");
+
+  l2 = gcry_sexp_find_token (l1, "dsa", 0);
+  if (!l2)
+    die ("returned public key not formed as expected\n");
+  gcry_sexp_release (l1);
+  l1 = l2;
+
+  /* Extract the parameters from the S-expression and print them to stdout.  */
+  for (idx=0; "pqg"[idx]; idx++)
+    {
+      l2 = gcry_sexp_find_token (l1, "pqg"+idx, 1);
+      if (!l2)
+        die ("no %c parameter in returned public key\n", "pqg"[idx]);
+      mpi = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
+      if (!mpi)
+        die ("no value for %c parameter in returned public key\n","pqg"[idx]);
+      gcry_sexp_release (l2);
+      if (standalone_mode)
+        printf ("%c = ", "PQG"[idx]);
+      print_mpi_line (mpi, 1);
+      gcry_mpi_release (mpi);
+    }
+  gcry_sexp_release (l1);
+
+  /* Extract the seed values.  */
+  l1 = gcry_sexp_find_token (key, "misc-key-info", 0);
+  if (!l1)
+    die ("misc-key-info not found in genkey result\n");
+
+  l2 = gcry_sexp_find_token (l1, "seed-values", 0);
+  if (!l2)
+    die ("no seed-values in returned key\n");
+  gcry_sexp_release (l1);
+  l1 = l2;
+
+  l2 = gcry_sexp_find_token (l1, "seed", 0);
+  if (!l2)
+    die ("no seed value in returned key\n");
+  data = gcry_sexp_nth_data (l2, 1, &datalen);
+  if (!data)
+    die ("no seed value in returned key\n");
+  if (standalone_mode)
+    printf ("Seed = ");
+  print_data_line (data, datalen);
+  gcry_sexp_release (l2);
+
+  l2 = gcry_sexp_find_token (l1, "counter", 0);
+  if (!l2)
+    die ("no counter value in returned key\n");
+  string = gcry_sexp_nth_string (l2, 1);
+  if (!string)
+    die ("no counter value in returned key\n");
+  if (standalone_mode)
+    printf ("c = %ld\n", strtoul (string, NULL, 10));
+  else
+    printf ("%lX\n", strtoul (string, NULL, 10));
+  gcry_free (string);
+  gcry_sexp_release (l2);
+
+  l2 = gcry_sexp_find_token (l1, "h", 0);
+  if (!l2)
+    die ("no n value in returned key\n");
+  mpi = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
+  if (!mpi)
+    die ("no h value in returned key\n");
+  if (standalone_mode)
+    printf ("H = ");
+  print_mpi_line (mpi, 1);
+  gcry_mpi_release (mpi);
+  gcry_sexp_release (l2);
+
+  gcry_sexp_release (l1);
+}
+
+
+/* Print public key Q (in octet-string format) and private key d.
+   KEY is the complete key as returned by ecdsa_gen_key.
+   with one parameter per line in hex format using this order: d, Q. */
+static void
+print_ecdsa_dq (gcry_sexp_t key)
+{
+  gcry_sexp_t l1, l2;
+  gcry_mpi_t mpi;
+  int idx;
+
+  l1 = gcry_sexp_find_token (key, "private-key", 0);
+  if (!l1)
+    die ("private key not found in genkey result\n");
+
+  l2 = gcry_sexp_find_token (l1, "ecc", 0);
+  if (!l2)
+    die ("returned private key not formed as expected\n");
+  gcry_sexp_release (l1);
+  l1 = l2;
+
+  /* Extract the parameters from the S-expression and print them to stdout.  */
+  for (idx=0; "dq"[idx]; idx++)
+    {
+      l2 = gcry_sexp_find_token (l1, "dq"+idx, 1);
+      if (!l2)
+        die ("no %c parameter in returned public key\n", "dq"[idx]);
+      mpi = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
+      if (!mpi)
+        die ("no value for %c parameter in returned private key\n","dq"[idx]);
+      gcry_sexp_release (l2);
+      if (standalone_mode)
+        printf ("%c = ", "dQ"[idx]);
+      print_mpi_line (mpi, 1);
+      gcry_mpi_release (mpi);
+    }
+
+  gcry_sexp_release (l1);
+}
+
+
+/* Generate DSA domain parameters for a modulus size of KEYSIZE.  The
+   result is printed to stdout with one parameter per line in hex
+   format and in this order: p, q, g, seed, counter, h.  If SEED is
+   not NULL this seed value will be used for the generation.  */
+static void
+run_dsa_pqg_gen (int keysize, const void *seed, size_t seedlen)
+{
+  gcry_sexp_t key;
+
+  if (seed)
+    key = dsa_gen_with_seed (keysize, seed, seedlen);
+  else
+    key = dsa_gen (keysize);
+  print_dsa_domain_parameters (key);
+  gcry_sexp_release (key);
+}
+
+
+/* Generate a DSA key of size of KEYSIZE and write the private key to
+   FILENAME.  Also write the parameters to stdout in the same way as
+   run_dsa_pqg_gen.  */
+static void
+run_dsa_gen (int keysize, const char *filename)
+{
+  gcry_sexp_t key, private_key;
+  FILE *fp;
+
+  key = dsa_gen (keysize);
+  private_key = gcry_sexp_find_token (key, "private-key", 0);
+  if (!private_key)
+    die ("private key not found in genkey result\n");
+  print_dsa_domain_parameters (key);
+
+  fp = fopen (filename, "wb");
+  if (!fp)
+    die ("can't create `%s': %s\n", filename, strerror (errno));
+  print_sexp (private_key, fp);
+  fclose (fp);
+
+  gcry_sexp_release (private_key);
+  gcry_sexp_release (key);
+}
+
+
+\f
+/* Sign DATA of length DATALEN using the key taken from the S-expression
+   encoded KEYFILE. */
+static void
+run_dsa_sign (const void *data, size_t datalen, const char *keyfile)
+
+{
+  gpg_error_t err;
+  gcry_sexp_t s_data, s_key, s_sig, s_tmp, s_tmp2;
+  char hash[20];
+  gcry_mpi_t tmpmpi;
+
+  gcry_md_hash_buffer (GCRY_MD_SHA1, hash, data, datalen);
+  err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash, 20, NULL);
+  if (!err)
+    {
+      err = gcry_sexp_build (&s_data, NULL,
+                             "(data (flags raw)(value %m))", tmpmpi);
+      gcry_mpi_release (tmpmpi);
+    }
+  if (err)
+    die ("gcry_sexp_build failed for DSA data input: %s\n",
+         gpg_strerror (err));
+
+  s_key = read_sexp_from_file (keyfile);
+
+  err = gcry_pk_sign (&s_sig, s_data, s_key);
+  if (err)
+    {
+      gcry_sexp_release (read_private_key_file (keyfile, 1));
+      die ("gcry_pk_signed failed (datalen=%d,keyfile=%s): %s\n",
+           (int)datalen, keyfile, gpg_strerror (err));
+    }
+  gcry_sexp_release (s_data);
+
+  /* We need to return the Y parameter first.  */
+  s_tmp = gcry_sexp_find_token (s_key, "private-key", 0);
+  if (!s_tmp)
+    die ("private key part not found in provided key\n");
+
+  s_tmp2 = gcry_sexp_find_token (s_tmp, "dsa", 0);
+  if (!s_tmp2)
+    die ("private key part is not a DSA key\n");
+  gcry_sexp_release (s_tmp);
+
+  s_tmp = gcry_sexp_find_token (s_tmp2, "y", 0);
+  tmpmpi = gcry_sexp_nth_mpi (s_tmp, 1, GCRYMPI_FMT_USG);
+  if (!tmpmpi)
+    die ("no y parameter in DSA key\n");
+  print_mpi_line (tmpmpi, 1);
+  gcry_mpi_release (tmpmpi);
+  gcry_sexp_release (s_tmp);
+
+  gcry_sexp_release (s_key);
+
+
+  /* Now return the actual signature.  */
+  s_tmp = gcry_sexp_find_token (s_sig, "sig-val", 0);
+  if (!s_tmp)
+    die ("no sig-val element in returned S-expression\n");
+
+  gcry_sexp_release (s_sig);
+  s_sig = s_tmp;
+  s_tmp = gcry_sexp_find_token (s_sig, "dsa", 0);
+  if (!s_tmp)
+    die ("no dsa element in returned S-expression\n");
+
+  gcry_sexp_release (s_sig);
+  s_sig = s_tmp;
+
+  s_tmp = gcry_sexp_find_token (s_sig, "r", 0);
+  tmpmpi = gcry_sexp_nth_mpi (s_tmp, 1, GCRYMPI_FMT_USG);
+  if (!tmpmpi)
+    die ("no r parameter in returned S-expression\n");
+  print_mpi_line (tmpmpi, 1);
+  gcry_mpi_release (tmpmpi);
+  gcry_sexp_release (s_tmp);
+
+  s_tmp = gcry_sexp_find_token (s_sig, "s", 0);
+  tmpmpi = gcry_sexp_nth_mpi (s_tmp, 1, GCRYMPI_FMT_USG);
+  if (!tmpmpi)
+    die ("no s parameter in returned S-expression\n");
+  print_mpi_line (tmpmpi, 1);
+  gcry_mpi_release (tmpmpi);
+  gcry_sexp_release (s_tmp);
+
+  gcry_sexp_release (s_sig);
+}
+
+
+\f
+/* Verify DATA of length DATALEN using the public key taken from the
+   S-expression in KEYFILE against the S-expression formatted
+   signature in SIGFILE.  */
+static void
+run_dsa_verify (const void *data, size_t datalen,
+                const char *keyfile, const char *sigfile)
 
-  der = store_tag_length (der, TAG_SEQUENCE, needed);
-  der = store_tag_length (der, TAG_INTEGER, 1);
-  *der++ = 0;
-  for (idx=0; idx < DIM(keyparms); idx++) 
+{
+  gpg_error_t err;
+  gcry_sexp_t s_data, s_key, s_sig;
+  char hash[20];
+  gcry_mpi_t tmpmpi;
+
+  gcry_md_hash_buffer (GCRY_MD_SHA1, hash, data, datalen);
+  /* Note that we can't simply use %b with HASH to build the
+     S-expression, because that might yield a negative value.  */
+  err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash, 20, NULL);
+  if (!err)
     {
-      der = store_tag_length (der, TAG_INTEGER, keyparmslen[idx]);
-      err = gcry_mpi_print (GCRYMPI_FMT_STD, der, 
-                           keyparmslen[idx], NULL, keyparms[idx]);
-      if (err)
-        die ("error formatting parameter: %s\n", gpg_strerror (err));
-      der += keyparmslen[idx];
+      err = gcry_sexp_build (&s_data, NULL,
+                             "(data (flags raw)(value %m))", tmpmpi);
+      gcry_mpi_release (tmpmpi);
     }
+  if (err)
+    die ("gcry_sexp_build failed for DSA data input: %s\n",
+         gpg_strerror (err));
 
-  /* Print the stuff.  */
-  for (idx=0; idx < DIM(keyparms); idx++) 
-    gcry_mpi_release (keyparms[idx]);
-
-  assert (der - derbuf == derlen);
+  s_key = read_sexp_from_file (keyfile);
+  s_sig = read_sexp_from_file (sigfile);
 
-  if (base64_output)
-    puts ("-----BEGIN RSA PRIVATE KEY-----");
-  print_buffer (derbuf, derlen);
-  if (base64_output)
-    puts ("-----END RSA PRIVATE KEY-----");
+  err = gcry_pk_verify (s_sig, s_data, s_key);
+  if (!err)
+    puts ("GOOD signature");
+  else if (gpg_err_code (err) == GPG_ERR_BAD_SIGNATURE)
+    puts ("BAD signature");
+  else
+    printf ("ERROR (%s)\n", gpg_strerror (err));
 
-  gcry_free (derbuf);
+  gcry_sexp_release (s_sig);
+  gcry_sexp_release (s_key);
+  gcry_sexp_release (s_data);
 }
 
 
 \f
-/* Sign DATA of length DATALEN using the key taken from the PEM
-   encoded KEYFILE and the hash algorithm HASHALGO.  */
+/* Sign DATA of length DATALEN using the key taken from the S-expression
+   encoded KEYFILE. */
 static void
-run_rsa_sign (const void *data, size_t datalen,
-              int hashalgo, int pkcs1, const char *keyfile)
+run_ecdsa_sign (const void *data, size_t datalen,
+                const char *keyfile, const int algo)
 
 {
   gpg_error_t err;
   gcry_sexp_t s_data, s_key, s_sig, s_tmp;
-  gcry_mpi_t sig_mpi = NULL;
-  unsigned char *outbuf;
-  size_t outlen;
-  
-/*   showhex ("D", data, datalen); */
+  char hash[128];
+  gcry_mpi_t tmpmpi;
 
-  if (pkcs1)
-    err = gcry_sexp_build (&s_data, NULL,
-                           "(data (flags pkcs1)(hash %s %b))",
-                           gcry_md_algo_name (hashalgo), (int)datalen, data);
-  else
-    {
-      gcry_mpi_t tmp;
+  s_key = read_sexp_from_file (keyfile);
 
-      err = gcry_mpi_scan (&tmp, GCRYMPI_FMT_USG, data, datalen,NULL);
-      if (!err)
-        {
-          err = gcry_sexp_build (&s_data, NULL,
-                                 "(data (flags raw)(value %m))", tmp);
-          gcry_mpi_release (tmp);
-        }
+  gcry_md_hash_buffer (algo, hash, data, datalen);
+  err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash,
+                       gcry_md_get_algo_dlen(algo), NULL);
+  if (!err)
+    {
+      err = gcry_sexp_build (&s_data, NULL,
+                             "(data (flags raw)(hash %s %M))",
+                             gcry_md_algo_name(algo), tmpmpi);
+      gcry_mpi_release (tmpmpi);
     }
   if (err)
-    die ("gcry_sexp_build failed for RSA data input: %s\n",
+    die ("gcry_sexp_build failed for ECDSA data input: %s\n",
          gpg_strerror (err));
 
-  s_key = read_key_file (keyfile, 0);
-
   err = gcry_pk_sign (&s_sig, s_data, s_key);
   if (err)
     {
-      gcry_sexp_release (read_key_file (keyfile, 1));
-      die ("gcry_pk_signed failed (datalen=%d,keyfile=%s): %s\n",
-           (int)datalen, keyfile, gpg_strerror (err));
+      die ("gcry_pk_signed failed: %s\n", gpg_strerror (err));
     }
-  gcry_sexp_release (s_key);
   gcry_sexp_release (s_data);
+  gcry_sexp_release (s_key);
 
+  /* Now return the actual signature.  */
   s_tmp = gcry_sexp_find_token (s_sig, "sig-val", 0);
-  if (s_tmp)
+  if (!s_tmp)
+    die ("no sig-val element in returned S-expression\n");
+
+  gcry_sexp_release (s_sig);
+  s_sig = s_tmp;
+  s_tmp = gcry_sexp_find_token (s_sig, "ecdsa", 0);
+  if (!s_tmp)
+    die ("no ecdsa element in returned S-expression\n");
+
+  gcry_sexp_release (s_sig);
+  s_sig = s_tmp;
+
+  s_tmp = gcry_sexp_find_token (s_sig, "r", 0);
+  tmpmpi = gcry_sexp_nth_mpi (s_tmp, 1, GCRYMPI_FMT_USG);
+  if (!tmpmpi)
+    die ("no r parameter in returned S-expression\n");
+  print_mpi_line (tmpmpi, 1);
+  gcry_mpi_release (tmpmpi);
+  gcry_sexp_release (s_tmp);
+
+  s_tmp = gcry_sexp_find_token (s_sig, "s", 0);
+  tmpmpi = gcry_sexp_nth_mpi (s_tmp, 1, GCRYMPI_FMT_USG);
+  if (!tmpmpi)
+    die ("no s parameter in returned S-expression\n");
+  print_mpi_line (tmpmpi, 1);
+  gcry_mpi_release (tmpmpi);
+  gcry_sexp_release (s_tmp);
+
+  gcry_sexp_release (s_sig);
+}
+
+
+\f
+/* Verify DATA of length DATALEN using the public key taken from the
+   S-expression in KEYFILE against the S-expression formatted
+   signature in SIGFILE.  */
+static void
+run_ecdsa_verify (const void *data, size_t datalen,
+                const char *keyfile, const int algo, const char *sigfile)
+
+{
+  gpg_error_t err;
+  gcry_sexp_t s_data, s_key, s_sig;
+  char hash[128];
+  gcry_mpi_t tmpmpi;
+
+  s_key = read_sexp_from_file (keyfile);
+
+  gcry_md_hash_buffer (algo, hash, data, datalen);
+  /* Note that we can't simply use %b with HASH to build the
+     S-expression, because that might yield a negative value.  */
+  err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_USG, hash,
+                       gcry_md_get_algo_dlen(algo), NULL);
+  if (!err)
     {
-      gcry_sexp_release (s_sig);
-      s_sig = s_tmp;
-      s_tmp = gcry_sexp_find_token (s_sig, "rsa", 0);
-      if (s_tmp)
-        {
-          gcry_sexp_release (s_sig);
-          s_sig = s_tmp;
-          s_tmp = gcry_sexp_find_token (s_sig, "s", 0);
-          if (s_tmp)
-            {
-              gcry_sexp_release (s_sig);
-              s_sig = s_tmp;
-              sig_mpi = gcry_sexp_nth_mpi (s_sig, 1, GCRYMPI_FMT_USG);
-            }
-        }
+      err = gcry_sexp_build (&s_data, NULL,
+                             "(data (flags raw)(hash %s %M))",
+                             gcry_md_algo_name(algo), tmpmpi);
+      gcry_mpi_release (tmpmpi);
     }
-  gcry_sexp_release (s_sig);
-              
-  if (!sig_mpi)
-    die ("no value in returned S-expression\n");
-  err = gcry_mpi_aprint (GCRYMPI_FMT_STD, &outbuf, &outlen, sig_mpi);
   if (err)
-    die ("gcry_mpi_aprint failed: %s\n", gpg_strerror (err));
-  gcry_mpi_release (sig_mpi);
+    die ("gcry_sexp_build failed for DSA data input: %s\n",
+         gpg_strerror (err));
 
-  print_buffer (outbuf, outlen);
-  gcry_free (outbuf);
+  s_sig = read_sexp_from_file (sigfile);
+
+  err = gcry_pk_verify (s_sig, s_data, s_key);
+  if (!err)
+    puts ("GOOD signature");
+  else if (gpg_err_code (err) == GPG_ERR_BAD_SIGNATURE)
+    puts ("BAD signature");
+  else
+    printf ("ERROR (%s)\n", gpg_strerror (err));
+
+  gcry_sexp_release (s_sig);
+  gcry_sexp_release (s_key);
+  gcry_sexp_release (s_data);
 }
 
 
+/* Generate an ECDSA key with specified domain parameters
+   and print the d and Q values, in the standard octet-string format. */
+static void
+run_ecdsa_gen_key (const char *curve)
+{
+  gcry_sexp_t key;
+
+  key = ecdsa_gen_key (curve);
+  print_ecdsa_dq (key);
+
+  gcry_sexp_release (key);
+}
+
 
 \f
 static void
@@ -1090,7 +2258,7 @@ usage (int show_help)
 {
   if (!show_help)
     {
-      fputs ("usage: " PGM 
+      fputs ("usage: " PGM
              " [OPTION] [FILE] (try --help for more information)\n", stderr);
       exit (2);
     }
@@ -1098,21 +2266,27 @@ usage (int show_help)
     ("Usage: " PGM " [OPTIONS] MODE [FILE]\n"
      "Run a crypto operation using hex encoded input and output.\n"
      "MODE:\n"
-     "  encrypt, decrypt, digest, random, hmac-sha, rsa-{gen,sign,verify}\n"
+     "  encrypt, decrypt, digest, random, hmac-sha,\n"
+     "  rsa-{derive,gen,sign,verify},\n"
+     "  dsa-{pqg-gen,gen,sign,verify}, ecdsa-{gen-key,sign,verify}\n"
      "OPTIONS:\n"
-     "  --verbose       print additional information\n"
-     "  --binary        input and output is in binary form\n"
-     "  --no-fips       do not force FIPS mode\n"
-     "  --key KEY       use the hex encoded KEY\n"
-     "  --iv IV         use the hex encoded IV\n"
-     "  --dt DT         use the hex encoded DT for the RNG\n"
-     "  --algo NAME     use algorithm NAME\n"
-     "  --keysize N     use a keysize of N bits\n"
-     "  --chunk N       read in chunks of N bytes (implies --binary)\n"
-     "  --pkcs1         use PKCS#1 encoding\n"
-     "  --loop          enable random loop mode\n"
-     "  --progress      print pogress indicators\n"
-     "  --help          print this text\n"
+     "  --verbose        Print additional information\n"
+     "  --binary         Input and output is in binary form\n"
+     "  --no-fips        Do not force FIPS mode\n"
+     "  --key KEY        Use the hex encoded KEY\n"
+     "  --iv IV          Use the hex encoded IV\n"
+     "  --dt DT          Use the hex encoded DT for the RNG\n"
+     "  --algo NAME      Use algorithm NAME\n"
+     "  --curve NAME     Select ECC curve spec NAME\n"
+     "  --keysize N      Use a keysize of N bits\n"
+     "  --signature NAME Take signature from file NAME\n"
+     "  --chunk N        Read in chunks of N bytes (implies --binary)\n"
+     "  --pkcs1          Use PKCS#1 encoding\n"
+     "  --pss            Use PSS encoding with a zero length salt\n"
+     "  --mct-server     Run a monte carlo test server\n"
+     "  --loop           Enable random loop mode\n"
+     "  --progress       Print pogress indicators\n"
+     "  --help           Print this text\n"
      "With no FILE, or when FILE is -, read standard input.\n"
      "Report bugs to " PACKAGE_BUGREPORT ".\n" , stdout);
   exit (0);
@@ -1126,16 +2300,20 @@ main (int argc, char **argv)
   int no_fips = 0;
   int progress = 0;
   int use_pkcs1 = 0;
+  int use_pss = 0;
   const char *mode_string;
+  const char *curve_string = NULL;
   const char *key_string = NULL;
   const char *iv_string = NULL;
   const char *dt_string = NULL;
   const char *algo_string = NULL;
   const char *keysize_string = NULL;
+  const char *signature_string = NULL;
   FILE *input;
   void *data;
   size_t datalen;
   size_t chunksize = 0;
+  int mct_server = 0;
 
 
   if (argc)
@@ -1223,6 +2401,14 @@ main (int argc, char **argv)
           keysize_string = *argv;
           argc--; argv++;
         }
+      else if (!strcmp (*argv, "--signature"))
+        {
+          argc--; argv++;
+          if (!argc)
+            usage (0);
+          signature_string = *argv;
+          argc--; argv++;
+        }
       else if (!strcmp (*argv, "--chunk"))
         {
           argc--; argv++;
@@ -1232,16 +2418,47 @@ main (int argc, char **argv)
           binary_input = binary_output = 1;
           argc--; argv++;
         }
+      else if (!strcmp (*argv, "--curve"))
+        {
+          argc--; argv++;
+          if (!argc)
+            usage (0);
+          curve_string = *argv;
+          argc--; argv++;
+        }
       else if (!strcmp (*argv, "--pkcs1"))
         {
           use_pkcs1 = 1;
           argc--; argv++;
         }
-    }          
+      else if (!strcmp (*argv, "--pss"))
+        {
+          use_pss = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--mct-server"))
+        {
+          mct_server = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--standalone"))
+        {
+          standalone_mode = 1;
+          argc--; argv++;
+        }
+    }
 
   if (!argc || argc > 2)
     usage (0);
+
   mode_string = *argv;
+
+  if (use_pkcs1 && use_pss)
+    die ("Only one of --pkcs or --pss may be given\n");
+
+  if (!strcmp (mode_string, "rsa-derive"))
+    binary_input = 1;
+
   if (argc == 2 && strcmp (argv[1], "-"))
     {
       input = fopen (argv[1], binary_input? "rb":"r");
@@ -1259,27 +2476,32 @@ main (int argc, char **argv)
   if (verbose)
     fprintf (stderr, PGM ": started (mode=%s)\n", mode_string);
 
-  gcry_control (GCRYCTL_SET_VERBOSITY, (int)verbose);
+  xgcry_control (GCRYCTL_SET_VERBOSITY, (int)verbose);
   if (!no_fips)
-    gcry_control (GCRYCTL_FORCE_FIPS_MODE, 0);
+    xgcry_control (GCRYCTL_FORCE_FIPS_MODE, 0);
   if (!gcry_check_version ("1.4.3"))
     die ("Libgcrypt is not sufficient enough\n");
   if (verbose)
     fprintf (stderr, PGM ": using Libgcrypt %s\n", gcry_check_version (NULL));
   if (no_fips)
-    gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
-  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+    xgcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+  xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
 
   /* Most operations need some input data.  */
   if (!chunksize
+      && !mct_server
       && strcmp (mode_string, "random")
-      && strcmp (mode_string, "rsa-gen") )
+      && strcmp (mode_string, "rsa-gen")
+      && strcmp (mode_string, "rsa-keygen")
+      && strcmp (mode_string, "rsa-keygen-kat")
+      && strcmp (mode_string, "dsa-gen")
+      && strcmp (mode_string, "ecdsa-gen-key") )
     {
       data = read_file (input, !binary_input, &datalen);
       if (!data)
         die ("error reading%s input\n", binary_input?"":" and decoding");
       if (verbose)
-        fprintf (stderr, PGM ": %u bytes of input data\n", 
+        fprintf (stderr, PGM ": %u bytes of input data\n",
                  (unsigned int)datalen);
     }
   else
@@ -1292,7 +2514,8 @@ main (int argc, char **argv)
   if (!strcmp (mode_string, "encrypt") || !strcmp (mode_string, "decrypt"))
     {
       int cipher_algo, cipher_mode;
-      void  *iv_buffer, *key_buffer;
+      void  *iv_buffer = NULL;
+      void *key_buffer = NULL;
       size_t iv_buflen,  key_buflen;
 
       if (!algo_string)
@@ -1300,22 +2523,71 @@ main (int argc, char **argv)
       cipher_algo = map_openssl_cipher_name (algo_string, &cipher_mode);
       if (!cipher_algo)
         die ("cipher algorithm `%s' is not supported\n", algo_string);
-      if (!iv_string)
-        die ("option --iv is required in this mode\n");
-      iv_buffer = hex2buffer (iv_string, &iv_buflen);
-      if (!iv_buffer)
-        die ("invalid value for IV\n");
-      if (!key_string)
-        die ("option --key is required in this mode\n");
-      key_buffer = hex2buffer (key_string, &key_buflen);
-      if (!key_buffer)
-        die ("invalid value for KEY\n");
+      if (mct_server)
+        {
+          int iterations;
 
-      run_encrypt_decrypt ((*mode_string == 'e'),
-                           cipher_algo, cipher_mode,
-                           iv_buffer, iv_buflen,
-                           key_buffer, key_buflen,
-                           data, data? datalen:chunksize, input);
+          for (;;)
+            {
+              gcry_free (key_buffer); key_buffer = NULL;
+              gcry_free (iv_buffer); iv_buffer = NULL;
+              gcry_free (data); data = NULL;
+              if (!(key_buffer = read_textline (input)))
+                {
+                  if (feof (input))
+                    break;
+                  die ("no version info in input\n");
+                }
+              if (atoi (key_buffer) != 1)
+                die ("unsupported input version %s\n",
+                     (const char*)key_buffer);
+              gcry_free (key_buffer);
+              if (!(key_buffer = read_textline (input)))
+                die ("no iteration count in input\n");
+              iterations = atoi (key_buffer);
+              gcry_free (key_buffer);
+              if (!(key_buffer = read_hexline (input, &key_buflen)))
+                die ("no key in input\n");
+              if (!(iv_buffer = read_hexline (input, &iv_buflen)))
+                die ("no IV in input\n");
+              if (!(data = read_hexline (input, &datalen)))
+                die ("no data in input\n");
+              skip_to_empty_line (input);
+
+              run_cipher_mct_loop ((*mode_string == 'e'),
+                                   cipher_algo, cipher_mode,
+                                   iv_buffer, iv_buflen,
+                                   key_buffer, key_buflen,
+                                   data, datalen, iterations);
+            }
+        }
+      else
+        {
+          if (cipher_mode != GCRY_CIPHER_MODE_ECB)
+            {
+              if (!iv_string)
+                die ("option --iv is required in this mode\n");
+              iv_buffer = hex2buffer (iv_string, &iv_buflen);
+              if (!iv_buffer)
+                die ("invalid value for IV\n");
+            }
+          else
+            {
+              iv_buffer = NULL;
+              iv_buflen = 0;
+            }
+          if (!key_string)
+            die ("option --key is required in this mode\n");
+          key_buffer = hex2buffer (key_string, &key_buflen);
+          if (!key_buffer)
+            die ("invalid value for KEY\n");
+
+          run_encrypt_decrypt ((*mode_string == 'e'),
+                               cipher_algo, cipher_mode,
+                               iv_buffer, iv_buflen,
+                               key_buffer, key_buflen,
+                               data, data? datalen:chunksize, input);
+        }
       gcry_free (key_buffer);
       gcry_free (iv_buffer);
     }
@@ -1328,6 +2600,8 @@ main (int argc, char **argv)
       algo = gcry_md_map_name (algo_string);
       if (!algo)
         die ("digest algorithm `%s' is not supported\n", algo_string);
+      if (!data)
+        die ("no data available (do not use --chunk)\n");
 
       run_digest (algo, data, datalen);
     }
@@ -1340,11 +2614,11 @@ main (int argc, char **argv)
       unsigned char buffer[16];
       size_t count = 0;
 
-      if (hex2bin (key_string, key, 16) < 0 )
+      if (!key_string || hex2bin (key_string, key, 16) < 0 )
         die ("value for --key are not 32 hex digits\n");
-      if (hex2bin (iv_string, seed, 16) < 0 )
+      if (!iv_string || hex2bin (iv_string, seed, 16) < 0 )
         die ("value for --iv are not 32 hex digits\n");
-      if (hex2bin (dt_string, dt, 16) < 0 )
+      if (!dt_string || hex2bin (dt_string, dt, 16) < 0 )
         die ("value for --dt are not 32 hex digits\n");
 
       /* The flag value 1 disables the dup check, so that the RNG
@@ -1353,7 +2627,7 @@ main (int argc, char **argv)
       if (err)
         die ("init external RNG test failed: %s\n", gpg_strerror (err));
 
-      do 
+      do
         {
           err = run_external_rng_test (context, buffer, sizeof buffer);
           if (err)
@@ -1362,15 +2636,15 @@ main (int argc, char **argv)
           if (progress)
             {
               if (!(++count % 1000))
-                fprintf (stderr, PGM ": %lu random bytes so far\n", 
-                         (unsigned long int)count * sizeof buffer);
+                fprintf (stderr, PGM ": %lu random bytes so far\n",
+                         (unsigned long int)(count * sizeof buffer));
             }
         }
       while (loop_mode);
-      
+
       if (progress)
         fprintf (stderr, PGM ": %lu random bytes\n",
-                         (unsigned long int)count * sizeof buffer);
+                 (unsigned long int)(count * sizeof buffer));
 
       deinit_external_rng_test (context);
     }
@@ -1405,10 +2679,30 @@ main (int argc, char **argv)
 
       gcry_free (key_buffer);
     }
+  else if (!strcmp (mode_string, "rsa-derive"))
+    {
+      if (!data)
+        die ("no data available (do not use --chunk)\n");
+      run_rsa_derive (data, datalen);
+    }
+  else if (!strcmp (mode_string, "rsa-keygen"))
+    {
+      data = read_file (input, 0, &datalen);
+      if (!data)
+        die ("no data available (do not use --chunk)\n");
+      run_rsa_keygen (data, datalen, 0);
+    }
+  else if (!strcmp (mode_string, "rsa-keygen-kat"))
+    {
+      data = read_file (input, 0, &datalen);
+      if (!data)
+        die ("no data available (do not use --chunk)\n");
+      run_rsa_keygen (data, datalen, 1);
+    }
   else if (!strcmp (mode_string, "rsa-gen"))
     {
       int keysize;
-      
+
       if (!binary_output)
         base64_output = 1;
 
@@ -1433,11 +2727,125 @@ main (int argc, char **argv)
       if (!data)
         die ("no data available (do not use --chunk)\n");
 
-      run_rsa_sign (data, datalen, algo, use_pkcs1, key_string);
+      run_rsa_sign (data, datalen, algo, use_pkcs1, use_pss, key_string);
 
     }
   else if (!strcmp (mode_string, "rsa-verify"))
     {
+      int algo;
+
+      if (!key_string)
+        die ("option --key is required in this mode\n");
+      if (access (key_string, R_OK))
+        die ("option --key needs to specify an existing keyfile\n");
+      if (!algo_string)
+        die ("option --algo is required in this mode\n");
+      algo = gcry_md_map_name (algo_string);
+      if (!algo)
+        die ("digest algorithm `%s' is not supported\n", algo_string);
+      if (!data)
+        die ("no data available (do not use --chunk)\n");
+      if (!signature_string)
+        die ("option --signature is required in this mode\n");
+      if (access (signature_string, R_OK))
+        die ("option --signature needs to specify an existing file\n");
+
+      run_rsa_verify (data, datalen, algo, use_pkcs1, use_pss, key_string,
+                      signature_string);
+
+    }
+  else if (!strcmp (mode_string, "dsa-pqg-gen"))
+    {
+      int keysize;
+
+      keysize = keysize_string? atoi (keysize_string) : 0;
+      if (keysize < 1024 || keysize > 3072)
+        die ("invalid keysize specified; needs to be 1024 .. 3072\n");
+      run_dsa_pqg_gen (keysize, datalen? data:NULL, datalen);
+    }
+  else if (!strcmp (mode_string, "dsa-gen"))
+    {
+      int keysize;
+
+      keysize = keysize_string? atoi (keysize_string) : 0;
+      if (keysize < 1024 || keysize > 3072)
+        die ("invalid keysize specified; needs to be 1024 .. 3072\n");
+      if (!key_string)
+        die ("option --key is required in this mode\n");
+      run_dsa_gen (keysize, key_string);
+    }
+  else if (!strcmp (mode_string, "dsa-sign"))
+    {
+      if (!key_string)
+        die ("option --key is required in this mode\n");
+      if (access (key_string, R_OK))
+        die ("option --key needs to specify an existing keyfile\n");
+      if (!data)
+        die ("no data available (do not use --chunk)\n");
+
+      run_dsa_sign (data, datalen, key_string);
+    }
+  else if (!strcmp (mode_string, "dsa-verify"))
+    {
+      if (!key_string)
+        die ("option --key is required in this mode\n");
+      if (access (key_string, R_OK))
+        die ("option --key needs to specify an existing keyfile\n");
+      if (!data)
+        die ("no data available (do not use --chunk)\n");
+      if (!signature_string)
+        die ("option --signature is required in this mode\n");
+      if (access (signature_string, R_OK))
+        die ("option --signature needs to specify an existing file\n");
+
+      run_dsa_verify (data, datalen, key_string, signature_string);
+    }
+  else if (!strcmp (mode_string, "ecdsa-gen-key"))
+    {
+      if (!curve_string)
+        die ("option --curve containing name of the specified curve is required in this mode\n");
+      run_ecdsa_gen_key (curve_string);
+    }
+  else if (!strcmp (mode_string, "ecdsa-sign"))
+    {
+      int algo;
+
+      if (!key_string)
+        die ("option --key is required in this mode\n");
+      if (access (key_string, R_OK))
+        die ("option --key needs to specify an existing keyfile\n");
+      if (!algo_string)
+        die ("use --algo to specify the digest algorithm\n");
+      algo = gcry_md_map_name (algo_string);
+      if (!algo)
+        die ("digest algorithm `%s' is not supported\n", algo_string);
+
+      if (!data)
+        die ("no data available (do not use --chunk)\n");
+
+      run_ecdsa_sign (data, datalen, key_string, algo);
+    }
+  else if (!strcmp (mode_string, "ecdsa-verify"))
+    {
+      int algo;
+
+      if (!key_string)
+        die ("option --key is required in this mode\n");
+      if (access (key_string, R_OK))
+        die ("option --key needs to specify an existing keyfile\n");
+      if (!algo_string)
+        die ("use --algo to specify the digest algorithm\n");
+      algo = gcry_md_map_name (algo_string);
+      if (!algo)
+        die ("digest algorithm `%s' is not supported\n", algo_string);
+      if (!data)
+        die ("no data available (do not use --chunk)\n");
+      if (!signature_string)
+        die ("option --signature is required in this mode\n");
+      if (access (signature_string, R_OK))
+        die ("option --signature needs to specify an existing file\n");
+
+      run_ecdsa_verify (data, datalen, key_string, algo, signature_string);
     }
   else
     usage (0);
@@ -1455,4 +2863,3 @@ main (int argc, char **argv)
 
   return 0;
 }
-