pubkey: Re-map all depreccated RSA algo numbers.
[libgcrypt.git] / cipher / dsa.c
index 136d64f..1707d8c 100644 (file)
@@ -58,6 +58,14 @@ typedef struct
 } 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"
@@ -107,8 +115,10 @@ static gpg_err_code_t generate (DSA_secret_key *sk,
                                 gcry_mpi_t **ret_factors);
 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 int verify (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input,
+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;
@@ -138,9 +148,9 @@ 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;
@@ -149,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, 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;
 }
 
@@ -253,7 +263,7 @@ generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
         {
           mpi_add_ui (h, h, 1);
           /* g = h^e mod p */
-          gcry_mpi_powm (g, h, e, p);
+          mpi_powm (g, h, e, p);
         }
       while (!mpi_cmp_ui (g, 1));  /* Continue until g != 1. */
     }
@@ -281,25 +291,25 @@ generate (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
       if( DBG_CIPHER )
         progress('.');
       if( !rndbuf )
-        rndbuf = gcry_random_bytes_secure ((qbits+7)/8, random_level);
+        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 )
     {
@@ -321,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;
     }
@@ -408,9 +418,9 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
       /* Get an initial seed value.  */
       if (deriveparms)
         {
-          initial_seed.sexp = gcry_sexp_find_token (deriveparms, "seed", 0);
+          initial_seed.sexp = sexp_find_token (deriveparms, "seed", 0);
           if (initial_seed.sexp)
-            initial_seed.seed = gcry_sexp_nth_data (initial_seed.sexp, 1,
+            initial_seed.seed = sexp_nth_data (initial_seed.sexp, 1,
                                                     &initial_seed.seedlen);
         }
 
@@ -429,7 +439,7 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
       /*                                          &prime_q, &prime_p, */
       /*                                          r_counter, */
       /*                                          r_seed, r_seedlen, NULL); */
-      gcry_sexp_release (initial_seed.sexp);
+      sexp_release (initial_seed.sexp);
       if (ec)
         goto leave;
 
@@ -451,19 +461,19 @@ generate_fips186 (DSA_secret_key *sk, unsigned int nbits, unsigned int qbits,
 
 
   /* Select a random number x with:  0 < x < q  */
-  value_x = gcry_mpi_snew (qbits);
+  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)
     {
@@ -485,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;
     }
@@ -508,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;
@@ -528,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;
@@ -563,18 +573,9 @@ sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_secret_key *skey,
   qbits = mpi_get_nbits (skey->q);
 
   /* Convert the INPUT into an MPI.  */
-  if (mpi_is_opaque (input))
-    {
-      abuf = gcry_mpi_get_opaque (input, &abits);
-      rc = gpg_err_code (gcry_mpi_scan (&hash, GCRYMPI_FMT_USG,
-                                        abuf, (abits+7)/8, NULL));
-      if (rc)
-        return rc;
-      if (abits > qbits)
-        gcry_mpi_rshift (hash, hash, abits - qbits);
-    }
-  else
-    hash = input;
+  rc = _gcry_dsa_normalize_hash (input, &hash, qbits);
+  if (rc)
+    return rc;
 
  again:
   /* Create the K value.  */
@@ -589,7 +590,7 @@ sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_secret_key *skey,
           goto leave;
         }
 
-      abuf = gcry_mpi_get_opaque (input, &abits);
+      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)
@@ -602,7 +603,7 @@ sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_secret_key *skey,
     }
 
   /* 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 */
