pk: Allow the use of a hash element for DSA sign and verify.
authorWerner Koch <wk@gnupg.org>
Fri, 19 Jul 2013 16:14:38 +0000 (18:14 +0200)
committerWerner Koch <wk@gnupg.org>
Fri, 19 Jul 2013 16:14:38 +0000 (18:14 +0200)
* cipher/pubkey.c (pubkey_sign): Add arg ctx and pass it to the sign
module.
(gcry_pk_sign): Pass CTX to pubkey_sign.
(sexp_data_to_mpi): Add flag rfc6979 and code to alls hash with *DSA
* cipher/rsa.c (rsa_sign, rsa_verify): Return an error if an opaque
MPI is given for DATA/HASH.
* cipher/elgamal.c (elg_sign, elg_verify): Ditto.
* cipher/dsa.c (dsa_sign, dsa_verify): Convert a given opaque MPI.
* cipher/ecc.c (ecc_sign, ecc_verify): Ditto.
* tests/basic.c (check_pubkey_sign_ecdsa): Add a test for using a hash
element with DSA.
--

This patch allows the use of

  (data (flags raw)
    (hash sha256 #80112233445566778899AABBCCDDEEFF
                  000102030405060708090A0B0C0D0E0F#))

in addition to the old but more efficient

  (data (flags raw)
    (value #80112233445566778899AABBCCDDEEFF
            000102030405060708090A0B0C0D0E0F#))

for DSA and ECDSA.  With the hash element the flag "raw" must be
explicitly given because existing regression test code expects that
conflict error is return if no flags but a hash element is given.

Note that the hash algorithm name is currently not checked.  It may
eventually be used to cross-check the length of the provided hash
value.  It is suggested that the correct hash name is given - even if
a truncated hash value is used.

Finally this patch adds a way to pass the hash algorithm and flag
values to the signing module.  "rfc6979" as been implemented as a new
but not yet used flag.

Signed-off-by: Werner Koch <wk@gnupg.org>
cipher/dsa.c
cipher/ecc.c
cipher/elgamal.c
cipher/pubkey.c
cipher/rsa.c
tests/basic.c

index 55805e2..7652c19 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.
  *
@@ -539,7 +540,7 @@ check_secret_key( DSA_secret_key *sk )
    Make a DSA signature from HASH and put it into r and s.
  */
 static void
-sign(gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_secret_key *skey )
+sign (gcry_mpi_t r, gcry_mpi_t s, gcry_mpi_t hash, DSA_secret_key *skey )
 {
   gcry_mpi_t k;
   gcry_mpi_t kinv;
@@ -929,7 +930,22 @@ 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));
-      sign (resarr[0], resarr[1], data, &sk);
+      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);
     }
   return err;
 }
@@ -954,8 +970,26 @@ dsa_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
       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;
+      if (mpi_is_opaque (hash))
+        {
+          const void *abuf;
+          unsigned int abits;
+          gcry_mpi_t a;
+
+          abuf = gcry_mpi_get_opaque (hash, &abits);
+          err = gcry_mpi_scan (&a, GCRYMPI_FMT_USG, abuf, abits/8, NULL);
+          if (!err)
+            {
+              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;
 }
index e4b1799..725dfbe 100644 (file)
@@ -1347,7 +1347,24 @@ ecc_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey,
 
   resarr[0] = mpi_alloc (mpi_get_nlimbs (sk.E.p));
   resarr[1] = mpi_alloc (mpi_get_nlimbs (sk.E.p));
-  err = sign (data, &sk, resarr[0], resarr[1]);
+
+  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)
+        {
+          err = sign (a, &sk, resarr[0], resarr[1]);
+          gcry_mpi_release (a);
+        }
+    }
+  else
+    err = sign (data, &sk, resarr[0], resarr[1]);
+
   if (err)
     {
       mpi_free (resarr[0]);
@@ -1394,7 +1411,22 @@ ecc_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
       return err;
     }
 
-  err = verify (hash, &pk, data[0], data[1]);
+  if (mpi_is_opaque (hash))
+    {
+      const void *abuf;
+      unsigned int abits;
+      gcry_mpi_t a;
+
+      abuf = gcry_mpi_get_opaque (hash, &abits);
+      err = gcry_mpi_scan (&a, GCRYMPI_FMT_USG, abuf, abits/8, NULL);
+      if (!err)
+        {
+          err = verify (a, &pk, data[0], data[1]);
+          gcry_mpi_release (a);
+        }
+    }
+  else
+    err = verify (hash, &pk, data[0], data[1]);
 
   point_free (&pk.E.G);
   point_free (&pk.Q);
