[svn] GnuPG - r4487 - trunk/sm

svn author wk cvs at cvs.gnupg.org
Fri Apr 20 12:54:47 CEST 2007


Author: wk
Date: 2007-04-20 12:54:46 +0200 (Fri, 20 Apr 2007)
New Revision: 4487

Modified:
   trunk/sm/ChangeLog
   trunk/sm/certcheck.c
Log:
	* certcheck.c (do_encode_md): Add arg PKEY.  Add support for DSA2
	  and all ECDSA sizes.
        (get_dsa_qbits): New.
        (pk_algo_from_sexp): A key will never contain ecdsa as algorithm,
        so remove that.
      


Modified: trunk/sm/ChangeLog
===================================================================
--- trunk/sm/ChangeLog	2007-04-18 13:03:35 UTC (rev 4486)
+++ trunk/sm/ChangeLog	2007-04-20 10:54:46 UTC (rev 4487)
@@ -1,3 +1,11 @@
+2007-04-19  Werner Koch  <wk at g10code.com>
+
+	* certcheck.c (do_encode_md): Add arg PKEY.  Add support for DSA2
+	and all ECDSA sizes.
+	(get_dsa_qbits): New.
+	(pk_algo_from_sexp): A key will never contain ecdsa as algorithm,
+	so remove that.
+
 2007-04-18  Werner Koch  <wk at g10code.com>
 
 	* certcheck.c (do_encode_md): Support 160 bit ECDSA.

Modified: trunk/sm/certcheck.c
===================================================================
--- trunk/sm/certcheck.c	2007-04-18 13:03:35 UTC (rev 4486)
+++ trunk/sm/certcheck.c	2007-04-20 10:54:46 UTC (rev 4487)
@@ -35,10 +35,38 @@
 #include "keydb.h"
 #include "i18n.h"
 
+/* Return the number of bits of the Q parameter from the DSA key
+   KEY.  */
+static unsigned int
+get_dsa_qbits (gcry_sexp_t key)
+{
+  gcry_sexp_t l1, l2;
+  gcry_mpi_t q;
+  unsigned int nbits;
 
+  l1 = gcry_sexp_find_token (key, "public-key", 0);
+  if (!l1)
+    return 0; /* Does not contain a key object.  */
+  l2 = gcry_sexp_cadr (l1);
+  gcry_sexp_release  (l1);
+  l1 = gcry_sexp_find_token (l2, "q", 1);
+  gcry_sexp_release (l2);
+  if (!l1)
+    return 0; /* Invalid object.  */
+  q = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+  gcry_sexp_release (l1);
+  if (!q)
+    return 0; /* Missing value.  */
+  nbits = gcry_mpi_get_nbits (q);
+  gcry_mpi_release (q);
+
+  return nbits;
+}
+
+
 static int
 do_encode_md (gcry_md_hd_t md, int algo, int pkalgo, unsigned int nbits,
-              gcry_mpi_t *r_val)
+              gcry_sexp_t pkey, gcry_mpi_t *r_val)
 {
   int n;
   size_t nframe;
@@ -46,17 +74,54 @@
 
   if (pkalgo == GCRY_PK_DSA || pkalgo == GCRY_PK_ECDSA)
     {
+      unsigned int qbits;
+
+      if ( pkalgo == GCRY_PK_ECDSA )
+        qbits = gcry_pk_get_nbits (pkey);
+      else
+        qbits = get_dsa_qbits (pkey);
+
+      if ( (qbits%8) )
+	{
+	  log_error(_("DSA requires the hash length to be a"
+		      " multiple of 8 bits\n"));
+	  return gpg_error (GPG_ERR_INTERNAL);
+	}
+
+      /* Don't allow any Q smaller than 160 bits.  We don't want
+	 someone to issue signatures from a key with a 16-bit Q or
+	 something like that, which would look correct but allow
+	 trivial forgeries.  Yes, I know this rules out using MD5 with
+	 DSA. ;) */
+      if (qbits < 160)
+	{
+	  log_error (_("%s key uses an unsafe (%u bit) hash\n"),
+                     gcry_pk_algo_name (pkalgo), qbits);
+	  return gpg_error (GPG_ERR_INTERNAL);
+	}
+
+      /* Check if we're too short.  Too long is safe as we'll
+	 automatically left-truncate. */
       nframe = gcry_md_get_algo_dlen (algo);
-      if (nframe != 20)
+      if (nframe < qbits/8)
         {
-          log_error (_("DSA requires the use of a 160 bit hash algorithm\n"));
-          return gpg_error (GPG_ERR_INTERNAL);
+	  log_error (_("a %u bit hash is not valid for a %u bit %s key\n"),
+                     (unsigned int)nframe*8,
+                     gcry_pk_get_nbits (pkey), 
+                     gcry_pk_algo_name (pkalgo));
+          /* FIXME: we need to check the requirements for ECDSA.  */
+          if (nframe < 20 || pkalgo == GCRY_PK_DSA  )
+            return gpg_error (GPG_ERR_INTERNAL);
         }
+
       frame = xtrymalloc (nframe);
       if (!frame)
         return out_of_core ();
       memcpy (frame, gcry_md_read (md, algo), nframe);
       n = nframe;
+      /* Truncate.  */
+      if (n > qbits/8)
+        n = qbits/8;
     }
   else
     {
@@ -143,8 +208,6 @@
     algo = GCRY_PK_RSA;
   else if (n==3 && !memcmp (name, "dsa", 3))
     algo = GCRY_PK_DSA;
-  else if (n==5 && !memcmp (name, "ecdsa", 5))
-    algo = GCRY_PK_ECDSA;
   /* Because this function is called only for verification we can
      assume that ECC actually means ECDSA.  */
   else if (n==3 && !memcmp (name, "ecc", 3))
@@ -158,10 +221,9 @@
 }
 
 
-/*
-  Check the signature on CERT using the ISSUER-CERT.  This function
-  does only test the cryptographic signature and nothing else.  It is
-  assumed that the ISSUER_CERT is valid. */
+/* Check the signature on CERT using the ISSUER-CERT.  This function
+   does only test the cryptographic signature and nothing else.  It is
+   assumed that the ISSUER_CERT is valid. */
 int
 gpgsm_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert)
 {
@@ -249,7 +311,7 @@
     }
 
   rc = do_encode_md (md, algo, pk_algo_from_sexp (s_pkey),
-                     gcry_pk_get_nbits (s_pkey), &frame);
+                     gcry_pk_get_nbits (s_pkey), s_pkey, &frame);
   if (rc)
     {
       gcry_md_close (md);
@@ -322,7 +384,7 @@
 
 
   rc = do_encode_md (md, algo, pk_algo_from_sexp (s_pkey),
-                     gcry_pk_get_nbits (s_pkey), &frame);
+                     gcry_pk_get_nbits (s_pkey), s_pkey, &frame);
   if (rc)
     {
       gcry_sexp_release (s_sig);




More information about the Gnupg-commits mailing list