@@ -639,18 +640,25 @@ sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t input, DSA_secret_key *skey,
 /*
    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) );
@@ -673,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;
 }
@@ -700,9 +721,7 @@ dsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
   gcry_sexp_t deriveparms = NULL;
   gcry_sexp_t seedinfo = NULL;
   gcry_sexp_t misc_info = NULL;
-  int transient_key = 0;
-  int use_fips186_2 = 0;
-  int use_fips186 = 0;
+  int flags = 0;
   dsa_domain_t domain;
   gcry_mpi_t *factors = NULL;
 
@@ -713,53 +732,72 @@ dsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
   if (rc)
     return rc;
 
+  /* Parse the optional flags list.  */
+  l1 = sexp_find_token (genparms, "flags", 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 = gcry_sexp_find_token (genparms, "qbits", 0);
+  l1 = sexp_find_token (genparms, "qbits", 0);
   if (l1)
     {
       char buf[50];
       const char *s;
       size_t n;
 
-      s = gcry_sexp_nth_data (l1, 1, &n);
+      s = sexp_nth_data (l1, 1, &n);
       if (!s || n >= DIM (buf) - 1 )
         {
-          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);
-      gcry_sexp_release (l1);
+      sexp_release (l1);
     }
 
   /* Parse the optional transient-key flag.  */
-  l1 = gcry_sexp_find_token (genparms, "transient-key", 0);
-  if (l1)
+  if (!(flags & PUBKEY_FLAG_TRANSIENT_KEY))
     {
-      transient_key = 1;
-      gcry_sexp_release (l1);
+      l1 = sexp_find_token (genparms, "transient-key", 0);
+      if (l1)
+        {
+          flags |= PUBKEY_FLAG_TRANSIENT_KEY;
+          sexp_release (l1);
+        }
     }
 
   /* Get the optional derive parameters.  */
-  deriveparms = gcry_sexp_find_token (genparms, "derive-parms", 0);
+  deriveparms = sexp_find_token (genparms, "derive-parms", 0);
 
   /* Parse the optional "use-fips186" flags.  */
-  l1 = gcry_sexp_find_token (genparms, "use-fips186", 0);
-  if (l1)
+  if (!(flags & PUBKEY_FLAG_USE_FIPS186))
     {
-      use_fips186 = 1;
-      gcry_sexp_release (l1);
+      l1 = sexp_find_token (genparms, "use-fips186", 0);
+      if (l1)
+        {
+          flags |= PUBKEY_FLAG_USE_FIPS186;
+          sexp_release (l1);
+        }
     }
-  l1 = gcry_sexp_find_token (genparms, "use-fips186-2", 0);
-  if (l1)
+  if (!(flags & PUBKEY_FLAG_USE_FIPS186_2))
     {
-      use_fips186_2 = 1;
-      gcry_sexp_release (l1);
+      l1 = sexp_find_token (genparms, "use-fips186-2", 0);
+      if (l1)
+        {
+          flags |= PUBKEY_FLAG_USE_FIPS186_2;
+          sexp_release (l1);
+        }
     }
 
   /* Check whether domain parameters are given.  */
-  domainsexp = gcry_sexp_find_token (genparms, "domain", 0);
+  domainsexp = sexp_find_token (genparms, "domain", 0);
   if (domainsexp)
     {
       /* DERIVEPARMS can't be used together with domain parameters.
@@ -767,30 +805,30 @@ dsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
          are derived from the domain parameters.  */
       if (deriveparms || qbits || nbits)
         {
-          gcry_sexp_release (domainsexp);
-          gcry_sexp_release (deriveparms);
+          sexp_release (domainsexp);
+          sexp_release (deriveparms);
           return GPG_ERR_INV_VALUE;
         }
 
       /* Put all domain parameters into the domain object.  */
-      l1 = gcry_sexp_find_token (domainsexp, "p", 0);
-      domain.p = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
-      gcry_sexp_release (l1);
-      l1 = gcry_sexp_find_token (domainsexp, "q", 0);
-      domain.q = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
-      gcry_sexp_release (l1);
-      l1 = gcry_sexp_find_token (domainsexp, "g", 0);
-      domain.g = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
-      gcry_sexp_release (l1);
-      gcry_sexp_release (domainsexp);
+      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);
-          gcry_sexp_release (deriveparms);
+          _gcry_mpi_release (domain.p);
+          _gcry_mpi_release (domain.q);
+          _gcry_mpi_release (domain.g);
+          sexp_release (deriveparms);
           return GPG_ERR_MISSING_VALUE;
         }
 
@@ -799,30 +837,36 @@ dsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
       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;
 
