pubkey: Re-map all depreccated RSA algo numbers.
[libgcrypt.git] / cipher / dsa.c
index d11a7d0..1707d8c 100644 (file)
@@ -1,6 +1,7 @@
 /* dsa.c - DSA signature algorithm
  * Copyright (C) 1998, 2000, 2001, 2002, 2003,
  *               2006, 2008  Free Software Foundation, Inc.
+ * Copyright (C) 2013 g10 Code GmbH.
  *
  * This file is part of Libgcrypt.
  *
@@ -26,6 +27,8 @@
 #include "g10lib.h"
 #include "mpi.h"
 #include "cipher.h"
+#include "pubkey-internal.h"
+
 
 typedef struct
 {
@@ -46,6 +49,23 @@ typedef struct
 } DSA_secret_key;
 
 
+/* A structure used to hold domain parameters.  */
+typedef struct
+{
+  gcry_mpi_t p;            /* prime */
+  gcry_mpi_t q;            /* group order */
+  gcry_mpi_t g;            /* group generator */
+} dsa_domain_t;
+
+
+static const char *dsa_names[] =
+  {
+    "dsa",
+    "openpgp-dsa",
+    NULL,
+  };
+
+
 /* A sample 1024 bit DSA key used for the selftests.  */
 static const char sample_secret_key[] =
 "(private-key"
@@ -65,7 +85,7 @@ static const char sample_secret_key[] =
 "      42CAA7DC289F0C5A9D155F02D3D551DB741A81695B74D4C8F477F9C7838EB0FB#)"
 "  (x #11D54E4ADBD3034160F2CED4B7CD292A4EBF3EC0#)))";
 /* A sample 1024 bit DSA key used for the selftests (public only).  */
-static const char sample_public_key[] = 
+static const char sample_public_key[] =
 "(public-key"
 " (dsa"
 "  (p #00AD7C0025BA1A15F775F3F2D673718391D00456978D347B33D7B49E7F32EDAB"
@@ -85,18 +105,20 @@ static const char sample_public_key[] =
 
 
 \f
-static gcry_mpi_t gen_k (gcry_mpi_t q);
 static int test_keys (DSA_secret_key *sk, unsigned int qbits);
 static int check_secret_key (DSA_secret_key *sk);
 static gpg_err_code_t generate (DSA_secret_key *sk,
                                 unsigned int nbits,
                                 unsigned int qbits,
                                 int transient_key,
+                                dsa_domain_t *domain,
                                 gcry_mpi_t **ret_factors);
-static void sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input,
-                  DSA_secret_key *skey);
-static int verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input,
+static gpg_err_code_t sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input,
+                            DSA_secret_key *skey, int flags, int hashalgo);
+static gpg_err_code_t verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input,
                    DSA_public_key *pkey);
+static unsigned int dsa_get_nbits (gcry_sexp_t parms);
+
 
 static void (*progress_cb) (void *,const char *, int, int, int );
 static void *progress_cb_data;
@@ -120,78 +142,15 @@ progress (int c)
 }
 
 
-/*
- * Generate a random secret exponent k less than q.
- */
-static gcry_mpi_t
-gen_k( gcry_mpi_t q )
-{
-  gcry_mpi_t k = mpi_alloc_secure( mpi_get_nlimbs(q) );
-  unsigned int nbits = mpi_get_nbits(q);
-  unsigned int nbytes = (nbits+7)/8;
-  char *rndbuf = NULL;
-
-  if ( DBG_CIPHER )
-    log_debug("choosing a random k ");
-  for (;;) 
-    {
-      if( DBG_CIPHER )
-        progress('.');
-
-      if ( !rndbuf || nbits < 32 ) 
-        {
-          gcry_free(rndbuf);
-          rndbuf = gcry_random_bytes_secure( (nbits+7)/8, GCRY_STRONG_RANDOM );
-       }
-      else
-        { /* Change only some of the higher bits.  We could improve
-            this by directly requesting more memory at the first call
-            to get_random_bytes() and use this the here maybe it is
-            easier to do this directly in random.c. */
-          char *pp = gcry_random_bytes_secure( 4, GCRY_STRONG_RANDOM );
-          memcpy( rndbuf,pp, 4 );
-          gcry_free(pp);
-       }
-      _gcry_mpi_set_buffer( k, rndbuf, nbytes, 0 );
-      if ( mpi_test_bit( k, nbits-1 ) )
-        mpi_set_highbit( k, nbits-1 );
-      else
-        {
-          mpi_set_highbit( k, nbits-1 );
-          mpi_clear_bit( k, nbits-1 );
-       }
-
-      if( !(mpi_cmp( k, q ) < 0) ) /* check: k < q */
-        {      
-          if( DBG_CIPHER )
-            progress('+');
-          continue; /* no  */
-        }
-      if( !(mpi_cmp_ui( k, 0 ) > 0) )  /* check: k > 0 */
-        {
-          if( DBG_CIPHER )
-            progress('-');
-          continue; /* no */
-        }
-      break;   /* okay */
-    }
-  gcry_free(rndbuf);
-  if( DBG_CIPHER )
-    progress('\n');
-  
-  return k;
-}
-
-
 /* Check that a freshly generated key actually works.  Returns 0 on success. */
 static int
 test_keys (DSA_secret_key *sk, unsigned int qbits)
 {
   int result = -1;  /* Default to failure.  */
   DSA_public_key pk;
-  gcry_mpi_t data  = gcry_mpi_new (qbits);
-  gcry_mpi_t sig_a = gcry_mpi_new (qbits);
-  gcry_mpi_t sig_b = gcry_mpi_new (qbits);
+  gcry_mpi_t data  = mpi_new (qbits);
+  gcry_mpi_t sig_a = mpi_new (qbits);
+  gcry_mpi_t sig_b = mpi_new (qbits);
 
   /* Put the relevant parameters into a public key structure.  */
   pk.p = sk->p;
@@ -200,26 +159,26 @@ test_keys (DSA_secret_key *sk, unsigned int qbits)
   pk.y = sk->y;
 
   /* Create a random plaintext.  */
-  gcry_mpi_randomize (data, qbits, GCRY_WEAK_RANDOM);
+  _gcry_mpi_randomize (data, qbits, GCRY_WEAK_RANDOM);
 
   /* Sign DATA using the secret key.  */
-  sign (sig_a, sig_b, data, sk);
+  sign (sig_a, sig_b, data, sk, 0, 0);
 
   /* Verify the signature using the public key.  */
-  if ( !verify (sig_a, sig_b, data, &pk) )
+  if ( verify (sig_a, sig_b, data, &pk) )
     goto leave; /* Signature does not match.  */
 
   /* Modify the data and check that the signing fails.  */
-  gcry_mpi_add_ui (data, data, 1);
-  if ( verify (sig_a, sig_b, data, &pk) )
+  mpi_add_ui (data, data, 1);
+  if ( !verify (sig_a, sig_b, data, &pk) )
     goto leave; /* Signature matches but should not.  */
 
   result = 0; /* The test succeeded.  */
 
  leave:
-  gcry_mpi_release (sig_b);
-  gcry_mpi_release (sig_a);
-  gcry_mpi_release (data);
+  _gcry_mpi_release (sig_b);
+  _gcry_mpi_release (sig_a);
+  _gcry_mpi_release (data);
   return result;
 }
 
