[git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-174-g1cfa79a

by Werner Koch cvs at cvs.gnupg.org
Fri Jul 26 20:51:04 CEST 2013


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU crypto library".

The branch, master has been updated
       via  1cfa79aabc5d0fd8d124901054475e90ab7d9cde (commit)
       via  b72d312ad11887fc416aa821786f6bdb663c0f4a (commit)
      from  287bf0e543f244d784cf8b58340bf0ab3c6aba97 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 1cfa79aabc5d0fd8d124901054475e90ab7d9cde
Author: Werner Koch <wk at gnupg.org>
Date:   Fri Jul 26 20:15:53 2013 +0200

    Implement deterministic DSA as specified by rfc-6979.
    
    * cipher/dsa.c (dsa_sign): Move opaque mpi extraction to sign.
    (sign): Add args FLAGS and HASHALGO.  Implement deterministic DSA.
    Add code path for R==0 to comply with the standard.
    (dsa_verify): Left fill opaque mpi based hash values.
    * cipher/dsa-common.c (int2octets, bits2octets): New.
    (_gcry_dsa_gen_rfc6979_k): New.
    * tests/dsa-rfc6979.c: New.
    * tests/Makefile.am (TESTS): Add dsa-rfc6979.
    --
    
    This patch also fixes a recent patch (37d0a1e) which allows to pass
    the hash in a (hash) element.
    
    Support for deterministic ECDSA will come soon.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/cipher/dsa-common.c b/cipher/dsa-common.c
index a5854ce..c5386b7 100644
--- a/cipher/dsa-common.c
+++ b/cipher/dsa-common.c
@@ -84,13 +84,13 @@ _gcry_dsa_gen_k (gcry_mpi_t q, int security_level)
       if (!(mpi_cmp (k, q) < 0))    /* check: k < q */
         {
           if (DBG_CIPHER)
-            log_debug ("\tk too large - again");
+            log_debug ("\tk too large - again\n");
           continue; /* no  */
         }
       if (!(mpi_cmp_ui (k, 0) > 0)) /* check: k > 0 */
         {
           if (DBG_CIPHER)
-            log_debug ("\tk is zero - again");
+            log_debug ("\tk is zero - again\n");
           continue; /* no */
         }
       break;	/* okay */
@@ -99,3 +99,267 @@ _gcry_dsa_gen_k (gcry_mpi_t q, int security_level)
 
   return k;
 }