index 128dd99..b40d132 100644 (file)
@@ -763,6 +763,9 @@ elg_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey,
   (void)flags;
   (void)hashalgo;
 
+  if (mpi_is_opaque (data))
+    return GPG_ERR_INV_DATA;
+
   if ((! data)
       || (! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3]))
     err = GPG_ERR_BAD_MPI;
@@ -792,6 +795,9 @@ elg_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
   (void)cmp;
   (void)opaquev;
 
+  if (mpi_is_opaque (hash))
+    return GPG_ERR_INV_DATA;
+
   if ((! data[0]) || (! data[1]) || (! hash)
       || (! pkey[0]) || (! pkey[1]) || (! pkey[2]))
     err = GPG_ERR_BAD_MPI;
index 23a4358..606cedf 100644 (file)
@@ -37,7 +37,8 @@ static gcry_err_code_t pubkey_decrypt (int algo, gcry_mpi_t *result,
                                        gcry_mpi_t *data, gcry_mpi_t *skey,
                                        int flags);
 static gcry_err_code_t pubkey_sign (int algo, gcry_mpi_t *resarr,
-                                    gcry_mpi_t hash, gcry_mpi_t *skey);
+                                    gcry_mpi_t hash, gcry_mpi_t *skey,
+                                    struct pk_encoding_ctx *ctx);
 static gcry_err_code_t pubkey_verify (int algo, gcry_mpi_t hash,
                                       gcry_mpi_t *data, gcry_mpi_t *pkey,
                                     int (*cmp) (void *, gcry_mpi_t),
@@ -712,7 +713,7 @@ pubkey_decrypt (int algorithm, gcry_mpi_t *result, gcry_mpi_t *data,
  */
 static gcry_err_code_t
 pubkey_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
-             gcry_mpi_t *skey)
+             gcry_mpi_t *skey, struct pk_encoding_ctx *ctx)
 {
   gcry_pk_spec_t *pubkey;
   gcry_module_t module;
@@ -732,7 +733,8 @@ pubkey_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
   if (module)
     {
       pubkey = (gcry_pk_spec_t *) module->spec;
-      rc = pubkey->sign (algorithm, resarr, data, skey, 0, 0);
+      rc = pubkey->sign (algorithm, resarr, data, skey,
+                         ctx->flags, ctx->hash_algo);
       _gcry_module_release (module);
       goto ready;
     }
@@ -2477,7 +2479,7 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo,
    (<mpi>)
    or
    (data
-    [(flags [raw, pkcs1, oaep, pss, no-blinding])]
+    [(flags [raw, direct, pkcs1, oaep, pss, no-blinding, rfc6979])]
     [(hash <algo> <value>)]
     [(value <text>)]
     [(hash-algo <algo>)]
@@ -2504,8 +2506,9 @@ sexp_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi,
   int i;
   size_t n;
   const char *s;
-  int unknown_flag=0;
+  int unknown_flag = 0;
   int parsed_flags = 0;
+  int explicit_raw = 0;
 
   *ret_mpi = NULL;
   ldata = gcry_sexp_find_token (input, "data", 0);
@@ -2525,9 +2528,14 @@ sexp_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi,
             s = gcry_sexp_nth_data (lflags, i, &n);
             if (!s)
               ; /* not a data element*/
+           else if (n == 7 && ! memcmp (s, "rfc6979", 7))
+             parsed_flags |= PUBKEY_FLAG_RFC6979;
             else if ( n == 3 && !memcmp (s, "raw", 3)
                       && ctx->encoding == PUBKEY_ENC_UNKNOWN)
-              ctx->encoding = PUBKEY_ENC_RAW;
+              {
+                ctx->encoding = PUBKEY_ENC_RAW;
+                explicit_raw = 1;
+              }
             else if ( n == 5 && !memcmp (s, "pkcs1", 5)
                       && ctx->encoding == PUBKEY_ENC_UNKNOWN)
               ctx->encoding = PUBKEY_ENC_PKCS1;
@@ -2557,8 +2565,47 @@ sexp_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi,
     rc = GPG_ERR_INV_OBJ; /* none or both given */
   else if (unknown_flag)
     rc = GPG_ERR_INV_FLAG;
+  else if (ctx->encoding == PUBKEY_ENC_RAW && lhash
+           && (explicit_raw || (parsed_flags & PUBKEY_FLAG_RFC6979)))
+    {
+      /* Raw encoding along with a hash element.  This is commonly
+         used for DSA.  For better backward error compatibility we
+         allow this only if either the rfc6979 flag has been given or
+         the raw flags was explicitly given.  */
+      if (gcry_sexp_length (lhash) != 3)
+        rc = GPG_ERR_INV_OBJ;
+      else if ( !(s=gcry_sexp_nth_data (lhash, 1, &n)) || !n )
+        rc = GPG_ERR_INV_OBJ;
+      else
+        {
+          void *value;
+          size_t valuelen;
+
+         ctx->hash_algo = get_hash_algo (s, n);
+          if (!ctx->hash_algo)
+            rc = GPG_ERR_DIGEST_ALGO;
+          else if (!(value=gcry_sexp_nth_buffer (lhash, 2, &valuelen)))
+            rc = GPG_ERR_INV_OBJ;
+          else if ((valuelen * 8) < valuelen)
+            {
+              gcry_free (value);
+              rc = GPG_ERR_TOO_LARGE;
+            }
+          else
+            *ret_mpi = gcry_mpi_set_opaque (NULL, value, valuelen*8);
+        }
+    }
   else if (ctx->encoding == PUBKEY_ENC_RAW && lvalue)
     {
+      /* RFC6969 may only be used with the a hash value and not the
+         MPI based value.  */
+      if (parsed_flags & PUBKEY_FLAG_RFC6979)
+        {
+          rc = GPG_ERR_CONFLICT;
+          goto leave;
+        }
+
+      /* Get the value */
       *ret_mpi = gcry_sexp_nth_mpi (lvalue, 1, GCRYMPI_FMT_USG);
       if (!*ret_mpi)
         rc = GPG_ERR_INV_OBJ;
@@ -3214,7 +3261,7 @@ gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey)
       rc = gpg_err_code_from_syserror ();
       goto leave;
     }
-  rc = pubkey_sign (module->mod_id, result, hash, skey);
+  rc = pubkey_sign (module->mod_id, result, hash, skey, &ctx);
   if (rc)
     goto leave;
 
index 4787f81..c9fcebf 100644 (file)
@@ -700,7 +700,7 @@ stronger_key_check ( RSA_secret_key *skey )
  * Where m is OUTPUT, c is INPUT and d,n,p,q,u are elements of SKEY.
  */
 static void
-secret(gcry_mpi_t output, gcry_mpi_t input, RSA_secret_key *skey )
+secret (gcry_mpi_t output, gcry_mpi_t input, RSA_secret_key *skey )
 {
   if (!skey->p || !skey->q || !skey->u)
     {
@@ -1002,6 +1002,9 @@ rsa_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey,
   (void)flags;
   (void)hashalgo;
 
+  if (mpi_is_opaque (data))
+    return GPG_ERR_INV_DATA;
+
   sk.n = skey[0];
   sk.e = skey[1];
   sk.d = skey[2];
@@ -1028,6 +1031,9 @@ rsa_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
   (void)cmp;
   (void)opaquev;
 
+  if (mpi_is_opaque (hash))
+    return GPG_ERR_INV_DATA;
+
   pk.n = pkey[0];
   pk.e = pkey[1];
   result = gcry_mpi_new ( 160 );
index 88ae131..46e213c 100644 (file)
@@ -3073,6 +3073,14 @@ check_pubkey_sign_ecdsa (int n, gcry_sexp_t skey, gcry_sexp_t pkey)
     int dummy;
   } datas[] =
     {
+      { 192,
+        "(data (flags raw)\n"
+        " (value #00112233445566778899AABBCCDDEEFF0001020304050607#))",
+        0,
+        "(data (flags raw)\n"
+        " (value #80112233445566778899AABBCCDDEEFF0001020304050607#))",
+        0
+      },
       { 256,
         "(data (flags raw)\n"
         " (value #00112233445566778899AABBCCDDEEFF"
@@ -3083,12 +3091,14 @@ check_pubkey_sign_ecdsa (int n, gcry_sexp_t skey, gcry_sexp_t pkey)
         /* */    "000102030405060708090A0B0C0D0E0F#))",
         0
       },
-      { 192,
+      { 256,
         "(data (flags raw)\n"
-        " (value #00112233445566778899AABBCCDDEEFF0001020304050607#))",
+        " (hash sha256 #00112233445566778899AABBCCDDEEFF"
+        /* */          "000102030405060708090A0B0C0D0E0F#))",
         0,
         "(data (flags raw)\n"
-        " (value #80112233445566778899AABBCCDDEEFF0001020304050607#))",
+        " (hash sha256 #80112233445566778899AABBCCDDEEFF"
+        /* */          "000102030405060708090A0B0C0D0E0F#))",
         0
       },
       { 0, NULL }