@@ -235,7 +194,7 @@ test_keys (DSA_secret_key *sk, unsigned int qbits)
  */
 static gpg_err_code_t
 generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
-          int transient_key,  gcry_mpi_t **ret_factors )
+          int transient_key, dsa_domain_t *domain, gcry_mpi_t **ret_factors )
 {
   gcry_mpi_t p;    /* the prime */
   gcry_mpi_t q;    /* the 160 bit prime factor */
@@ -274,66 +233,85 @@ generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
         return GPG_ERR_INV_VALUE;
     }
 
-  /* Generate the primes.  */
-  p = _gcry_generate_elg_prime( 1, nbits, qbits, NULL, ret_factors );
-  /* get q out of factors */
-  q = mpi_copy((*ret_factors)[0]);
-  if( mpi_get_nbits(q) != qbits )
-    BUG();
-
-  /* Find a generator g (h and e are helpers).
-     e = (p-1)/q */
-  e = mpi_alloc( mpi_get_nlimbs(p) );
-  mpi_sub_ui( e, p, 1 );
-  mpi_fdiv_q( e, e, q );
-  g = mpi_alloc( mpi_get_nlimbs(p) );
-  h = mpi_alloc_set_ui( 1 ); /* we start with 2 */
-  do
+  if (domain->p && domain->q && domain->g)
+    {
+      /* Domain parameters are given; use them.  */
+      p = mpi_copy (domain->p);
+      q = mpi_copy (domain->q);
+      g = mpi_copy (domain->g);
+      gcry_assert (mpi_get_nbits (p) == nbits);
+      gcry_assert (mpi_get_nbits (q) == qbits);
+      h = mpi_alloc (0);
+      e = NULL;
+    }
+  else
     {
-      mpi_add_ui( h, h, 1 );
-      /* g = h^e mod p */
-      gcry_mpi_powm( g, h, e, p );
-    } 
-  while( !mpi_cmp_ui( g, 1 ) );  /* continue until g != 1 */
+      /* Generate new domain parameters.  */
+      p = _gcry_generate_elg_prime (1, nbits, qbits, NULL, ret_factors);
+      /* Get q out of factors.  */
+      q = mpi_copy ((*ret_factors)[0]);
+      gcry_assert (mpi_get_nbits (q) == qbits);
+
+      /* Find a generator g (h and e are helpers).
+         e = (p-1)/q */
+      e = mpi_alloc (mpi_get_nlimbs (p));
+      mpi_sub_ui (e, p, 1);
+      mpi_fdiv_q (e, e, q);
+      g = mpi_alloc (mpi_get_nlimbs (p));
+      h = mpi_alloc_set_ui (1); /* (We start with 2.) */
+      do
+        {
+          mpi_add_ui (h, h, 1);
+          /* g = h^e mod p */
+          mpi_powm (g, h, e, p);
+        }
+      while (!mpi_cmp_ui (g, 1));  /* Continue until g != 1. */
+    }
 
-  /* Select a random number which has these properties:
+  /* Select a random number X with the property:
    *    0 < x < q-1
-   * This must be a very good random number because this
-   * is the secret part. */
-  /* The random quality depends on the transient_key flag.  */
+   *
+   * FIXME: Why do we use the requirement x < q-1 ? It should be
+   * sufficient to test for x < q.  FIPS-186-3 check x < q-1 but it
+   * does not check for 0 < x because it makes sure that Q is unsigned
+   * and finally adds one to the result so that 0 will never be
+   * returned.  We should replace the code below with _gcry_dsa_gen_k.
+   *
+   * This must be a very good random number because this is the secret
+   * part.  The random quality depends on the transient_key flag.  */
   random_level = transient_key ? GCRY_STRONG_RANDOM : GCRY_VERY_STRONG_RANDOM;
   if (DBG_CIPHER)
-    log_debug("choosing a random x%s", transient_key? " (transient-key)":"");
+    log_debug("choosing a random x%s\n", transient_key? " (transient-key)":"");
   gcry_assert( qbits >= 160 );
   x = mpi_alloc_secure( mpi_get_nlimbs(q) );
   mpi_sub_ui( h, q, 1 );  /* put q-1 into h */
   rndbuf = NULL;
-  do 
+  do
     {
       if( DBG_CIPHER )
         progress('.');
       if( !rndbuf )
-        rndbuf = gcry_random_bytes_secure ((qbits+7)/8, random_level);
-      else 
+        rndbuf = _gcry_random_bytes_secure ((qbits+7)/8, random_level);
+      else
         { /* Change only some of the higher bits (= 2 bytes)*/
-          char *r = gcry_random_bytes_secure (2, random_level);
+          char *r = _gcry_random_bytes_secure (2, random_level);
           memcpy(rndbuf, r, 2 );
-          gcry_free(r);
+          xfree(r);
         }
 
       _gcry_mpi_set_buffer( x, rndbuf, (qbits+7)/8, 0 );
       mpi_clear_highbit( x, qbits+1 );
-    } 
+    }
   while ( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, h )<0 ) );
-  gcry_free(rndbuf);
+  xfree(rndbuf);
   mpi_free( e );
   mpi_free( h );
 
   /* y = g^x mod p */
   y = mpi_alloc( mpi_get_nlimbs(p) );
-  gcry_mpi_powm( y, g, x, p );
+  mpi_powm (y, g, x, p);
 
-  if( DBG_CIPHER ) 
+  if( DBG_CIPHER )
     {
       progress('\n');
       log_mpidump("dsa  p", p );
@@ -353,11 +331,11 @@ generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
   /* Now we can test our keys (this should never fail!). */
   if ( test_keys (sk, qbits) )
     {
-      gcry_mpi_release (sk->p); sk->p = NULL;
-      gcry_mpi_release (sk->q); sk->q = NULL;
-      gcry_mpi_release (sk->g); sk->g = NULL;
-      gcry_mpi_release (sk->y); sk->y = NULL;
-      gcry_mpi_release (sk->x); sk->x = NULL;
+      _gcry_mpi_release (sk->p); sk->p = NULL;
+      _gcry_mpi_release (sk->q); sk->q = NULL;
+      _gcry_mpi_release (sk->g); sk->g = NULL;
+      _gcry_mpi_release (sk->y); sk->y = NULL;
+      _gcry_mpi_release (sk->x); sk->x = NULL;
       fips_signal_error ("self-test after key generation failed");
       return GPG_ERR_SELFTEST_FAILED;
     }
@@ -368,10 +346,13 @@ generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
 /* Generate a DSA key pair with a key of size NBITS using the
    algorithm given in FIPS-186-3.  If USE_FIPS186_2 is true,
    FIPS-186-2 is used and thus the length is restricted to 1024/160.
-   If DERIVEPARMS are not NULL the may contain a seed value. */
+   If DERIVEPARMS is not NULL it may contain a seed value.  If domain
+   parameters are specified in DOMAIN, DERIVEPARMS may not be given
+   and NBITS and QBITS must match the specified domain parameters.  */
 static gpg_err_code_t
 generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
                   gcry_sexp_t deriveparms, int use_fips186_2,
+                  dsa_domain_t *domain,
                   int *r_counter, void **r_seed, size_t *r_seedlen,
                   gcry_mpi_t *r_h)
 {
@@ -381,8 +362,8 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
     const void *seed;
     size_t seedlen;
   } initial_seed = { NULL, NULL, 0 };