+
+
+/* Turn VALUE into an octet string and store it in an allocated buffer
+   at R_FRAME.  If the resulting octet string is shorter than NBYTES
+   the result will be left padded with zeroes.  If VALUE does not fit
+   into NBYTES an error code is returned.  */
+static gpg_err_code_t
+int2octets (unsigned char **r_frame, gcry_mpi_t value, size_t nbytes)
+{
+  gpg_err_code_t rc;
+  size_t nframe, noff, n;
+  unsigned char *frame;
+
+  rc = gpg_err_code (gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0,
+                                      &nframe, value));
+  if (rc)
+    return rc;
+  if (nframe > nbytes)
+    return GPG_ERR_TOO_LARGE; /* Value too long to fit into NBYTES.  */
+
+  noff = (nframe < nbytes)? nbytes - nframe : 0;
+  n = nframe + noff;
+  frame = mpi_is_secure (value)? gcry_malloc_secure (n) : gcry_malloc (n);
+  if (!frame)
+    return gpg_err_code_from_syserror ();
+  if (noff)
+    memset (frame, 0, noff);
+  nframe += noff;
+  rc = gpg_err_code (gcry_mpi_print (GCRYMPI_FMT_USG, frame+noff, nframe-noff,
+                                      NULL, value));
+  if (rc)
+    {
+      gcry_free (frame);
+      return rc;
+    }
+
+  *r_frame = frame;
+  return 0;
+}
+
+
+/* Connert the bit string BITS of length NBITS into an octet string
+   with a length of (QBITS+7)/8 bytes.  On success store the result at
+   R_FRAME.  */
+static gpg_err_code_t
+bits2octets (unsigned char **r_frame,
+             const void *bits, unsigned int nbits,
+             gcry_mpi_t q, unsigned int qbits)
+{
+  gpg_err_code_t rc;
+  gcry_mpi_t z1;
+
+  /* z1 = bits2int (b) */
+  rc = gpg_err_code (gcry_mpi_scan (&z1, GCRYMPI_FMT_USG,
+                                    bits, (nbits+7)/8, NULL));
+  if (rc)
+    return rc;
+  if (nbits > qbits)
+    gcry_mpi_rshift (z1, z1, nbits - qbits);
+
+  /* z2 - z1 mod q */
+  if (mpi_cmp (z1, q) >= 0)
+    mpi_sub (z1, z1, q);
+
+  /* Convert to an octet string.  */
+  rc = int2octets (r_frame, z1, (qbits+7)/8);
+
+  mpi_free (z1);
+  return rc;
+}
+
+
+/*
+ * Generate a deterministic secret exponent K less than DSA_Q.  H1 is
+ * the to be signed digest with a length of HLEN bytes.  HALGO is the
+ * algorithm used to create the hash.  On success the value for K is
+ * stored at R_K.
+ */
+gpg_err_code_t
+_gcry_dsa_gen_rfc6979_k (gcry_mpi_t *r_k,
+                         gcry_mpi_t dsa_q, gcry_mpi_t dsa_x,
+                         const unsigned char *h1, unsigned int hlen,
+                         int halgo, unsigned int extraloops)
+{
+  gpg_err_code_t rc;
+  unsigned char *V = NULL;
+  unsigned char *K = NULL;
+  unsigned char *x_buf = NULL;
+  unsigned char *h1_buf = NULL;
+  gcry_md_hd_t hd = NULL;
+  unsigned char *t = NULL;
+  gcry_mpi_t k = NULL;
+  unsigned int tbits, qbits;
+  int i;
+
+  qbits = mpi_get_nbits (dsa_q);
+
+  if (!qbits || !h1 || !hlen)
+    return GPG_ERR_EINVAL;
+
+  if (gcry_md_get_algo_dlen (halgo) != hlen)
+    return GPG_ERR_DIGEST_ALGO;
+
+  /* Step b:  V = 0x01 0x01 0x01 ... 0x01 */
+  V = gcry_malloc (hlen);
+  if (!V)
+    {
+      rc = gpg_err_code_from_syserror ();
+      goto leave;
+    }
+  for (i=0; i < hlen; i++)
+    V[i] = 1;
+
+  /* Step c:  K = 0x00 0x00 0x00 ... 0x00 */
+  K = gcry_calloc (1, hlen);
+  if (!K)
+    {
+      rc = gpg_err_code_from_syserror ();
+      goto leave;
+    }
+
+  rc = int2octets (&x_buf, dsa_x, (qbits+7)/8);
+  if (rc)
+    goto leave;
+
+  rc = bits2octets (&h1_buf, h1, hlen*8, dsa_q, qbits);
+  if (rc)
+    goto leave;
+
+  /* Create a handle to compute the HMACs.  */
+  rc = gpg_err_code (gcry_md_open (&hd, halgo,
+                                   (GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC)));
+  if (rc)
+    goto leave;
+
+  /* Step d:  K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) */
+  rc = gpg_err_code (gcry_md_setkey (hd, K, hlen));
+  if (rc)
+    goto leave;
+  gcry_md_write (hd, V, hlen);
+  gcry_md_write (hd, "", 1);
+  gcry_md_write (hd, x_buf, (qbits+7)/8);
+  gcry_md_write (hd, h1_buf, (qbits+7)/8);
+  memcpy (K, gcry_md_read (hd, 0), hlen);
+
+  /* Step e:  V = HMAC_K(V) */
+  rc = gpg_err_code (gcry_md_setkey (hd, K, hlen));
+  if (rc)
+    goto leave;
+  gcry_md_write (hd, V, hlen);
+  memcpy (V, gcry_md_read (hd, 0), hlen);
+
+  /* Step f:  K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1) */
+  rc = gpg_err_code (gcry_md_setkey (hd, K, hlen));
+  if (rc)
+    goto leave;
+  gcry_md_write (hd, V, hlen);
+  gcry_md_write (hd, "\x01", 1);
+  gcry_md_write (hd, x_buf, (qbits+7)/8);
+  gcry_md_write (hd, h1_buf, (qbits+7)/8);
+  memcpy (K, gcry_md_read (hd, 0), hlen);
+
+  /* Step g:  V = HMAC_K(V) */
+  rc = gpg_err_code (gcry_md_setkey (hd, K, hlen));
+  if (rc)
+    goto leave;
+  gcry_md_write (hd, V, hlen);
+  memcpy (V, gcry_md_read (hd, 0), hlen);
+
+  /* Step h. */
+  t = gcry_malloc ((qbits+7)/8+hlen);
+  if (!t)
+    {
+      rc = gpg_err_code_from_syserror ();
+      goto leave;
+    }
+
+ again:
+  for (tbits = 0; tbits < qbits;)
+    {
+      /* V = HMAC_K(V) */
+      rc = gpg_err_code (gcry_md_setkey (hd, K, hlen));
+      if (rc)
+        goto leave;
+      gcry_md_write (hd, V, hlen);
+      memcpy (V, gcry_md_read (hd, 0), hlen);
+
+      /* T = T || V */
+      memcpy (t+(tbits+7)/8, V, hlen);
+      tbits += 8*hlen;
+    }
+
+  /* k = bits2int (T) */
+  mpi_free (k);
+  k = NULL;
+  rc = gpg_err_code (gcry_mpi_scan (&k, GCRYMPI_FMT_USG, t, (tbits+7)/8, NULL));
+  if (rc)
+    goto leave;
+  if (tbits > qbits)
+    gcry_mpi_rshift (k, k, tbits - qbits);
+
+  /* Check: k < q and k > 1 */
+  if (!(mpi_cmp (k, dsa_q) < 0 && mpi_cmp_ui (k, 0) > 0))
+    {
+      /* K = HMAC_K(V || 0x00) */
+      rc = gpg_err_code (gcry_md_setkey (hd, K, hlen));
+      if (rc)
+        goto leave;
+      gcry_md_write (hd, V, hlen);
+      gcry_md_write (hd, "", 1);
+      memcpy (K, gcry_md_read (hd, 0), hlen);
+
+      /* V = HMAC_K(V) */
+      rc = gpg_err_code (gcry_md_setkey (hd, K, hlen));
+      if (rc)
+        goto leave;
+      gcry_md_write (hd, V, hlen);
+      memcpy (V, gcry_md_read (hd, 0), hlen);
+
+      goto again;
+    }
+
+  /* The caller may have requested that we introduce some extra loops.
+     This is for example useful if the caller wants another value for
+     K because the last returned one yielded an R of 0.  Becuase this
+     is very unlikely we implement it in a straightforward way.  */
+  if (extraloops)
+    {
+      extraloops--;
+
+      /* K = HMAC_K(V || 0x00) */
+      rc = gpg_err_code (gcry_md_setkey (hd, K, hlen));
+      if (rc)
+        goto leave;
+      gcry_md_write (hd, V, hlen);
+      gcry_md_write (hd, "", 1);
+      memcpy (K, gcry_md_read (hd, 0), hlen);
+
+      /* V = HMAC_K(V) */
+      rc = gpg_err_code (gcry_md_setkey (hd, K, hlen));
+      if (rc)
+        goto leave;
+      gcry_md_write (hd, V, hlen);
+      memcpy (V, gcry_md_read (hd, 0), hlen);
+
+      goto again;
+    }
+
+  /* log_mpidump ("  k", k); */
+
+ leave:
+  gcry_free (t);
+  gcry_md_close (hd);
+  gcry_free (h1_buf);
+  gcry_free (x_buf);
+  gcry_free (K);
+  gcry_free (V);
+
+  if (rc)
+    mpi_free (k);
+  else
+    *r_k = k;
+  return rc;
+}
diff --git a/cipher/dsa.c b/cipher/dsa.c
index 7652c19..ac2dee1 100644
--- a/cipher/dsa.c
+++ b/cipher/dsa.c
@@ -105,8 +105,8 @@ static gpg_err_code_t generate (DSA_secret_key *sk,
                                 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 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,
                    DSA_public_key *pkey);
 
