summary refs log tree commit diff stats
path: root/libotr/libgcrypt-1.8.7/tests/fipsdrv.c
diff options
context:
space:
mode:
Diffstat (limited to 'libotr/libgcrypt-1.8.7/tests/fipsdrv.c')
-rw-r--r--libotr/libgcrypt-1.8.7/tests/fipsdrv.c2865
1 files changed, 2865 insertions, 0 deletions
diff --git a/libotr/libgcrypt-1.8.7/tests/fipsdrv.c b/libotr/libgcrypt-1.8.7/tests/fipsdrv.c
new file mode 100644
index 0000000..f9d9c45
--- /dev/null
+++ b/libotr/libgcrypt-1.8.7/tests/fipsdrv.c
@@ -0,0 +1,2865 @@
+/* fipsdrv.c  -  A driver to help with FIPS CAVS tests.
+   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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <ctype.h>
+#ifdef HAVE_W32_SYSTEM
+# include <fcntl.h> /* We need setmode().  */
+#else
+# include <signal.h>
+#endif
+#include <assert.h>
+#include <unistd.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"
+#include "t-common.h"
+
+
+/* Binary input flag.  */
+static int binary_input;
+
+/* Binary output flag.  */
+static int binary_output;
+
+/* Base64 output flag.  */
+static int base64_output;
+
+/* 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
+{
+  UNIVERSAL = 0,
+  APPLICATION = 1,
+  ASNCONTEXT = 2,
+  PRIVATE = 3
+};
+
+
+/* ASN.1 tags.  */
+enum
+{
+  TAG_NONE = 0,
+  TAG_BOOLEAN = 1,
+  TAG_INTEGER = 2,
+  TAG_BIT_STRING = 3,
+  TAG_OCTET_STRING = 4,
+  TAG_NULL = 5,
+  TAG_OBJECT_ID = 6,
+  TAG_OBJECT_DESCRIPTOR = 7,
+  TAG_EXTERNAL = 8,
+  TAG_REAL = 9,
+  TAG_ENUMERATED = 10,
+  TAG_EMBEDDED_PDV = 11,
+  TAG_UTF8_STRING = 12,
+  TAG_REALTIVE_OID = 13,
+  TAG_SEQUENCE = 16,
+  TAG_SET = 17,
+  TAG_NUMERIC_STRING = 18,
+  TAG_PRINTABLE_STRING = 19,
+  TAG_TELETEX_STRING = 20,
+  TAG_VIDEOTEX_STRING = 21,
+  TAG_IA5_STRING = 22,
+  TAG_UTC_TIME = 23,
+  TAG_GENERALIZED_TIME = 24,
+  TAG_GRAPHIC_STRING = 25,
+  TAG_VISIBLE_STRING = 26,
+  TAG_GENERAL_STRING = 27,
+  TAG_UNIVERSAL_STRING = 28,
+  TAG_CHARACTER_STRING = 29,
+  TAG_BMP_STRING = 30
+};
+
+/* ASN.1 Parser object.  */
+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.  */
+};
+
+
+static void
+showhex (const char *prefix, const void *buffer, size_t length)
+{
+  const unsigned char *p = buffer;
+
+  if (prefix)
+    fprintf (stderr, PGM ": %s: ", prefix);
+  while (length-- )
+    fprintf (stderr, "%02X", *p++);
+  if (prefix)
+    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
+   LENGTH bytes.  The function checks that the STRING will convert
+   exactly to LENGTH bytes. The string is delimited by either end of
+   string or a white space character.  The function returns -1 on
+   error or the length of the parsed string.  */
+static int
+hex2bin (const char *string, void *buffer, size_t length)
+{
+  int i;
+  const char *s = string;
+
+  for (i=0; i < length; )
+    {
+      if (!hexdigitp (s) || !hexdigitp (s+1))
+        return -1;           /* Invalid hex digits. */
+      ((unsigned char*)buffer)[i++] = xtoi_2 (s);
+      s += 2;
+    }
+  if (*s && (!my_isascii (*s) || !isspace (*s)) )
+    return -1;             /* Not followed by Nul or white space.  */
+  if (i != length)
+    return -1;             /* Not of expected length.  */
+  if (*s)
+    s++; /* Skip the delimiter. */
+  return s - string;
+}
+
+
+/* Convert STRING consisting of hex characters into its binary
+   representation and return it as an allocated buffer. The valid
+   length of the buffer is returned at R_LENGTH.  The string is
+   delimited by end of string.  The function returns NULL on
+   error.  */
+static void *
+hex2buffer (const char *string, size_t *r_length)
+{
+  const char *s;
+  unsigned char *buffer;
+  size_t length;
+
+  buffer = gcry_xmalloc (strlen(string)/2+1);
+  length = 0;
+  for (s=string; *s; s +=2 )
+    {
+      if (!hexdigitp (s) || !hexdigitp (s+1))
+        return NULL;           /* Invalid hex digits. */
+      ((unsigned char*)buffer)[length++] = xtoi_2 (s);
+    }
+  *r_length = 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
+   be hex encoded and the decoded content is returned. */
+static void *
+read_file (FILE *fp, int decode, size_t *r_length)
+{
+  char *buffer;
+  size_t buflen;
+  size_t nread, bufsize = 0;
+
+  *r_length = 0;
+#define NCHUNK 8192
+#ifdef HAVE_DOSISH_SYSTEM
+  setmode (fileno(fp), O_BINARY);
+#endif
+  buffer = NULL;
+  buflen = 0;
+  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))
+        {
+          gcry_free (buffer);
+          return NULL;
+        }
+      buflen += nread;
+    }
+  while (nread == NCHUNK);
+#undef NCHUNK
+  if (decode)
+    {
+      const char *s;
+      char *p;
+
+      for (s=buffer,p=buffer,nread=0; nread+1 < buflen; s += 2, nread +=2 )
+        {
+          if (!hexdigitp (s) || !hexdigitp (s+1))
+            {
+              gcry_free (buffer);
+              return NULL;  /* Invalid hex digits. */
+            }
+          *(unsigned char*)p++ = xtoi_2 (s);
+        }
+      if (nread != buflen)
+        {
+          gcry_free (buffer);
+          return NULL;  /* Odd number of hex digits. */
+        }
+      buflen = p - buffer;
+    }
+
+  *r_length = buflen;
+  return buffer;
+}
+
+/* Do in-place decoding of base-64 data of LENGTH in BUFFER.  Returns
+   the new length of the buffer.  Dies on error.  */
+static size_t
+base64_decode (char *buffer, size_t length)
+{
+  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,
+      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
+      0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
+      0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+      0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
+      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
+    };
+
+  int idx = 0;
+  unsigned char val = 0;
+  int c = 0;
+  char *d, *s;
+  int lfseen = 1;
+
+  /* Find BEGIN line.  */
+  for (s=buffer; length; length--, s++)
+    {
+      if (lfseen && *s == '-' && length > 11 && !memcmp (s, "-----BEGIN ", 11))
+        {
+          for (; length && *s != '\n'; length--, s++)
+            ;
+          break;
+        }
+      lfseen = (*s == '\n');
+    }
+
+  /* Decode until pad character or END line.  */
+  for (d=buffer; length; length--, s++)
+    {
+      if (lfseen && *s == '-' && length > 9 && !memcmp (s, "-----END ", 9))
+        break;
+      if ((lfseen = (*s == '\n')) || *s == ' ' || *s == '\r' || *s == '\t')
+        continue;
+      if (*s == '=')
+        {
+          /* Pad character: stop */
+          if (idx == 1)
+            *d++ = val;
+          break;
+        }
+
+      if ( (*s & 0x80) || (c = asctobin[*(unsigned char *)s]) == 0xff)
+        die ("invalid base64 character %02X at pos %d detected\n",
+             *(unsigned char*)s, (int)(s-buffer));
+
+      switch (idx)
+        {
+        case 0:
+          val = c << 2;
+          break;
+        case 1:
+          val |= (c>>4)&3;
+          *d++ = val;
+          val = (c<<4)&0xf0;
+          break;
+        case 2:
+          val |= (c>>2)&15;
+          *d++ = val;
+          val = (c<<6)&0xc0;
+          break;
+        case 3:
+          val |= c&0x3f;
+          *d++ = val;
+          break;
+        }
+      idx = (idx+1) % 4;
+    }
+
+  return d - buffer;
+}
+
+
+/* Parse the buffer at the address BUFFER which consists of the number
+   of octets as stored at BUFLEN.  Return the tag and the length part
+   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
+parse_tag (unsigned char const **buffer, size_t *buflen, struct tag_info *ti)
+{
+  int c;
+  unsigned long tag;
+  const unsigned char *buf = *buffer;
+  size_t length = *buflen;
+
+  ti->length = 0;
+  ti->ndef = 0;
+  ti->nhdr = 0;
+
+  /* Get the tag */
+  if (!length)
+    return -1; /* Premature EOF.  */
+  c = *buf++; length--;
+  ti->nhdr++;
+
+  ti->class = (c & 0xc0) >> 6;
+  ti->cons  = !!(c & 0x20);
+  tag       = (c & 0x1f);
+
+  if (tag == 0x1f)
+    {
+      tag = 0;
+      do
+        {
+          tag <<= 7;
+          if (!length)
+            return -1; /* Premature EOF.  */
+          c = *buf++; length--;
+          ti->nhdr++;
+          tag |= (c & 0x7f);
+        }
+      while ( (c & 0x80) );
+    }
+  ti->tag = tag;
+
+  /* Get the length */
+  if (!length)
+    return -1; /* Premature EOF. */
+  c = *buf++; length--;
+  ti->nhdr++;
+
+  if ( !(c & 0x80) )
+    ti->length = c;
+  else if (c == 0x80)
+    ti->ndef = 1;
+  else if (c == 0xff)
+    return -1; /* Forbidden length value.  */
+  else
+    {
+      unsigned long len = 0;
+      int count = c & 0x7f;
+
+      for (; count; count--)
+        {
+          len <<= 8;
+          if (!length)
+            return -1; /* Premature EOF.  */
+          c = *buf++; length--;
+          ti->nhdr++;
+          len |= (c & 0xff);
+        }
+      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;
+}
+
+
+/* Read the file FNAME assuming it is a PEM encoded private key file
+   and return an S-expression.  With SHOW set, the key parameters are
+   printed.  */
+static gcry_sexp_t
+read_private_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[8];
+  int n_keyparms = 8;
+  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_INTEGER || ti.class || ti.cons || ti.ndef)
+    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;
+
+  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 < 8? "nedpq12u"[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);
+
+  /* Convert from OpenSSL parameter ordering to the OpenPGP order. */
+  /* 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]);
+      gcry_mpi_invm (keyparms[7], keyparms[3], keyparms[4]);
+    }
+
+  /* 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)))",
+                         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 < 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;
+
+ bad_asn1:
+  die ("invalid ASN.1 structure in `%s'\n", fname);
+  return NULL; /*NOTREACHED*/
+}
+
+
+
+/* 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)
+{
+  int writerr = 0;
+
+  if (base64_output)
+    {
+      static const unsigned char bintoasc[64+1] =
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+        "abcdefghijklmnopqrstuvwxyz"
+        "0123456789+/";
+      const unsigned char *p;
+      unsigned char inbuf[4];
+      char outbuf[4];
+      int idx, quads;
+
+      idx = quads = 0;
+      for (p = buffer; length; p++, length--)
+        {
+          inbuf[idx++] = *p;
+          if (idx > 2)
+            {
+              outbuf[0] = bintoasc[(*inbuf>>2)&077];
+              outbuf[1] = bintoasc[(((*inbuf<<4)&060)
+                                    |((inbuf[1] >> 4)&017))&077];
+              outbuf[2] = bintoasc[(((inbuf[1]<<2)&074)
+                                    |((inbuf[2]>>6)&03))&077];
+              outbuf[3] = bintoasc[inbuf[2]&077];
+              if (fwrite (outbuf, 4, 1, stdout) != 1)
+                writerr = 1;
+              idx = 0;
+              if (++quads >= (64/4))
+                {
+                  if (fwrite ("\n", 1, 1, stdout) != 1)
+                    writerr = 1;
+                  quads = 0;
+                }
+            }
+        }
+      if (idx)
+        {
+          outbuf[0] = bintoasc[(*inbuf>>2)&077];
+          if (idx == 1)
+            {
+              outbuf[1] = bintoasc[((*inbuf<<4)&060)&077];
+              outbuf[2] = outbuf[3] = '=';
+            }
+          else
+            {
+              outbuf[1] = bintoasc[(((*inbuf<<4)&060)
+                                    |((inbuf[1]>>4)&017))&077];
+              outbuf[2] = bintoasc[((inbuf[1]<<2)&074)&077];
+              outbuf[3] = '=';
+            }
+          if (fwrite (outbuf, 4, 1, stdout) != 1)
+            writerr = 1;
+          quads++;
+        }
+      if (quads && fwrite ("\n", 1, 1, stdout) != 1)
+        writerr = 1;
+    }
+  else if (binary_output)
+    {
+      if (fwrite (buffer, length, 1, stdout) != 1)
+        writerr++;
+    }
+  else
+    {
+      const unsigned char *p = buffer;
+
+      if (verbose > 1)
+        showhex ("sent line", buffer, length);
+      while (length-- && !ferror (stdout) )
+        printf ("%02X", *p++);
+      if (ferror (stdout))
+        writerr++;
+    }
+  if (!writerr && fflush (stdout) == EOF)
+    writerr++;
+  if (writerr)
+    {
+#ifndef HAVE_W32_SYSTEM
+      if (loop_mode && errno == EPIPE)
+        loop_mode = 0;
+      else
+#endif
+        die ("writing output failed: %s\n", strerror (errno));
+    }
+}
+
+
+/* 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,
+                    unsigned int flags,
+                    const void *key, size_t keylen,
+                    const void *seed, size_t seedlen,
+                    const void *dt, size_t dtlen)
+{
+  return gcry_control (PRIV_CTL_INIT_EXTRNG_TEST,
+                       r_context, flags,
+                       key, keylen,
+                       seed, seedlen,
+                       dt, dtlen);
+}
+
+static gcry_error_t
+run_external_rng_test (void *context, void *buffer, size_t buflen)
+{
+  return gcry_control (PRIV_CTL_RUN_EXTRNG_TEST, context, buffer, buflen);
+}
+
+static void
+deinit_external_rng_test (void *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
+map_openssl_cipher_name (const char *name, int *r_mode)
+{
+  static struct {
+    const char *name;
+    int algo;
+    int mode;
+  } table[] =
+    {
+      { "bf-cbc",       GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC },
+      { "bf",           GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC },
+      { "bf-cfb",       GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CFB },
+      { "bf-ecb",       GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_ECB },
+      { "bf-ofb",       GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_OFB },
+
+      { "cast-cbc",     GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC },
+      { "cast",         GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC },
+      { "cast5-cbc",    GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC },
+      { "cast5-cfb",    GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CFB },
+      { "cast5-ecb",    GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_ECB },
+      { "cast5-ofb",    GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_OFB },
+
+      { "des-cbc",      GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC },
+      { "des",          GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC },
+      { "des-cfb",      GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CFB },
+      { "des-ofb",      GCRY_CIPHER_DES, GCRY_CIPHER_MODE_OFB },
+      { "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-cfb", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CFB },
+      { "des-ede3-ofb", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_OFB },
+
+      { "rc4",          GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM },
+
+      { "aes-128-cbc",  GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC },
+      { "aes-128",      GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC },
+      { "aes-128-cfb",  GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CFB },
+      { "aes-128-ecb",  GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB },
+      { "aes-128-ofb",  GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_OFB },
+
+      { "aes-192-cbc",  GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC },
+      { "aes-192",      GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC },
+      { "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 },
+      { "aes-256-ecb",  GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_ECB },
+      { "aes-256-ofb",  GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB },
+
+      { NULL, 0 , 0 }
+    };
+  int idx;
+
+  for (idx=0; table[idx].name; idx++)
+    if (!strcmp (name, table[idx].name))
+      {
+        *r_mode = table[idx].mode;
+        return table[idx].algo;
+      }
+  *r_mode = 0;
+  return 0;
+}
+
+
+
+/* Run an encrypt or decryption operations.  If DATA is NULL the
+   function reads its input in chunks of size DATALEN from fp and
+   processes it and writes it out until EOF.  */
+static void
+run_encrypt_decrypt (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, FILE *fp)
+{
+  gpg_error_t err;
+  gcry_cipher_hd_t hd;
+  void *outbuf;
+  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",
+         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));
+
+  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 < blocklen? blocklen:outbuflen);
+
+  do
+    {
+      if (inbuf)
+        {
+          int nread = fread (inbuf, 1, datalen, fp);
+          if (nread < (int)datalen && ferror (fp))
+            die ("error reading input\n");
+          data = inbuf;
+          inbuflen = nread;
+        }
+      else
+        inbuflen = datalen;
+
+      if (encrypt_mode)
+        err = gcry_cipher_encrypt (hd, outbuf, outbuflen, data, inbuflen);
+      else
+        err = gcry_cipher_decrypt (hd, outbuf, outbuflen, data, inbuflen);
+      if (err)
+        die ("gcry_cipher_%scrypt failed: %s\n",
+             encrypt_mode? "en":"de", gpg_strerror (err));
+
+      print_buffer (outbuf, outbuflen);
+    }
+  while (inbuf);
+
+  gcry_cipher_close (hd);
+  gcry_free (outbuf);
+  gcry_free (inbuf);
+}
+
+
+static void
+get_current_iv (gcry_cipher_hd_t hd, void *buffer, size_t buflen)
+{
+  unsigned char tmp[17];
+
+  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);
+}
+
+/* Run the inner loop of the CAVS monte carlo test.  */
+static void
+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_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_cipher_open (&hd, cipher_algo, cipher_mode, 0);
+  if (err)
+    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);
+  if (!blocklen || blocklen > sizeof output)
+    die ("invalid block length %d\n", (int)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));
+
+  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);
+}
+
+
+
+/* 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);
+}
+
+
+/* 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);
+}
+
+
+
+/* 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);
+}
+
+
+
+static size_t
+compute_tag_length (size_t n)
+{
+  int needed = 0;
+
+  if (n < 128)
+    needed += 2; /* Tag and one length byte.  */
+  else if (n < 256)
+    needed += 3; /* Tag, number of length bytes, 1 length byte.  */
+  else if (n < 65536)
+    needed += 4; /* Tag, number of length bytes, 2 length bytes.  */
+  else
+    die ("DER object too long to encode\n");
+
+  return needed;
+}
+
+static unsigned char *
+store_tag_length (unsigned char *p, int tag, size_t n)
+{
+  if (tag == TAG_SEQUENCE)
+    tag |= 0x20; /* constructed */
+
+  *p++ = tag;
+  if (n < 128)
+    *p++ = n;
+  else if (n < 256)
+    {
+      *p++ = 0x81;
+      *p++ = n;
+    }
+  else if (n < 65536)
+    {
+      *p++ = 0x82;
+      *p++ = n >> 8;
+      *p++ = n;
+    }
+
+  return p;
+}
+
+
+/* Generate an RSA key of size KEYSIZE using the public exponent
+   PUBEXP and print it to stdout in the OpenSSL format.  The format
+   is:
+
+       SEQUENCE {
+         INTEGER (0)  -- Unknown constant.
+         INTEGER      -- n
+         INTEGER      -- e
+         INTEGER      -- d
+         INTEGER      -- p
+         INTEGER      -- q      (with p < q)
+         INTEGER      -- dmp1 = d mod (p-1)
+         INTEGER      -- dmq1 = d mod (q-1)
+         INTEGER      -- u    = p^{-1} mod q
+       }
+
+*/
+static void
+run_rsa_gen (int keysize, int pubexp)
+{
+  gpg_error_t err;
+  gcry_sexp_t keyspec, key, l1;
+  const char keyelems[] = "nedpq..u";
+  gcry_mpi_t keyparms[8];
+  size_t     keyparmslen[8];
+  int idx;
+  size_t derlen, needed, n;
+  unsigned char *derbuf, *der;
+
+  err = gcry_sexp_build (&keyspec, NULL,
+                         "(genkey (rsa (nbits %d)(rsa-use-e %d)))",
+                         keysize, pubexp);
+  if (err)
+    die ("gcry_sexp_build failed for RSA key generation: %s\n",
+         gpg_strerror (err));
+
+  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);
+  if (!l1)
+    die ("private key not found in genkey result\n");
+  gcry_sexp_release (key);
+  key = l1;
+
+  l1 = gcry_sexp_find_token (key, "rsa", 0);
+  if (!l1)
+    die ("returned private key not formed as expected\n");
+  gcry_sexp_release (key);
+  key = l1;
+
+  /* Extract the parameters from the S-expression and store them in a
+     well defined order in KEYPARMS.  */
+  for (idx=0; idx < DIM(keyparms); idx++)
+    {
+      if (keyelems[idx] == '.')
+        {
+          keyparms[idx] = gcry_mpi_new (0);
+          continue;
+        }
+      l1 = gcry_sexp_find_token (key, keyelems+idx, 1);
+      if (!l1)
+        die ("no %c parameter in returned private key\n", keyelems[idx]);
+      keyparms[idx] = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+      if (!keyparms[idx])
+        die ("no value for %c parameter in returned private key\n",
+             keyelems[idx]);
+      gcry_sexp_release (l1);
+    }
+
+  gcry_sexp_release (key);
+
+  /* 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]);
+      gcry_mpi_invm (keyparms[7], keyparms[3], keyparms[4]);
+    }
+
+  /* Compute the additional parameters.  */
+  gcry_mpi_sub_ui (keyparms[5], keyparms[3], 1);
+  gcry_mpi_mod (keyparms[5], keyparms[2], keyparms[5]);
+  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);
+
+  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);
+}
+
+
+
+/* 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);
+}
+
+
+
+/* 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);
+}
+
+
+
+/* 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);
+}
+
+
+
+/* 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);
+}
+
+
+
+/* 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)
+
+{
+  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)
+    {
+      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);
+  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);
+}
+
+
+
+/* Sign DATA of length DATALEN using the key taken from the S-expression
+   encoded KEYFILE. */
+static void
+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;
+  char hash[128];
+  gcry_mpi_t tmpmpi;
+
+  s_key = read_sexp_from_file (keyfile);
+
+  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 ECDSA data input: %s\n",
+         gpg_strerror (err));
+
+  err = gcry_pk_sign (&s_sig, s_data, s_key);
+  if (err)
+    {
+      die ("gcry_pk_signed failed: %s\n", gpg_strerror (err));
+    }
+  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)
+    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);
+}
+
+
+
+/* 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)
+    {
+      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 DSA data input: %s\n",
+         gpg_strerror (err));
+
+  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);
+}
+
+
+
+static void
+usage (int show_help)
+{
+  if (!show_help)
+    {
+      fputs ("usage: " PGM
+             " [OPTION] [FILE] (try --help for more information)\n", stderr);
+      exit (2);
+    }
+  fputs
+    ("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,\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"
+     "  --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);
+}
+
+int
+main (int argc, char **argv)
+{
+  int last_argc = -1;
+  gpg_error_t err;
+  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)
+    { argc--; argv++; }
+
+  while (argc && last_argc != argc )
+    {
+      last_argc = argc;
+      if (!strcmp (*argv, "--"))
+        {
+          argc--; argv++;
+          break;
+        }
+      else if (!strcmp (*argv, "--help"))
+        {
+          usage (1);
+        }
+      else if (!strcmp (*argv, "--version"))
+        {
+          fputs (PGM " (Libgcrypt) " PACKAGE_VERSION "\n", stdout);
+          exit (0);
+        }
+      else if (!strcmp (*argv, "--verbose"))
+        {
+          verbose++;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--binary"))
+        {
+          binary_input = binary_output = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--no-fips"))
+        {
+          no_fips++;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--loop"))
+        {
+          loop_mode = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--progress"))
+        {
+          progress = 1;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--key"))
+        {
+          argc--; argv++;
+          if (!argc)
+            usage (0);
+          key_string = *argv;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--iv"))
+        {
+          argc--; argv++;
+          if (!argc)
+            usage (0);
+          iv_string = *argv;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--dt"))
+        {
+          argc--; argv++;
+          if (!argc)
+            usage (0);
+          dt_string = *argv;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--algo"))
+        {
+          argc--; argv++;
+          if (!argc)
+            usage (0);
+          algo_string = *argv;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--keysize"))
+        {
+          argc--; argv++;
+          if (!argc)
+            usage (0);
+          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++;
+          if (!argc)
+            usage (0);
+          chunksize = atoi (*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");
+      if (!input)
+        die ("can't open `%s': %s\n", argv[1], strerror (errno));
+    }
+  else
+    input = stdin;
+
+#ifndef HAVE_W32_SYSTEM
+  if (loop_mode)
+    signal (SIGPIPE, SIG_IGN);
+#endif
+
+  if (verbose)
+    fprintf (stderr, PGM ": started (mode=%s)\n", mode_string);
+
+  xgcry_control (GCRYCTL_SET_VERBOSITY, (int)verbose);
+  if (!no_fips)
+    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)
+    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-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",
+                 (unsigned int)datalen);
+    }
+  else
+    {
+      data = NULL;
+      datalen = 0;
+    }
+
+
+  if (!strcmp (mode_string, "encrypt") || !strcmp (mode_string, "decrypt"))
+    {
+      int cipher_algo, cipher_mode;
+      void  *iv_buffer = NULL;
+      void *key_buffer = NULL;
+      size_t iv_buflen,  key_buflen;
+
+      if (!algo_string)
+        die ("option --algo is required in this mode\n");
+      cipher_algo = map_openssl_cipher_name (algo_string, &cipher_mode);
+      if (!cipher_algo)
+        die ("cipher algorithm `%s' is not supported\n", algo_string);
+      if (mct_server)
+        {
+          int iterations;
+
+          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);
+    }
+  else if (!strcmp (mode_string, "digest"))
+    {
+      int algo;
+
+      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");
+
+      run_digest (algo, data, datalen);
+    }
+  else if (!strcmp (mode_string, "random"))
+    {
+      void *context;
+      unsigned char key[16];
+      unsigned char seed[16];
+      unsigned char dt[16];
+      unsigned char buffer[16];
+      size_t count = 0;
+
+      if (!key_string || hex2bin (key_string, key, 16) < 0 )
+        die ("value for --key are not 32 hex digits\n");
+      if (!iv_string || hex2bin (iv_string, seed, 16) < 0 )
+        die ("value for --iv are not 32 hex digits\n");
+      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
+         returns all generated data.  */
+      err = init_external_rng_test (&context, 1, key, 16, seed, 16, dt, 16);
+      if (err)
+        die ("init external RNG test failed: %s\n", gpg_strerror (err));
+
+      do
+        {
+          err = run_external_rng_test (context, buffer, sizeof buffer);
+          if (err)
+            die ("running external RNG test failed: %s\n", gpg_strerror (err));
+          print_buffer (buffer, sizeof buffer);
+          if (progress)
+            {
+              if (!(++count % 1000))
+                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));
+
+      deinit_external_rng_test (context);
+    }
+  else if (!strcmp (mode_string, "hmac-sha"))
+    {
+      int algo;
+      void  *key_buffer;
+      size_t key_buflen;
+
+      if (!data)
+        die ("no data available (do not use --chunk)\n");
+      if (!algo_string)
+        die ("option --algo is required in this mode\n");
+      switch (atoi (algo_string))
+        {
+        case 1:   algo = GCRY_MD_SHA1; break;
+        case 224: algo = GCRY_MD_SHA224; break;
+        case 256: algo = GCRY_MD_SHA256; break;
+        case 384: algo = GCRY_MD_SHA384; break;
+        case 512: algo = GCRY_MD_SHA512; break;
+        default:  algo = 0; break;
+        }
+      if (!algo)
+        die ("no digest algorithm found for hmac type `%s'\n", algo_string);
+      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_hmac (algo, key_buffer, key_buflen, data, datalen);
+
+      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;
+
+      keysize = keysize_string? atoi (keysize_string) : 0;
+      if (keysize < 128 || keysize > 16384)
+        die ("invalid keysize specified; needs to be 128 .. 16384\n");
+      run_rsa_gen (keysize, 65537);
+    }
+  else if (!strcmp (mode_string, "rsa-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 ("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");
+
+      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);
+
+  gcry_free (data);
+
+  /* Because Libgcrypt does not enforce FIPS mode in all cases we let
+     the process die if Libgcrypt is not anymore in FIPS mode after
+     the actual operation.  */
+  if (!no_fips && !gcry_fips_mode_active ())
+    die ("FIPS mode is not anymore active\n");
+
+  if (verbose)
+    fputs (PGM ": ready\n", stderr);
+
+  return 0;
+}