-  gcry_mpi_t prime_q = NULL; 
-  gcry_mpi_t prime_p = NULL; 
+  gcry_mpi_t prime_q = NULL;
+  gcry_mpi_t prime_p = NULL;
   gcry_mpi_t value_g = NULL; /* The generator. */
   gcry_mpi_t value_y = NULL; /* g^x mod p */
   gcry_mpi_t value_x = NULL; /* The secret exponent. */
@@ -419,65 +400,82 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
   else
     return GPG_ERR_INV_VALUE;
 
-  /* Get an initial seed value.  */
-  if (deriveparms)
+  if (domain->p && domain->q && domain->g)
     {
-      initial_seed.sexp = gcry_sexp_find_token (deriveparms, "seed", 0);
-      if (initial_seed.sexp)
-        initial_seed.seed = gcry_sexp_nth_data (initial_seed.sexp, 1,
-                                                &initial_seed.seedlen);
+      /* Domain parameters are given; use them.  */
+      prime_p = mpi_copy (domain->p);
+      prime_q = mpi_copy (domain->q);
+      value_g = mpi_copy (domain->g);
+      gcry_assert (mpi_get_nbits (prime_p) == nbits);
+      gcry_assert (mpi_get_nbits (prime_q) == qbits);
+      gcry_assert (!deriveparms);
+      ec = 0;
     }
+  else
+    {
+      /* Generate new domain parameters.  */
 
-  /* Fixme: Enable 186-3 after it has been approved and after fixing
-     the generation function.  */
-/*   if (use_fips186_2) */
-  (void)use_fips186_2;
-    ec = _gcry_generate_fips186_2_prime (nbits, qbits, 
-                                         initial_seed.seed, 
-                                         initial_seed.seedlen,
-                                         &prime_q, &prime_p, 
-                                         r_counter,
-                                         r_seed, r_seedlen);
-/*   else */
-/*     ec = _gcry_generate_fips186_3_prime (nbits, qbits, NULL, 0, */
-/*                                          &prime_q, &prime_p, */
-/*                                          r_counter, */
-/*                                          r_seed, r_seedlen, NULL); */
-  gcry_sexp_release (initial_seed.sexp);
-  if (ec)
-    goto leave;
+      /* Get an initial seed value.  */
+      if (deriveparms)
+        {
+          initial_seed.sexp = sexp_find_token (deriveparms, "seed", 0);
+          if (initial_seed.sexp)
+            initial_seed.seed = sexp_nth_data (initial_seed.sexp, 1,
+                                                    &initial_seed.seedlen);
+        }
+
+      /* Fixme: Enable 186-3 after it has been approved and after fixing
+         the generation function.  */
+      /*   if (use_fips186_2) */
+      (void)use_fips186_2;
+      ec = _gcry_generate_fips186_2_prime (nbits, qbits,
+                                           initial_seed.seed,
+                                           initial_seed.seedlen,
+                                           &prime_q, &prime_p,
+                                           r_counter,
+                                           r_seed, r_seedlen);
+      /*   else */
+      /*     ec = _gcry_generate_fips186_3_prime (nbits, qbits, NULL, 0, */
+      /*                                          &prime_q, &prime_p, */
+      /*                                          r_counter, */
+      /*                                          r_seed, r_seedlen, NULL); */
+      sexp_release (initial_seed.sexp);
+      if (ec)
+        goto leave;
+
+      /* Find a generator g (h and e are helpers).
+         e = (p-1)/q */
+      value_e = mpi_alloc_like (prime_p);
+      mpi_sub_ui (value_e, prime_p, 1);
+      mpi_fdiv_q (value_e, value_e, prime_q );
+      value_g = mpi_alloc_like (prime_p);
+      value_h = mpi_alloc_set_ui (1);
+      do
+        {
+          mpi_add_ui (value_h, value_h, 1);
+          /* g = h^e mod p */
+          mpi_powm (value_g, value_h, value_e, prime_p);
+        }
+      while (!mpi_cmp_ui (value_g, 1));  /* Continue until g != 1.  */
+    }
 
-  /* Find a generator g (h and e are helpers).
-     e = (p-1)/q */
-  value_e = mpi_alloc_like (prime_p);
-  mpi_sub_ui (value_e, prime_p, 1);
-  mpi_fdiv_q (value_e, value_e, prime_q );
-  value_g = mpi_alloc_like (prime_p);
-  value_h = mpi_alloc_set_ui (1); 
-  do
-    {
-      mpi_add_ui (value_h, value_h, 1);
-      /* g = h^e mod p */
-      mpi_powm (value_g, value_h, value_e, prime_p);
-    } 
-  while (!mpi_cmp_ui (value_g, 1));  /* Continue until g != 1.  */
 
   /* Select a random number x with:  0 < x < q  */
-  value_x = gcry_mpi_snew (qbits);
-  do 
+  value_x = mpi_snew (qbits);
+  do
     {
       if( DBG_CIPHER )
         progress('.');
-      gcry_mpi_randomize (value_x, qbits, GCRY_VERY_STRONG_RANDOM);
+      _gcry_mpi_randomize (value_x, qbits, GCRY_VERY_STRONG_RANDOM);
       mpi_clear_highbit (value_x, qbits+1);
-    } 
+    }
   while (!(mpi_cmp_ui (value_x, 0) > 0 && mpi_cmp (value_x, prime_q) < 0));
 
   /* y = g^x mod p */
   value_y = mpi_alloc_like (prime_p);
-  gcry_mpi_powm (value_y, value_g, value_x, prime_p);
+  mpi_powm (value_y, value_g, value_x, prime_p);
 