@@ -152,7 +152,7 @@ test_keys (DSA_secret_key *sk, unsigned int qbits)
   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) )
@@ -537,17 +537,69 @@ 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;
 
-  /* Select a random k with 0 < k < q */
-  k = _gcry_dsa_gen_k (skey->q, GCRY_STRONG_RANDOM);
+  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;
+
+ 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 = gcry_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 );
@@ -566,6 +618,21 @@ 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;
 }
 
 
@@ -910,7 +977,7 @@ static gcry_err_code_t
 dsa_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey,
           int flags, int hashalgo)
 {
-  gcry_err_code_t err = GPG_ERR_NO_ERROR;
+  gcry_err_code_t rc;
   DSA_secret_key sk;
 
   (void)algo;
@@ -920,7 +987,7 @@ dsa_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey,
   if ((! data)
       || (! skey[0]) || (! skey[1]) || (! skey[2])
       || (! skey[3]) || (! skey[4]))
-    err = GPG_ERR_BAD_MPI;
+    rc = GPG_ERR_BAD_MPI;
   else
     {
       sk.p = skey[0];
@@ -930,24 +997,9 @@ dsa_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey,
       sk.x = skey[4];
       resarr[0] = mpi_alloc (mpi_get_nlimbs (sk.p));
       resarr[1] = mpi_alloc (mpi_get_nlimbs (sk.p));
-      if (mpi_is_opaque (data))
-        {
-          const void *abuf;
-          unsigned int abits;
-          gcry_mpi_t a;
-
-          abuf = gcry_mpi_get_opaque (data, &abits);
-          err = gcry_mpi_scan (&a, GCRYMPI_FMT_USG, abuf, abits/8, NULL);
-          if (!err)
-            {
-              sign (resarr[0], resarr[1], a, &sk);
-              gcry_mpi_release (a);
-            }
-        }
-      else
-        sign (resarr[0], resarr[1], data, &sk);
+      rc = sign (resarr[0], resarr[1], data, &sk, flags, hashalgo);
     }
-  return err;
+  return rc;
 }
 
 static gcry_err_code_t