-      rc = 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);
       if (!rc && h_value)
         {
           /* Format the seed-values unless domain parameters are used
              for which a H_VALUE of NULL is an indication.  */
-          rc = gcry_sexp_build (&seedinfo, NULL,
-                                "(seed-values(counter %d)(seed %b)(h %m))",
-                                counter, (int)seedlen, seed, h_value);
-          gcry_free (seed);
-          gcry_mpi_release (h_value);
+          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
     {
-      rc = generate (&sk, nbits, qbits, transient_key, &domain, &factors);
+      rc = generate (&sk, nbits, qbits,
+                     !!(flags & PUBKEY_FLAG_TRANSIENT_KEY),
+                     &domain, &factors);
     }
 
   if (!rc)
@@ -839,7 +883,7 @@ dsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
       /* 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);
+      format = xtrymalloc (50 + 2*nfactors);
       if (!format)
         rc = gpg_err_code_from_syserror ();
       else
@@ -859,7 +903,7 @@ dsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
           /* 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 = gcry_calloc (nfactors+1+1, sizeof *arg_list);
+          arg_list = xtrycalloc (nfactors+1+1, sizeof *arg_list);
           if (!arg_list)
             rc = gpg_err_code_from_syserror ();
           else
@@ -871,46 +915,46 @@ dsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
                 arg_list[i++] = factors + j;
               arg_list[i] = NULL;
 
-              rc = gcry_sexp_build_array (&misc_info, NULL, format, arg_list);
+              rc = sexp_build_array (&misc_info, NULL, format, arg_list);
             }
         }
 
-      gcry_free (arg_list);
-      gcry_free (format);
+      xfree (arg_list);
+      xfree (format);
     }
 
   if (!rc)
-    rc = gcry_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);
-
-  gcry_sexp_release (seedinfo);
-  gcry_sexp_release (misc_info);
-  gcry_sexp_release (deriveparms);
+    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);
-      gcry_free (factors);
+      xfree (factors);
     }
   return rc;
 }
@@ -918,123 +962,189 @@ dsa_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
 
 
 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_sexp_t *r_result, gcry_mpi_t data, gcry_mpi_t *skey,
-          int flags, int hashalgo)
+dsa_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
 {
   gcry_err_code_t rc;
-  DSA_secret_key sk;
-  gcry_mpi_t r, s;
+  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;
 
-  (void)algo;
-  (void)flags;
-  (void)hashalgo;
+  _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_SIGN,
+                                   dsa_get_nbits (keyparms));
 
-  if ((! data)
-      || (! skey[0]) || (! skey[1]) || (! skey[2])
-      || (! skey[3]) || (! skey[4]))
-    rc = GPG_ERR_BAD_MPI;
-  else
+  /* 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);
+
+  /* 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)
     {
-      sk.p = skey[0];
-      sk.q = skey[1];
-      sk.g = skey[2];
-      sk.y = skey[3];
-      sk.x = skey[4];
-      r = mpi_alloc (mpi_get_nlimbs (sk.p));
-      s = mpi_alloc (mpi_get_nlimbs (sk.p));
-      rc = sign (r, s, data, &sk, flags, hashalgo);
-      if (!rc)
-        rc = gcry_sexp_build (r_result, NULL, "(sig-val(dsa(r%M)(s%M)))", r, s);
-      mpi_free (r);
-      mpi_free (s);
+      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);
     }
+
+  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)
+    {
+      log_mpidump ("dsa_sign  sig_r", sig_r);
+      log_mpidump ("dsa_sign  sig_s", sig_s);
+    }
+  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,
-            int flags, int hashalgo)
+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;
-
-  (void)algo;
-  (void)cmp;
-  (void)opaquev;
-  (void)flags;
-  (void)hashalgo;
+  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);
 
-  if ((! data[0]) || (! data[1]) || (! hash)
-      || (! pkey[0]) || (! pkey[1]) || (! pkey[2]) || (! pkey[3]))
-    err = GPG_ERR_BAD_MPI;
-  else
+  /* 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)
     {
-      pk.p = pkey[0];
-      pk.q = pkey[1];
-      pk.g = pkey[2];
-      pk.y = pkey[3];
-      if (mpi_is_opaque (hash))
-        {
-          const void *abuf;
-          unsigned int abits, qbits;
-          gcry_mpi_t a;
+      log_mpidump ("dsa_verify  s_r", sig_r);
+      log_mpidump ("dsa_verify  s_s", sig_s);
+    }
 
-          qbits = mpi_get_nbits (pk.q);
+  /* 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)
+    {
+      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);
+    }
 
-          abuf = gcry_mpi_get_opaque (hash, &abits);
-          err = gcry_mpi_scan (&a, GCRYMPI_FMT_USG, abuf, (abits+7)/8, NULL);
-          if (!err)
-            {
-              if (abits > qbits)
-                gcry_mpi_rshift (a, a, abits - qbits);
+  /* Verify the signature.  */
+  rc = verify (sig_r, sig_s, data, &pk);
 
-              if (!verify (data[0], data[1], a, &pk))
-                err = GPG_ERR_BAD_SIGNATURE;
-              gcry_mpi_release (a);
-            }
-        }
-      else
-        {
-          if (!verify (data[0], data[1], hash, &pk))
-            err = GPG_ERR_BAD_SIGNATURE;
-        }
-    }
-  return err;
+ 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;
+  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.  */
 
-  return mpi_get_nbits (pkey[0]);
+  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;
 }
 
 
@@ -1059,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";
@@ -1091,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;
 }
 
@@ -1109,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;
     }
 
@@ -1133,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;
@@ -1170,13 +1278,6 @@ 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 =
   {
     GCRY_PK_DSA, { 0, 1 },