-  if (DBG_CIPHER) 
+  if (DBG_CIPHER)
     {
       progress('\n');
       log_mpidump("dsa  p", prime_p );
@@ -497,22 +495,22 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
   *r_h = value_h; value_h = NULL;
 
  leave:
-  gcry_mpi_release (prime_p);
-  gcry_mpi_release (prime_q);
-  gcry_mpi_release (value_g);
-  gcry_mpi_release (value_y);
-  gcry_mpi_release (value_x);
-  gcry_mpi_release (value_h);
-  gcry_mpi_release (value_e);
+  _gcry_mpi_release (prime_p);
+  _gcry_mpi_release (prime_q);
+  _gcry_mpi_release (value_g);
+  _gcry_mpi_release (value_y);
+  _gcry_mpi_release (value_x);
+  _gcry_mpi_release (value_h);
+  _gcry_mpi_release (value_e);
 
   /* As a last step test this keys (this should never fail of course). */
   if (!ec && test_keys (sk, qbits) )
     {
-      gcry_mpi_release (sk->p); sk->p = NULL;
-      gcry_mpi_release (sk->q); sk->q = NULL;
-      gcry_mpi_release (sk->g); sk->g = NULL;
-      gcry_mpi_release (sk->y); sk->y = NULL;
-      gcry_mpi_release (sk->x); sk->x = NULL;
+      _gcry_mpi_release (sk->p); sk->p = NULL;
+      _gcry_mpi_release (sk->q); sk->q = NULL;
+      _gcry_mpi_release (sk->g); sk->g = NULL;
+      _gcry_mpi_release (sk->y); sk->y = NULL;
+      _gcry_mpi_release (sk->x); sk->x = NULL;
       fips_signal_error ("self-test after key generation failed");
       ec = GPG_ERR_SELFTEST_FAILED;
     }
@@ -520,9 +518,9 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
   if (ec)
     {
       *r_counter = 0;
-      gcry_free (*r_seed); *r_seed = NULL;
+      xfree (*r_seed); *r_seed = NULL;
       *r_seedlen = 0;
-      gcry_mpi_release (*r_h); *r_h = NULL;
+      _gcry_mpi_release (*r_h); *r_h = NULL;
     }
 
   return ec;
@@ -540,7 +538,7 @@ check_secret_key( DSA_secret_key *sk )
   int rc;
   gcry_mpi_t y = mpi_alloc( mpi_get_nlimbs(sk->y) );
 
-  gcry_mpi_powm( y, sk->g, sk->x, sk->p );
+  mpi_powm( y, sk->g, sk->x, sk->p );
   rc = !mpi_cmp( y, sk->y );
   mpi_free( y );
   return rc;
@@ -549,20 +547,63 @@ check_secret_key( DSA_secret_key *sk )
 
 
 /*
-   Make a DSA signature from HASH and put it into r and s.
+   Make a DSA signature from INPUT and put it into r and s.
+
+   INPUT may either be a plain MPI or an opaque MPI which is then
+   internally converted to a plain MPI.  FLAGS and HASHALGO may both
+   be 0 for standard operation mode.
+
+   The return value is 0 on success or an error code.  Note that for
+   backward compatibility the function will not return any error if
+   FLAGS and HASHALGO are both 0 and INPUT is a plain MPI.
  */
-static void
-sign(gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_secret_key *skey )
+static gpg_err_code_t
+sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_secret_key *skey,
+      int flags, int hashalgo)
 {
+  gpg_err_code_t rc;
+  gcry_mpi_t hash;
   gcry_mpi_t k;
   gcry_mpi_t kinv;
   gcry_mpi_t tmp;
+  const void *abuf;
+  unsigned int abits, qbits;
+  int extraloops = 0;
+
+  qbits = mpi_get_nbits (skey->q);
 
-  /* Select a random k with 0 < k < q */
-  k = gen_k( skey->q );
+  /* Convert the INPUT into an MPI.  */
+  rc = _gcry_dsa_normalize_hash (input, &hash, qbits);
+  if (rc)
+    return rc;
+
+ again:
+  /* Create the K value.  */
+  if ((flags & PUBKEY_FLAG_RFC6979) && hashalgo)
+    {
+      /* Use Pornin's method for deterministic DSA.  If this flag is
+         set, it is expected that HASH is an opaque MPI with the to be
+         signed hash.  That hash is also used as h1 from 3.2.a.  */
+      if (!mpi_is_opaque (input))
+        {
+          rc = GPG_ERR_CONFLICT;
+          goto leave;
+        }
+
+      abuf = mpi_get_opaque (input, &abits);
+      rc = _gcry_dsa_gen_rfc6979_k (&k, skey->q, skey->x,
+                                    abuf, (abits+7)/8, hashalgo, extraloops);
+      if (rc)
+        goto leave;
+    }
+  else
+    {
+      /* Select a random k with 0 < k < q */
+      k = _gcry_dsa_gen_k (skey->q, GCRY_STRONG_RANDOM);
+    }
 
   /* r = (a^k mod p) mod q */
-  gcry_mpi_powm( r, skey->g, k, skey->p );
+  mpi_powm( r, skey->g, k, skey->p );
   mpi_fdiv_r( r, r, skey->q );
 
   /* kinv = k^(-1) mod q */
@@ -578,24 +619,46 @@ sign(gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_secret_key *skey )
   mpi_free(k);
   mpi_free(kinv);
   mpi_free(tmp);
+
+  if (!mpi_cmp_ui (r, 0))
+    {
+      /* This is a highly unlikely code path.  */
+      extraloops++;
+      goto again;
+    }
+
+  rc = 0;
+
+ leave:
+  if (hash != input)
+    mpi_free (hash);
+
+  return rc;
 }
 
 
 /*
    Returns true if the signature composed from R and S is valid.
  */
-static int
-verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_public_key *pkey )
+static gpg_err_code_t
+verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_public_key *pkey )
 {
-  int rc;
+  gpg_err_code_t rc = 0;
   gcry_mpi_t w, u1, u2, v;
   gcry_mpi_t base[3];
   gcry_mpi_t ex[3];
+  gcry_mpi_t hash;
+  unsigned int nbits;
 
   if( !(mpi_cmp_ui( r, 0 ) > 0 && mpi_cmp( r, pkey->q ) < 0) )
-    return 0; /* assertion     0 < r < q  failed */
+    return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n  failed.  */
   if( !(mpi_cmp_ui( s, 0 ) > 0 && mpi_cmp( s, pkey->q ) < 0) )
-    return 0; /* assertion     0 < s < q  failed */
+    return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n  failed.  */
+
+  nbits = mpi_get_nbits (pkey->q);
+  rc = _gcry_dsa_normalize_hash (input, &hash, nbits);
+  if (rc)
+    return rc;
 
   w  = mpi_alloc( mpi_get_nlimbs(pkey->q) );
   u1 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
@@ -618,12 +681,25 @@ verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_public_key *pkey )
   mpi_mulpowm( v, base, ex, pkey->p );
   mpi_fdiv_r( v, v, pkey->q );
 
-  rc = !mpi_cmp( v, r );
+  if (mpi_cmp( v, r ))
+    {
+      if (DBG_CIPHER)
+        {
+          log_mpidump ("     i", input);
+          log_mpidump ("     h", hash);
+          log_mpidump ("     v", v);
+          log_mpidump ("     r", r);
+          log_mpidump ("     s", s);
+        }
+      rc = GPG_ERR_BAD_SIGNATURE;
+    }
 
   mpi_free(w);
   mpi_free(u1);
   mpi_free(u2);
   mpi_free(v);
+  if (hash != input)
+    mpi_free (hash);
 
   return rc;
 }
@@ -634,311 +710,458 @@ verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_public_key *pkey )
  *********************************************/
 
 static gcry_err_code_t