@@ -973,13 +1025,18 @@ dsa_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
       if (mpi_is_opaque (hash))
         {
           const void *abuf;
-          unsigned int abits;
+          unsigned int abits, qbits;
           gcry_mpi_t a;
 
+          qbits = mpi_get_nbits (pk.q);
+
           abuf = gcry_mpi_get_opaque (hash, &abits);
-          err = gcry_mpi_scan (&a, GCRYMPI_FMT_USG, abuf, abits/8, NULL);
+          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);
+
               if (!verify (data[0], data[1], a, &pk))
                 err = GPG_ERR_BAD_SIGNATURE;
               gcry_mpi_release (a);
diff --git a/cipher/pubkey-internal.h b/cipher/pubkey-internal.h
index ae7e77b..9147cb2 100644
--- a/cipher/pubkey-internal.h
+++ b/cipher/pubkey-internal.h
@@ -22,6 +22,12 @@
 
 /*-- dsa-common.h --*/
 gcry_mpi_t _gcry_dsa_gen_k (gcry_mpi_t q, int security_level);
+gpg_err_code_t _gcry_dsa_gen_rfc6979_k (gcry_mpi_t *r_k,
+                                        gcry_mpi_t dsa_q, gcry_mpi_t dsa_x,
+                                        const unsigned char *h1,
+                                        unsigned int h1len,
+                                        int halgo,
+                                        unsigned int extraloops);
 
 
 /*-- ecc.c --*/
diff --git a/tests/Makefile.am b/tests/Makefile.am
index c18142e..871e32b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -20,7 +20,7 @@
 
 TESTS = version t-mpi-bit t-mpi-point prime basic \
         mpitests tsexp keygen pubkey hmac keygrip fips186-dsa aeswrap \
-	curves t-kdf pkcs1v2 random
+	curves t-kdf pkcs1v2 random dsa-rfc6979
 
 
 # The last test to run.