-dsa_generate_ext (int algo, unsigned int nbits, unsigned long evalue,
-                  const gcry_sexp_t genparms,
-                  gcry_mpi_t *skey, gcry_mpi_t **retfactors,
-                  gcry_sexp_t *r_extrainfo)
+dsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
 {
-  gpg_err_code_t ec;
+  gpg_err_code_t rc;
+  unsigned int nbits;
+  gcry_sexp_t domainsexp;
   DSA_secret_key sk;
   gcry_sexp_t l1;
   unsigned int qbits = 0;
   gcry_sexp_t deriveparms = NULL;
   gcry_sexp_t seedinfo = NULL;
-  int transient_key = 0;
-  int use_fips186_2 = 0;
-  int use_fips186 = 0;
-  
+  gcry_sexp_t misc_info = NULL;
+  int flags = 0;
+  dsa_domain_t domain;
+  gcry_mpi_t *factors = NULL;
+
+  memset (&sk, 0, sizeof sk);
+  memset (&domain, 0, sizeof domain);
 
-  (void)algo;    /* No need to check it.  */
-  (void)evalue;  /* Not required for DSA. */
+  rc = _gcry_pk_util_get_nbits (genparms, &nbits);
+  if (rc)
+    return rc;
 
-  if (genparms)
+  /* Parse the optional flags list.  */
+  l1 = sexp_find_token (genparms, "flags", 0);
+  if (l1)
     {
-      /* Parse the optional qbits element.  */
-      l1 = gcry_sexp_find_token (genparms, "qbits", 0);
-      if (l1)
+      rc = _gcry_pk_util_parse_flaglist (l1, &flags, NULL);
+      sexp_release (l1);
+      if (rc)
+        return rc;\
+    }
+
+  /* Parse the optional qbits element.  */
+  l1 = sexp_find_token (genparms, "qbits", 0);
+  if (l1)
+    {
+      char buf[50];
+      const char *s;
+      size_t n;
+
+      s = sexp_nth_data (l1, 1, &n);
+      if (!s || n >= DIM (buf) - 1 )
         {
-          char buf[50];
-          const char *s;
-          size_t n;
-          
-          s = gcry_sexp_nth_data (l1, 1, &n);
-          if (!s || n >= DIM (buf) - 1 )
-            {
-              gcry_sexp_release (l1);
-              return GPG_ERR_INV_OBJ; /* No value or value too large.  */
-            }
-          memcpy (buf, s, n);
-          buf[n] = 0;
-          qbits = (unsigned int)strtoul (buf, NULL, 0);
-          gcry_sexp_release (l1);
+          sexp_release (l1);
+          return GPG_ERR_INV_OBJ; /* No value or value too large.  */
         }
+      memcpy (buf, s, n);
+      buf[n] = 0;
+      qbits = (unsigned int)strtoul (buf, NULL, 0);
+      sexp_release (l1);
+    }
 
-      /* Parse the optional transient-key flag.  */
-      l1 = gcry_sexp_find_token (genparms, "transient-key", 0);
+  /* Parse the optional transient-key flag.  */
+  if (!(flags & PUBKEY_FLAG_TRANSIENT_KEY))
+    {
+      l1 = sexp_find_token (genparms, "transient-key", 0);
       if (l1)
         {
-          transient_key = 1;
-          gcry_sexp_release (l1);
+          flags |= PUBKEY_FLAG_TRANSIENT_KEY;
+          sexp_release (l1);
         }
+    }
 
-      /* Get the optional derive parameters.  */
-      deriveparms = gcry_sexp_find_token (genparms, "derive-parms", 0);
+  /* Get the optional derive parameters.  */
+  deriveparms = sexp_find_token (genparms, "derive-parms", 0);
 
-      /* Parse the optional "use-fips186" flags.  */
-      l1 = gcry_sexp_find_token (genparms, "use-fips186", 0);
+  /* Parse the optional "use-fips186" flags.  */
+  if (!(flags & PUBKEY_FLAG_USE_FIPS186))
+    {
+      l1 = sexp_find_token (genparms, "use-fips186", 0);
       if (l1)
         {
-          use_fips186 = 1;
-          gcry_sexp_release (l1);
+          flags |= PUBKEY_FLAG_USE_FIPS186;
+          sexp_release (l1);
         }
-      l1 = gcry_sexp_find_token (genparms, "use-fips186-2", 0);
+    }
+  if (!(flags & PUBKEY_FLAG_USE_FIPS186_2))
+    {
+      l1 = sexp_find_token (genparms, "use-fips186-2", 0);
       if (l1)
         {
-          use_fips186_2 = 1;
-          gcry_sexp_release (l1);
+          flags |= PUBKEY_FLAG_USE_FIPS186_2;
+          sexp_release (l1);
+        }
+    }
+
+  /* Check whether domain parameters are given.  */
+  domainsexp = sexp_find_token (genparms, "domain", 0);
+  if (domainsexp)
+    {
+      /* DERIVEPARMS can't be used together with domain parameters.
+         NBITS abnd QBITS may not be specified because there values
+         are derived from the domain parameters.  */
+      if (deriveparms || qbits || nbits)
+        {
+          sexp_release (domainsexp);
+          sexp_release (deriveparms);
+          return GPG_ERR_INV_VALUE;
+        }
+
+      /* Put all domain parameters into the domain object.  */
+      l1 = sexp_find_token (domainsexp, "p", 0);
+      domain.p = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+      sexp_release (l1);
+      l1 = sexp_find_token (domainsexp, "q", 0);
+      domain.q = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+      sexp_release (l1);
+      l1 = sexp_find_token (domainsexp, "g", 0);
+      domain.g = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+      sexp_release (l1);
+      sexp_release (domainsexp);
+
+      /* Check that all domain parameters are available.  */
+      if (!domain.p || !domain.q || !domain.g)
+        {
+          _gcry_mpi_release (domain.p);
+          _gcry_mpi_release (domain.q);
+          _gcry_mpi_release (domain.g);
+          sexp_release (deriveparms);
+          return GPG_ERR_MISSING_VALUE;
         }
+
+      /* Get NBITS and QBITS from the domain parameters.  */
+      nbits = mpi_get_nbits (domain.p);
+      qbits = mpi_get_nbits (domain.q);
     }
 
-  if (deriveparms || use_fips186 || use_fips186_2 || fips_mode ())
+  if (deriveparms
+      || (flags & PUBKEY_FLAG_USE_FIPS186)
+      || (flags & PUBKEY_FLAG_USE_FIPS186_2)
+      || fips_mode ())
     {
       int counter;
       void *seed;
       size_t seedlen;
       gcry_mpi_t h_value;
 
-      ec = generate_fips186 (&sk, nbits, qbits, deriveparms, use_fips186_2,
+      rc = generate_fips186 (&sk, nbits, qbits, deriveparms,
+                             !!(flags & PUBKEY_FLAG_USE_FIPS186_2),
+                             &domain,
                              &counter, &seed, &seedlen, &h_value);
-      gcry_sexp_release (deriveparms);
-      if (!ec)
+      if (!rc && h_value)
         {
-          ec = gpg_err_code (gcry_sexp_build 
-                             (&seedinfo, NULL,
-                              "(seed-values(counter %d)(seed %b)(h %m))",
-                              counter, (int)seedlen, seed, h_value));
-          if (ec)
-            {
-              gcry_mpi_release (sk.p); sk.p = NULL;
-              gcry_mpi_release (sk.q); sk.q = NULL;
-              gcry_mpi_release (sk.g); sk.g = NULL;
-              gcry_mpi_release (sk.y); sk.y = NULL;
-              gcry_mpi_release (sk.x); sk.x = NULL;
-            }
-          gcry_free (seed);
-          gcry_mpi_release (h_value);
+          /* Format the seed-values unless domain parameters are used
+             for which a H_VALUE of NULL is an indication.  */
+          rc = sexp_build (&seedinfo, NULL,
+                           "(seed-values(counter %d)(seed %b)(h %m))",
+                           counter, (int)seedlen, seed, h_value);
+          xfree (seed);
+          _gcry_mpi_release (h_value);
         }
     }
   else
     {
-      ec = generate (&sk, nbits, qbits, transient_key, retfactors);
+      rc = generate (&sk, nbits, qbits,
+                     !!(flags & PUBKEY_FLAG_TRANSIENT_KEY),
+                     &domain, &factors);
     }
-  if (!ec)
-    {
-      skey[0] = sk.p;
-      skey[1] = sk.q;
-      skey[2] = sk.g;
-      skey[3] = sk.y;
-      skey[4] = sk.x;
 
-      if (!r_extrainfo)
-        {
-          /* Old style interface - return the factors - if any - at
-             retfactors.  */
-        }
-      else if (!*retfactors && !seedinfo)
-        {
-          /* No factors and no seedinfo, thus there is nothing to return.  */
-          *r_extrainfo = NULL;
-        }
+  if (!rc)
+    {
+      /* Put the factors into MISC_INFO.  Note that the factors are
+         not confidential thus we can store them in standard memory.  */
+      int nfactors, i, j;
+      char *p;
+      char *format = NULL;
+      void **arg_list = NULL;
+
+      for (nfactors=0; factors && factors[nfactors]; nfactors++)
+        ;
+      /* Allocate space for the format string:
+         "(misc-key-info%S(pm1-factors%m))"
+         with one "%m" for each factor and construct it.  */
+      format = xtrymalloc (50 + 2*nfactors);
+      if (!format)
+        rc = gpg_err_code_from_syserror ();
       else
         {
-          /* Put the factors into extrainfo and set retfactors to NULL
-             to make use of the new interface.  Note that the factors
-             are not confidential thus we can store them in standard
-             memory.  */
-          int nfactors, i, j;
-          char *p;
-          char *format = NULL;
-          void **arg_list = NULL;
-
-          for (nfactors=0; *retfactors && (*retfactors)[nfactors]; nfactors++)
-            ;
-          /* Allocate space for the format string:
-               "(misc-key-info%S(pm1-factors%m))"
-             with one "%m" for each factor and construct it.  */
-          format = gcry_malloc (50 + 2*nfactors);
-          if (!format)
-            ec = gpg_err_code_from_syserror ();
-          else
+          p = stpcpy (format, "(misc-key-info");
+          if (seedinfo)
+            p = stpcpy (p, "%S");
+          if (nfactors)
             {
-              p = stpcpy (format, "(misc-key-info");
-              if (seedinfo)
-                p = stpcpy (p, "%S");
-              if (nfactors)
-                {
-                  p = stpcpy (p, "(pm1-factors");
-                  for (i=0; i < nfactors; i++)
-                    p = stpcpy (p, "%m");
-                  p = stpcpy (p, ")");
-                }
+              p = stpcpy (p, "(pm1-factors");
+              for (i=0; i < nfactors; i++)
+                p = stpcpy (p, "%m");
               p = stpcpy (p, ")");
-              
-              /* Allocate space for the list of factors plus one for
-                 an S-expression plus an extra NULL entry for safety
-                 and fill it with the factors.  */
-              arg_list = gcry_calloc (nfactors+1+1, sizeof *arg_list);
-              if (!arg_list)
-                ec = gpg_err_code_from_syserror ();
-              else
-                {
-                  i = 0;
-                  if (seedinfo)
-                    arg_list[i++] = &seedinfo;
-                  for (j=0; j < nfactors; j++)
-                    arg_list[i++] = (*retfactors) + j;
-                  arg_list[i] = NULL;
-                  
-                  ec = gpg_err_code (gcry_sexp_build_array 
-                                     (r_extrainfo, NULL, format, arg_list));
-                }
             }
-
-          gcry_free (arg_list);
-          gcry_free (format);
-          for (i=0; i < nfactors; i++)
-            {
-              gcry_mpi_release ((*retfactors)[i]);
-              (*retfactors)[i] = NULL;
-            }
-          *retfactors = NULL;
-          if (ec)
+          p = stpcpy (p, ")");
+
+          /* Allocate space for the list of factors plus one for the
+             seedinfo s-exp plus an extra NULL entry for safety and
+             fill it with the factors.  */
+          arg_list = xtrycalloc (nfactors+1+1, sizeof *arg_list);
+          if (!arg_list)
+            rc = gpg_err_code_from_syserror ();
+          else
             {
-              for (i=0; i < 5; i++)
-                {
-                  gcry_mpi_release (skey[i]);
-                  skey[i] = NULL;
-                }
+              i = 0;
+              if (seedinfo)
+                arg_list[i++] = &seedinfo;
+              for (j=0; j < nfactors; j++)
+                arg_list[i++] = factors + j;
+              arg_list[i] = NULL;
+
+              rc = sexp_build_array (&misc_info, NULL, format, arg_list);
             }
         }
-    }
-
-  gcry_sexp_release (seedinfo);
-  return ec;
-}
 
+      xfree (arg_list);
+      xfree (format);
+    }
 
-static gcry_err_code_t
-dsa_generate (int algo, unsigned int nbits, unsigned long evalue,
-              gcry_mpi_t *skey, gcry_mpi_t **retfactors)
-{
-  (void)evalue;
-  return dsa_generate_ext (algo, nbits, 0, NULL, skey, retfactors, NULL);
+  if (!rc)
+    rc = sexp_build (r_skey, NULL,
+                     "(key-data"
+                     " (public-key"
+                     "  (dsa(p%m)(q%m)(g%m)(y%m)))"
+                     " (private-key"
+                     "  (dsa(p%m)(q%m)(g%m)(y%m)(x%m)))"
+                     " %S)",
+                     sk.p, sk.q, sk.g, sk.y,
+                     sk.p, sk.q, sk.g, sk.y, sk.x,
+                     misc_info);
+
+
+  _gcry_mpi_release (sk.p);
+  _gcry_mpi_release (sk.q);
+  _gcry_mpi_release (sk.g);
+  _gcry_mpi_release (sk.y);
+  _gcry_mpi_release (sk.x);
+
+  _gcry_mpi_release (domain.p);
+  _gcry_mpi_release (domain.q);
+  _gcry_mpi_release (domain.g);
+
+  sexp_release (seedinfo);
+  sexp_release (misc_info);
+  sexp_release (deriveparms);
+  if (factors)
+    {
+      gcry_mpi_t *mp;
+      for (mp = factors; *mp; mp++)
+        mpi_free (*mp);
+      xfree (factors);
+    }
+  return rc;
 }
 
 
 
 static gcry_err_code_t
-dsa_check_secret_key (int algo, gcry_mpi_t *skey)
+dsa_check_secret_key (gcry_sexp_t keyparms)
 {
-  gcry_err_code_t err = GPG_ERR_NO_ERROR;
-  DSA_secret_key sk;
+  gcry_err_code_t rc;
+  DSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL};
 
-  (void)algo;
+  rc = _gcry_sexp_extract_param (keyparms, NULL, "pqgyx",
+                                 &sk.p, &sk.q, &sk.g, &sk.y, &sk.x,
+                                 NULL);
+  if (rc)
+    goto leave;
 
-  if ((! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3]) || (! skey[4]))
-    err = GPG_ERR_BAD_MPI;
-  else
-    {
-      sk.p = skey[0];
-      sk.q = skey[1];
-      sk.g = skey[2];
-      sk.y = skey[3];
-      sk.x = skey[4];
-      if (! check_secret_key (&sk))
-       err = GPG_ERR_BAD_SECKEY;
-    }
+  if (!check_secret_key (&sk))
+    rc = GPG_ERR_BAD_SECKEY;
 