diff --git a/tests/dsa-rfc6979.c b/tests/dsa-rfc6979.c
new file mode 100644
index 0000000..6a9ac40
--- /dev/null
+++ b/tests/dsa-rfc6979.c
@@ -0,0 +1,475 @@
+/* dsa-rfc6979.c - Test for Deterministic DSA
+ * Copyright (C) 2008 Free Software Foundation, Inc.
+ * Copyright (C) 2013 g10 Code GmbH
+ *
+ * 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>
+
+#ifdef _GCRYPT_IN_LIBGCRYPT
+# include "../src/gcrypt-int.h"
+#else
+# include <gcrypt.h>
+#endif
+
+
+#define my_isascii(c) (!((c) & 0x80))
+#define digitp(p)   (*(p) >= '0' && *(p) <= '9')
+#define hexdigitp(a) (digitp (a)                     \
+                      || (*(a) >= 'A' && *(a) <= 'F')  \
+                      || (*(a) >= 'a' && *(a) <= 'f'))
+#define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
+                     *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
+#define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
+#define DIM(v)		     (sizeof(v)/sizeof((v)[0]))
+#define DIMof(type,member)   DIM(((type *)0)->member)
+
+static int verbose;
+static int error_count;
+
+static void
+info (const char *format, ...)
+{
+  va_list arg_ptr;
+
+  va_start (arg_ptr, format);
+  vfprintf (stderr, format, arg_ptr);
+  va_end (arg_ptr);
+}
+
+static void
+fail (const char *format, ...)
+{
+  va_list arg_ptr;
+
+  va_start (arg_ptr, format);
+  vfprintf (stderr, format, arg_ptr);
+  va_end (arg_ptr);
+  error_count++;
+}
+
+static void
+die (const char *format, ...)
+{
+  va_list arg_ptr;
+
+  va_start (arg_ptr, format);
+  vfprintf (stderr, format, arg_ptr);
+  va_end (arg_ptr);
+  exit (1);
+}
+
+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 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 *
+data_from_hex (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))
+        die ("error parsing hex string `%s'\n", string);
+      ((unsigned char*)buffer)[length++] = xtoi_2 (s);
+    }
+  *r_length = length;
+  return buffer;
+}
+
+
+static void
+extract_cmp_data (gcry_sexp_t sexp, const char *name, const char *expected)
+{
+  gcry_sexp_t l1;
+  const void *a;
+  size_t alen;
+  void *b;
+  size_t blen;
+
+  l1 = gcry_sexp_find_token (sexp, name, 0);
+  a = gcry_sexp_nth_data (l1, 1, &alen);
+  b = data_from_hex (expected, &blen);
+  if (!a)
+    fail ("parameter \"%s\" missing in key\n", name);
+  else if ( alen != blen || memcmp (a, b, alen) )
+    {
+      fail ("parameter \"%s\" does not match expected value\n", name);
+      if (verbose)
+        {
+          info ("expected: %s\n", expected);
+          show_sexp ("sexp: ", sexp);
+        }
+    }
+  gcry_free (b);
+  gcry_sexp_release (l1);
+}
+
+
+/* These test vectors are from RFC 6979.  */
+static void
+check_dsa_rfc6979 (void)
+{
+  static struct {
+    const char *name;
+    const char *key;
+  } keys[] = {
+    {
+      "DSA, 1024 bits",
+      "(private-key"
+      " (DSA"
+      " (p #86F5CA03DCFEB225063FF830A0C769B9DD9D6153AD91D7CE27F787C43278B447"
+      "     E6533B86B18BED6E8A48B784A14C252C5BE0DBF60B86D6385BD2F12FB763ED88"
+      "     73ABFD3F5BA2E0A8C0A59082EAC056935E529DAF7C610467899C77ADEDFC846C"
+      "     881870B7B19B2B58F9BE0521A17002E3BDD6B86685EE90B3D9A1B02B782B1779#)"
+      " (q #996F967F6C8E388D9E28D01E205FBA957A5698B1#)"
+      " (g #07B0F92546150B62514BB771E2A0C0CE387F03BDA6C56B505209FF25FD3C133D"
+      "     89BBCD97E904E09114D9A7DEFDEADFC9078EA544D2E401AEECC40BB9FBBF78FD"
+      "     87995A10A1C27CB7789B594BA7EFB5C4326A9FE59A070E136DB77175464ADCA4"
+      "     17BE5DCE2F40D10A46A3A3943F26AB7FD9C0398FF8C76EE0A56826A8A88F1DBD#)"
+      " (x #411602CB19A6CCC34494D79D98EF1E7ED5AF25F7#)"
+      " (y #5DF5E01DED31D0297E274E1691C192FE5868FEF9E19A84776454B100CF16F653"
+      "     92195A38B90523E2542EE61871C0440CB87C322FC4B4D2EC5E1E7EC766E1BE8D"
+      "     4CE935437DC11C3C8FD426338933EBFE739CB3465F4D3668C5E473508253B1E6"
+      "     82F65CBDC4FAE93C2EA212390E54905A86E2223170B44EAA7DA5DD9FFCFB7F3B#)"
+      " ))"
+    },
+    {
+      "DSA, 2048 bits",
+      "(private-key"
+      " (DSA"
+      " (p #9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48"
+      "     C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F"
+      "     FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5"
+      "     B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2"
+      "     35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41"
+      "     F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE"
+      "     92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15"
+      "     3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B#)"
+      " (q #F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F#)"
+      " (g #5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613"
+      "     D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4"
+      "     6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472"
+      "     085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5"
+      "     AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA"
+      "     3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71"
+      "     BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0"
+      "     DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7#)"
+      " (x #69C7548C21D0DFEA6B9A51C9EAD4E27C33D3B3F180316E5BCAB92C933F0E4DBC#)"
+      " (y #667098C654426C78D7F8201EAC6C203EF030D43605032C2F1FA937E5237DBD94"
+      "     9F34A0A2564FE126DC8B715C5141802CE0979C8246463C40E6B6BDAA2513FA61"
+      "     1728716C2E4FD53BC95B89E69949D96512E873B9C8F8DFD499CC312882561ADE"
+      "     CB31F658E934C0C197F2C4D96B05CBAD67381E7B768891E4DA3843D24D94CDFB"
+      "     5126E9B8BF21E8358EE0E0A30EF13FD6A664C0DCE3731F7FB49A4845A4FD8254"
+      "     687972A2D382599C9BAC4E0ED7998193078913032558134976410B89D2C171D1"
+      "     23AC35FD977219597AA7D15C1A9A428E59194F75C721EBCBCFAE44696A499AFA"
+      "     74E04299F132026601638CB87AB79190D4A0986315DA8EEC6561C938996BEADF#)"
+      " ))"
+    },
+    { NULL }
+  };
+
+  static struct {
+    const char *keyname;
+    const char *name;
+    const char *hashname;
+    const char *message;
+    const char *k, *r, *s;
+  } tests[] = {
+    {
+      "DSA, 1024 bits",
+      "With SHA-1, message = \"sample\"",
+      "sha1", "sample",
+      "7BDB6B0FF756E1BB5D53583EF979082F9AD5BD5B",
+      "2E1A0C2562B2912CAAF89186FB0F42001585DA55",
+      "29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5"
+    },
+    {
+      "DSA, 1024 bits",
+      "With SHA-224, message = \"sample\"",
+      "sha224", "sample",
+      "562097C06782D60C3037BA7BE104774344687649",
+      "4BC3B686AEA70145856814A6F1BB53346F02101E",
+      "410697B92295D994D21EDD2F4ADA85566F6F94C1"
+    },
+    {
+      "DSA, 1024 bits",
+      "With SHA-256, message = \"sample\"",
+      "sha256", "sample",
+      "519BA0546D0C39202A7D34D7DFA5E760B318BCFB",
+      "81F2F5850BE5BC123C43F71A3033E9384611C545",
+      "4CDD914B65EB6C66A8AAAD27299BEE6B035F5E89"
+    },
+    {
+      "DSA, 1024 bits",
+      "With SHA-384, message = \"sample\"",
+      "sha384", "sample",
+      "95897CD7BBB944AA932DBC579C1C09EB6FCFC595",
+      "07F2108557EE0E3921BC1774F1CA9B410B4CE65A",
+      "54DF70456C86FAC10FAB47C1949AB83F2C6F7595"
+    },
+    {
+      "DSA, 1024 bits",
+      "With SHA-512, message = \"sample\"",
+      "sha512", "sample",
+      "09ECE7CA27D0F5A4DD4E556C9DF1D21D28104F8B",
+      "16C3491F9B8C3FBBDD5E7A7B667057F0D8EE8E1B",
+      "02C36A127A7B89EDBB72E4FFBC71DABC7D4FC69C"
+    },
+    {
+      "DSA, 1024 bits",
+      "With SHA-1, message = \"test\"",
+      "sha1", "test",
+      "5C842DF4F9E344EE09F056838B42C7A17F4A6433",
+      "42AB2052FD43E123F0607F115052A67DCD9C5C77",
+      "183916B0230D45B9931491D4C6B0BD2FB4AAF088"
+    },
+    {
+      "DSA, 1024 bits",
+      "With SHA-224, message = \"test\"",
+      "sha224", "test",
+      "4598B8EFC1A53BC8AECD58D1ABBB0C0C71E67297",
+      "6868E9964E36C1689F6037F91F28D5F2C30610F2",
+      "49CEC3ACDC83018C5BD2674ECAAD35B8CD22940F"
+    },
+    {
+      "DSA, 1024 bits",
+      "With SHA-256, message = \"test\"",
+      "sha256", "test",
+      "5A67592E8128E03A417B0484410FB72C0B630E1A",
+      "22518C127299B0F6FDC9872B282B9E70D0790812",
+      "6837EC18F150D55DE95B5E29BE7AF5D01E4FE160"
+    },
+    {
+      "DSA, 1024 bits",
+      "With SHA-384, message = \"test\"",
+      "sha384", "test",
+      "220156B761F6CA5E6C9F1B9CF9C24BE25F98CD89",
+      "854CF929B58D73C3CBFDC421E8D5430CD6DB5E66",
+      "91D0E0F53E22F898D158380676A871A157CDA622"
+    },
+    {
+      "DSA, 1024 bits",
+      "With SHA-512, message = \"test\"",
+      "sha512", "test",
+      "65D2C2EEB175E370F28C75BFCDC028D22C7DBE9C",
+      "8EA47E475BA8AC6F2D821DA3BD212D11A3DEB9A0",
+      "7C670C7AD72B6C050C109E1790008097125433E8"
+    },
+    {
+      "DSA, 2048 bits",
+      "With SHA-1, message = \"sample\"",
+      "sha1", "sample",
+      "888FA6F7738A41BDC9846466ABDB8174C0338250AE50CE955CA16230F9CBD53E",
+      "3A1B2DBD7489D6ED7E608FD036C83AF396E290DBD602408E8677DAABD6E7445A",
+      "D26FCBA19FA3E3058FFC02CA1596CDBB6E0D20CB37B06054F7E36DED0CDBBCCF"
+    },
+    {
+      "DSA, 2048 bits",
+      "With SHA-224, message = \"sample\"",
+      "sha224", "sample",
+      "BC372967702082E1AA4FCE892209F71AE4AD25A6DFD869334E6F153BD0C4D806",
+      "DC9F4DEADA8D8FF588E98FED0AB690FFCE858DC8C79376450EB6B76C24537E2C",
+      "A65A9C3BC7BABE286B195D5DA68616DA8D47FA0097F36DD19F517327DC848CEC"
+    },
+    {
+      "DSA, 2048 bits",
+      "With SHA-256, message = \"sample\"",
+      "sha256", "sample",
+      "8926A27C40484216F052F4427CFD5647338B7B3939BC6573AF4333569D597C52",
+      "EACE8BDBBE353C432A795D9EC556C6D021F7A03F42C36E9BC87E4AC7932CC809",
+      "7081E175455F9247B812B74583E9E94F9EA79BD640DC962533B0680793A38D53"
+    },
+    {
+      "DSA, 2048 bits",
+      "With SHA-384, message = \"sample\"",
+      "sha384", "sample",
+      "C345D5AB3DA0A5BCB7EC8F8FB7A7E96069E03B206371EF7D83E39068EC564920",
+      "B2DA945E91858834FD9BF616EBAC151EDBC4B45D27D0DD4A7F6A22739F45C00B",
+      "19048B63D9FD6BCA1D9BAE3664E1BCB97F7276C306130969F63F38FA8319021B"
+    },
+    {
+      "DSA, 2048 bits",
+      "With SHA-512, message = \"sample\"",
+      "sha512", "sample",
+      "5A12994431785485B3F5F067221517791B85A597B7A9436995C89ED0374668FC",
+      "2016ED092DC5FB669B8EFB3D1F31A91EECB199879BE0CF78F02BA062CB4C942E",
+      "D0C76F84B5F091E141572A639A4FB8C230807EEA7D55C8A154A224400AFF2351"
+    },
+    {
+      "DSA, 2048 bits",
+      "With SHA-1, message = \"test\"",
+      "sha1", "test",
+      "6EEA486F9D41A037B2C640BC5645694FF8FF4B98D066A25F76BE641CCB24BA4F",
+      "C18270A93CFC6063F57A4DFA86024F700D980E4CF4E2CB65A504397273D98EA0",
+      "414F22E5F31A8B6D33295C7539C1C1BA3A6160D7D68D50AC0D3A5BEAC2884FAA"
+    },
+    {
+      "DSA, 2048 bits",
+      "With SHA-224, message = \"test\"",
+      "sha224", "test",
+      "06BD4C05ED74719106223BE33F2D95DA6B3B541DAD7BFBD7AC508213B6DA6670",
+      "272ABA31572F6CC55E30BF616B7A265312018DD325BE031BE0CC82AA17870EA3",
+      "E9CC286A52CCE201586722D36D1E917EB96A4EBDB47932F9576AC645B3A60806"
+    },
+    {
+      "DSA, 2048 bits",
+      "With SHA-256, message = \"test\"",
+      "sha256", "test",
+      "1D6CE6DDA1C5D37307839CD03AB0A5CBB18E60D800937D67DFB4479AAC8DEAD7",
+      "8190012A1969F9957D56FCCAAD223186F423398D58EF5B3CEFD5A4146A4476F0",
+      "7452A53F7075D417B4B013B278D1BB8BBD21863F5E7B1CEE679CF2188E1AB19E"
+    },
+    {
+      "DSA, 2048 bits",
+      "With SHA-384, message = \"test\"",
+      "sha384", "test",
+      "206E61F73DBE1B2DC8BE736B22B079E9DACD974DB00EEBBC5B64CAD39CF9F91C",
+      "239E66DDBE8F8C230A3D071D601B6FFBDFB5901F94D444C6AF56F732BEB954BE",
+      "6BD737513D5E72FE85D1C750E0F73921FE299B945AAD1C802F15C26A43D34961"
+    },
+    {
+      "DSA, 2048 bits",
+      "With SHA-512, message = \"test\"",
+      "sha512", "test",
+      "AFF1651E4CD6036D57AA8B2A05CCF1A9D5A40166340ECBBDC55BE10B568AA0AA",
+      "89EC4BB1400ECCFF8E7D9AA515CD1DE7803F2DAFF09693EE7FD1353E90A68307",
+      "C9F0BDABCC0D880BB137A994CC7F3980CE91CC10FAF529FC46565B15CEA854E1"
+    },
+    { NULL }
+  };
+
+  gpg_error_t err;
+  int tno, i, hashalgo;
+  gcry_sexp_t seckey, data, sig;
+  unsigned char digest[64];
+  int digestlen;
+
+  for (tno = 0; tests[tno].keyname; tno++)
+    {
+      if (verbose)
+        info ("Test %d: %s. %s.\n", tno, tests[tno].keyname, tests[tno].name);
+
+      {
+        for (i=0; keys[i].name; i++)
+          if (!strcmp (tests[tno].keyname, keys[i].name))
+            break;
+        if (!keys[i].name)
+          die ("Key '%s' used by test '%s' not found\n",
+               tests[tno].keyname, tests[tno].name);
+
+        err = gcry_sexp_new (&seckey, keys[i].key, 0, 1);
+        if (err)
+          die ("reading key failed: %s\n", gpg_strerror (err));
+      }
+
+      hashalgo = gcry_md_map_name (tests[tno].hashname);
+      if (!hashalgo)
+        die ("hash with name '%s' is not supported\n", tests[tno].hashname);
+
+      digestlen = gcry_md_get_algo_dlen (hashalgo);
+      if (digestlen > sizeof digest)
+        die ("internal error: digest does not fit into our buffer\n");
+
+      gcry_md_hash_buffer (hashalgo, digest,
+                           tests[tno].message, strlen (tests[tno].message));
+
+      err = gcry_sexp_build (&data, NULL,
+                             "(data "
+                             " (flags rfc6979)"
+                             " (hash %s %b))",
+                             tests[tno].hashname, digestlen, digest);
+      if (err)
+        die ("building data sexp failed: %s\n", gpg_strerror (err));
+
+      err = gcry_pk_sign (&sig, data, seckey);
+      if (err)
+        fail ("signing failed: %s\n", gpg_strerror (err));
+
+      extract_cmp_data (sig, "r", tests[tno].r);
+      extract_cmp_data (sig, "s", tests[tno].s);
+
+      err = gcry_pk_verify (sig, data, seckey);
+      if (err)
+        fail ("verification failed: %s\n", gpg_strerror (err));
+
+
+      gcry_sexp_release (sig);
+      gcry_sexp_release (data);
+      gcry_sexp_release (seckey);
+    }
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+  int debug = 0;
+
+  if (argc > 1 && !strcmp (argv[1], "--verbose"))
+    verbose = 1;
+  else if (argc > 1 && !strcmp (argv[1], "--debug"))
+    {
+      verbose = 2;
+      debug = 1;
+    }
+
+  gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+  /* Check that we test exactly our version - including the patchlevel.  */
+  if (strcmp (GCRYPT_VERSION, gcry_check_version (NULL)))
+    die ("version mismatch; pgm=%s, library=%s\n",
+         GCRYPT_VERSION,gcry_check_version (NULL));
+  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+  if (debug)
+    gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
+  /* No valuable keys are create, so we can speed up our RNG. */
+  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+
+  check_dsa_rfc6979 ();
+
+  return error_count ? 1 : 0;
+}