-  return err;
+ leave:
+  _gcry_mpi_release (sk.p);
+  _gcry_mpi_release (sk.q);
+  _gcry_mpi_release (sk.g);
+  _gcry_mpi_release (sk.y);
+  _gcry_mpi_release (sk.x);
+  if (DBG_CIPHER)
+    log_debug ("dsa_testkey    => %s\n", gpg_strerror (rc));
+  return rc;
 }
 
 
 static gcry_err_code_t
-dsa_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey)
+dsa_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
 {
-  gcry_err_code_t err = GPG_ERR_NO_ERROR;
-  DSA_secret_key sk;
+  gcry_err_code_t rc;
+  struct pk_encoding_ctx ctx;
+  gcry_mpi_t data = NULL;
+  DSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL};
+  gcry_mpi_t sig_r = NULL;
+  gcry_mpi_t sig_s = NULL;
+
+  _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_SIGN,
+                                   dsa_get_nbits (keyparms));
+
+  /* Extract the data.  */
+  rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx);
+  if (rc)
+    goto leave;
+  if (DBG_CIPHER)
+    log_mpidump ("dsa_sign   data", data);
 
-  (void)algo;
+  /* Extract the key.  */
+  rc = _gcry_sexp_extract_param (keyparms, NULL, "pqgyx",
+                                 &sk.p, &sk.q, &sk.g, &sk.y, &sk.x, NULL);
+  if (rc)
+    goto leave;
+  if (DBG_CIPHER)
+    {
+      log_mpidump ("dsa_sign      p", sk.p);
+      log_mpidump ("dsa_sign      q", sk.q);
+      log_mpidump ("dsa_sign      g", sk.g);
+      log_mpidump ("dsa_sign      y", sk.y);
+      if (!fips_mode ())
+        log_mpidump ("dsa_sign      x", sk.x);
+    }
 
-  if ((! data)
-      || (! skey[0]) || (! skey[1]) || (! skey[2])
-      || (! skey[3]) || (! skey[4]))
-    err = GPG_ERR_BAD_MPI;
-  else
+  sig_r = mpi_new (0);
+  sig_s = mpi_new (0);
+  rc = sign (sig_r, sig_s, data, &sk, ctx.flags, ctx.hash_algo);
+  if (rc)
+    goto leave;
+  if (DBG_CIPHER)
     {
-      sk.p = skey[0];
-      sk.q = skey[1];
-      sk.g = skey[2];
-      sk.y = skey[3];
-      sk.x = skey[4];
-      resarr[0] = mpi_alloc (mpi_get_nlimbs (sk.p));
-      resarr[1] = mpi_alloc (mpi_get_nlimbs (sk.p));
-      sign (resarr[0], resarr[1], data, &sk);
+      log_mpidump ("dsa_sign  sig_r", sig_r);
+      log_mpidump ("dsa_sign  sig_s", sig_s);
     }
-  return err;
+  rc = sexp_build (r_sig, NULL, "(sig-val(dsa(r%M)(s%M)))", sig_r, sig_s);
+
+ leave:
+  _gcry_mpi_release (sig_r);
+  _gcry_mpi_release (sig_s);
+  _gcry_mpi_release (sk.p);
+  _gcry_mpi_release (sk.q);
+  _gcry_mpi_release (sk.g);
+  _gcry_mpi_release (sk.y);
+  _gcry_mpi_release (sk.x);
+  _gcry_mpi_release (data);
+  _gcry_pk_util_free_encoding_ctx (&ctx);
+  if (DBG_CIPHER)
+    log_debug ("dsa_sign      => %s\n", gpg_strerror (rc));
+  return rc;
 }
 
+
 static gcry_err_code_t
-dsa_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
-            int (*cmp) (void *, gcry_mpi_t), void *opaquev)
+dsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
 {
-  gcry_err_code_t err = GPG_ERR_NO_ERROR;
-  DSA_public_key pk;
+  gcry_err_code_t rc;
+  struct pk_encoding_ctx ctx;
+  gcry_sexp_t l1 = NULL;
+  gcry_mpi_t sig_r = NULL;
+  gcry_mpi_t sig_s = NULL;
+  gcry_mpi_t data = NULL;
+  DSA_public_key pk = { NULL, NULL, NULL, NULL };
+
+  _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_VERIFY,
+                                   dsa_get_nbits (s_keyparms));
+
+  /* Extract the data.  */
+  rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx);
+  if (rc)
+    goto leave;
+  if (DBG_CIPHER)
+    log_mpidump ("dsa_verify data", data);
 
-  (void)algo;
-  (void)cmp;
-  (void)opaquev;
+  /* Extract the signature value.  */
+  rc = _gcry_pk_util_preparse_sigval (s_sig, dsa_names, &l1, NULL);
+  if (rc)
+    goto leave;
+  rc = _gcry_sexp_extract_param (l1, NULL, "rs", &sig_r, &sig_s, NULL);
+  if (rc)
+    goto leave;
+  if (DBG_CIPHER)
+    {
+      log_mpidump ("dsa_verify  s_r", sig_r);
+      log_mpidump ("dsa_verify  s_s", sig_s);
+    }
 
-  if ((! data[0]) || (! data[1]) || (! hash)
-      || (! pkey[0]) || (! pkey[1]) || (! pkey[2]) || (! pkey[3]))
-    err = GPG_ERR_BAD_MPI;
-  else
+  /* Extract the key.  */
+  rc = _gcry_sexp_extract_param (s_keyparms, NULL, "pqgy",
+                                 &pk.p, &pk.q, &pk.g, &pk.y, NULL);
+  if (rc)
+    goto leave;
+  if (DBG_CIPHER)
     {
-      pk.p = pkey[0];
-      pk.q = pkey[1];
-      pk.g = pkey[2];
-      pk.y = pkey[3];
-      if (! verify (data[0], data[1], hash, &pk))
-       err = GPG_ERR_BAD_SIGNATURE;
+      log_mpidump ("dsa_verify    p", pk.p);
+      log_mpidump ("dsa_verify    q", pk.q);
+      log_mpidump ("dsa_verify    g", pk.g);
+      log_mpidump ("dsa_verify    y", pk.y);
     }