commit b72d312ad11887fc416aa821786f6bdb663c0f4a
Author: Werner Koch <wk at gnupg.org>
Date:   Fri Jul 26 19:22:36 2013 +0200

    Allow the use of a private-key s-expression with gcry_pk_verify.
    
    * cipher/pubkey.c (sexp_to_key): Fallback to private key.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index 606cedf..b540bd5 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -2022,9 +2022,14 @@ sexp_to_key (gcry_sexp_t sexp, int want_private, int use,
   pk_extra_spec_t *extraspec;
   int is_ecc;
 
-  /* Check that the first element is valid.  */
+  /* Check that the first element is valid.  If we are looking for a
+     public key but a private key was supplied, we allow the use of
+     the private key anyway.  The rationale for this is that the
+     private key is a superset of the public key. */
   list = gcry_sexp_find_token (sexp,
                                want_private? "private-key":"public-key", 0);
+  if (!list && !want_private)
+    list = gcry_sexp_find_token (sexp, "private-key", 0);
   if (!list)
     return GPG_ERR_INV_OBJ; /* Does not contain a key object.  */
 

-----------------------------------------------------------------------

Summary of changes:
 cipher/dsa-common.c      |  268 ++++++++++++++++++++++++++-
 cipher/dsa.c             |  115 +++++++++---
 cipher/pubkey-internal.h |    6 +
 cipher/pubkey.c          |    7 +-
 tests/Makefile.am        |    2 +-
 tests/dsa-rfc6979.c      |  475 ++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 840 insertions(+), 33 deletions(-)
 create mode 100644 tests/dsa-rfc6979.c


hooks/post-receive
-- 
The GNU crypto library
http://git.gnupg.org




More information about the Gnupg-commits mailing list