-  return err;
+
+  /* Verify the signature.  */
+  rc = verify (sig_r, sig_s, data, &pk);
+
+ leave:
+  _gcry_mpi_release (pk.p);
+  _gcry_mpi_release (pk.q);
+  _gcry_mpi_release (pk.g);
+  _gcry_mpi_release (pk.y);
+  _gcry_mpi_release (data);
+  _gcry_mpi_release (sig_r);
+  _gcry_mpi_release (sig_s);
+  sexp_release (l1);
+  _gcry_pk_util_free_encoding_ctx (&ctx);
+  if (DBG_CIPHER)
+    log_debug ("dsa_verify    => %s\n", rc?gpg_strerror (rc):"Good");
+  return rc;
 }
 
 
+/* Return the number of bits for the key described by PARMS.  On error
+ * 0 is returned.  The format of PARMS starts with the algorithm name;
+ * for example:
+ *
+ *   (dsa
+ *     (p <mpi>)
+ *     (q <mpi>)
+ *     (g <mpi>)
+ *     (y <mpi>))
+ *
+ * More parameters may be given but we only need P here.
+ */
 static unsigned int
-dsa_get_nbits (int algo, gcry_mpi_t *pkey)
+dsa_get_nbits (gcry_sexp_t parms)
 {
-  (void)algo;
-
-  return mpi_get_nbits (pkey[0]);
+  gcry_sexp_t l1;
+  gcry_mpi_t p;
+  unsigned int nbits;
+
+  l1 = sexp_find_token (parms, "p", 1);
+  if (!l1)
+    return 0; /* Parameter P not found.  */
+
+  p = sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+  sexp_release (l1);
+  nbits = p? mpi_get_nbits (p) : 0;
+  _gcry_mpi_release (p);
+  return nbits;
 }
 
 
 \f
-/* 
+/*
      Self-test section.
  */
 
 static const char *
 selftest_sign_1024 (gcry_sexp_t pkey, gcry_sexp_t skey)
 {
-  static const char sample_data[] = 
-    "(data (flags pkcs1)"
-    " (hash sha1 #a0b1c2d3e4f500102030405060708090a1b2c3d4#))";
-  static const char sample_data_bad[] = 
-    "(data (flags pkcs1)"
-    " (hash sha1 #a0b1c2d3e4f510102030405060708090a1b2c3d4#))";
+  static const char sample_data[] =
+    "(data (flags raw)"
+    " (value #a0b1c2d3e4f500102030405060708090a1b2c3d4#))";
+  static const char sample_data_bad[] =
+    "(data (flags raw)"
+    " (value #a0b1c2d3e4f510102030405060708090a1b2c3d4#))";
 
   const char *errtxt = NULL;
   gcry_error_t err;
@@ -946,30 +1169,29 @@ selftest_sign_1024 (gcry_sexp_t pkey, gcry_sexp_t skey)
   gcry_sexp_t data_bad = NULL;
   gcry_sexp_t sig = NULL;
 
-  err = gcry_sexp_sscan (&data, NULL,
-                         sample_data, strlen (sample_data));
+  err = sexp_sscan (&data, NULL, sample_data, strlen (sample_data));
   if (!err)
-    err = gcry_sexp_sscan (&data_bad, NULL, 
-                           sample_data_bad, strlen (sample_data_bad));
+    err = sexp_sscan (&data_bad, NULL,
+                      sample_data_bad, strlen (sample_data_bad));
   if (err)
     {
       errtxt = "converting data failed";
       goto leave;
     }
 
-  err = gcry_pk_sign (&sig, data, skey);
+  err = _gcry_pk_sign (&sig, data, skey);
   if (err)
     {
       errtxt = "signing failed";
       goto leave;
     }
-  err = gcry_pk_verify (sig, data, pkey);
+  err = _gcry_pk_verify (sig, data, pkey);
   if (err)
     {
       errtxt = "verify failed";
       goto leave;
     }
-  err = gcry_pk_verify (sig, data_bad, pkey);
+  err = _gcry_pk_verify (sig, data_bad, pkey);
   if (gcry_err_code (err) != GPG_ERR_BAD_SIGNATURE)
     {
       errtxt = "bad signature not detected";
@@ -978,9 +1200,9 @@ selftest_sign_1024 (gcry_sexp_t pkey, gcry_sexp_t skey)
 
 
  leave:
-  gcry_sexp_release (sig);
-  gcry_sexp_release (data_bad);
-  gcry_sexp_release (data);
+  sexp_release (sig);
+  sexp_release (data_bad);
+  sexp_release (data);
   return errtxt;
 }
 
@@ -996,22 +1218,21 @@ selftests_dsa (selftest_report_func_t report)
 
   /* Convert the S-expressions into the internal representation.  */
   what = "convert";
-  err = gcry_sexp_sscan (&skey, NULL, 
-                         sample_secret_key, strlen (sample_secret_key));
+  err = sexp_sscan (&skey, NULL, sample_secret_key, strlen (sample_secret_key));
   if (!err)
-    err = gcry_sexp_sscan (&pkey, NULL, 
-                           sample_public_key, strlen (sample_public_key));
+    err = sexp_sscan (&pkey, NULL,
+                      sample_public_key, strlen (sample_public_key));
   if (err)
     {
-      errtxt = gcry_strerror (err);
+      errtxt = _gcry_strerror (err);
       goto failed;
     }
 
   what = "key consistency";
-  err = gcry_pk_testkey (skey);
+  err = _gcry_pk_testkey (skey);
   if (err)
     {
-      errtxt = gcry_strerror (err);
+      errtxt = _gcry_strerror (err);
       goto failed;
     }
 
@@ -1020,13 +1241,13 @@ selftests_dsa (selftest_report_func_t report)
   if (errtxt)
     goto failed;
 
-  gcry_sexp_release (pkey);
-  gcry_sexp_release (skey);
+  sexp_release (pkey);
+  sexp_release (skey);
   return 0; /* Succeeded. */
 
  failed:
-  gcry_sexp_release (pkey);
-  gcry_sexp_release (skey);
+  sexp_release (pkey);
+  sexp_release (skey);
   if (report)
     report ("pubkey", GCRY_PK_DSA, what, errtxt);
   return GPG_ERR_SELFTEST_FAILED;
@@ -1049,7 +1270,7 @@ run_selftests (int algo, int extended, selftest_report_func_t report)
     default:
       ec = GPG_ERR_PUBKEY_ALGO;
       break;
-        
+
     }
   return ec;
 }
@@ -1057,29 +1278,18 @@ run_selftests (int algo, int extended, selftest_report_func_t report)
 
 
 \f
-static const char *dsa_names[] =
-  {
-    "dsa",
-    "openpgp-dsa",
-    NULL,
-  };
-
 gcry_pk_spec_t _gcry_pubkey_spec_dsa =
   {
-    "DSA", dsa_names, 
-    "pqgy", "pqgyx", "", "rs", "pqgy",
+    GCRY_PK_DSA, { 0, 1 },
     GCRY_PK_USAGE_SIGN,
+    "DSA", dsa_names,
+    "pqgy", "pqgyx", "", "rs", "pqgy",
     dsa_generate,
     dsa_check_secret_key,
     NULL,
     NULL,
     dsa_sign,
     dsa_verify,
-    dsa_get_nbits
+    dsa_get_nbits,
+    run_selftests
   };
-pk_extra_spec_t _gcry_pubkey_extraspec_dsa = 
-  {
-    run_selftests,
-    dsa_generate_ext
-  };
-