[svn] GnuPG - r4120 - trunk/g10

svn author dshaw cvs at cvs.gnupg.org
Thu Apr 20 23:32:45 CEST 2006


Author: dshaw
Date: 2006-04-20 23:32:42 +0200 (Thu, 20 Apr 2006)
New Revision: 4120

Modified:
   trunk/g10/ChangeLog
   trunk/g10/gpg.c
   trunk/g10/options.h
   trunk/g10/pkclist.c
   trunk/g10/sign.c
Log:
* options.h, gpg.c (main): Add --enable-dsa2 and --disable-dsa2. Defaults
to disable.

* pkclist.c (algo_available): If --enable-dsa2 is set, we're allowed to
truncate hashes to fit DSA keys.

* sign.c (match_dsa_hash): New.  Return the best match hash for a given q
size. (do_sign, hash_for, sign_file): When signing with a DSA key, if it
has q==160, assume it is an old DSA key and don't allow truncation unless
--enable-dsa2 is also set.  q!=160 always allows truncation since they
must be DSA2 keys. (make_keysig_packet): If the user doesn't specify a
--cert-digest-algo, use match_dsa_hash to pick the best hash for key
signatures.


Modified: trunk/g10/ChangeLog
===================================================================
--- trunk/g10/ChangeLog	2006-04-20 21:11:56 UTC (rev 4119)
+++ trunk/g10/ChangeLog	2006-04-20 21:32:42 UTC (rev 4120)
@@ -1,3 +1,21 @@
+2006-04-20  David Shaw  <dshaw at jabberwocky.com>
+
+	* options.h, gpg.c (main): Add --enable-dsa2 and --disable-dsa2.
+	Defaults to disable.
+
+	* pkclist.c (algo_available): If --enable-dsa2 is set, we're
+	allowed to truncate hashes to fit DSA keys.
+
+	* sign.c (match_dsa_hash): New.  Return the best match hash for a
+	given q size.
+	(do_sign, hash_for, sign_file): When signing with a DSA key, if it
+	has q==160, assume it is an old DSA key and don't allow truncation
+	unless --enable-dsa2 is also set.  q!=160 always allows truncation
+	since they must be DSA2 keys.
+	(make_keysig_packet): If the user doesn't specify a
+	--cert-digest-algo, use match_dsa_hash to pick the best hash for
+	key signatures.
+
 2006-04-19  David Shaw  <dshaw at jabberwocky.com>
 
 	* gpg.c (print_mds), armor.c (armor_filter, parse_hash_header):

Modified: trunk/g10/gpg.c
===================================================================
--- trunk/g10/gpg.c	2006-04-20 21:11:56 UTC (rev 4119)
+++ trunk/g10/gpg.c	2006-04-20 21:32:42 UTC (rev 4120)
@@ -362,6 +362,8 @@
     oAutoKeyLocate,
     oNoAutoKeyLocate,
     oAllowMultisigVerification,
+    oEnableDSA2,
+    oDisableDSA2,
 
     oNoop
   };
@@ -699,6 +701,8 @@
     { oDebugCCIDDriver, "debug-ccid-driver", 0, "@"},
 #endif
     { oAllowMultisigVerification, "allow-multisig-verification", 0, "@"},
+    { oEnableDSA2, "enable-dsa2", 0, "@"},
+    { oDisableDSA2, "disable-dsa2", 0, "@"},
 
     /* These two are aliases to help users of the PGP command line
        product use gpg with minimal pain.  Many commands are common
@@ -2659,6 +2663,9 @@
             opt.allow_multisig_verification = 1;
             break;
 
+	  case oEnableDSA2: opt.flags.dsa2=1; break;
+	  case oDisableDSA2: opt.flags.dsa2=0; break;
+
 	  case oNoop: break;
 
 	  default : pargs.err = configfp? 1:2; break;

Modified: trunk/g10/options.h
===================================================================
--- trunk/g10/options.h	2006-04-20 21:11:56 UTC (rev 4119)
+++ trunk/g10/options.h	2006-04-20 21:32:42 UTC (rev 4120)
@@ -222,6 +222,7 @@
     unsigned int require_cross_cert:1;
     unsigned int use_embedded_filename:1;
     unsigned int utf8_filename:1;
+    unsigned int dsa2:1;
   } flags;
 
   /* Linked list of ways to find a key if the key isn't on the local

Modified: trunk/g10/pkclist.c
===================================================================
--- trunk/g10/pkclist.c	2006-04-20 21:11:56 UTC (rev 4119)
+++ trunk/g10/pkclist.c	2006-04-20 21:32:42 UTC (rev 4120)
@@ -1,6 +1,6 @@
 /* pkclist.c
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
- *               2004, 2005 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ *               2006 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -1210,8 +1210,20 @@
     }
   else if( preftype == PREFTYPE_HASH )
     {
-      if(hint && ((*(int *)hint) != md_digest_length(algo)))
-	return 0;
+      if(hint)
+	{
+	  if(opt.flags.dsa2)
+	    {
+	      /* If --enable-dsa2 is set, then we'll accept a hash
+		 that is larger than we need.  If --enable-dsa2 is not
+		 set, then we won't accept any hash that isn't exactly
+		 the right size. */
+	      if((*(int *)hint) > md_digest_length(algo))
+		return 0;
+	    }
+	  else if(((*(int *)hint) != md_digest_length(algo)))
+	    return 0;
+	}
 
       if((PGP6 || PGP7) && (algo != DIGEST_ALGO_MD5
 			    && algo != DIGEST_ALGO_SHA1

Modified: trunk/g10/sign.c
===================================================================
--- trunk/g10/sign.c	2006-04-20 21:11:56 UTC (rev 4119)
+++ trunk/g10/sign.c	2006-04-20 21:32:42 UTC (rev 4120)
@@ -319,10 +319,15 @@
       }
     else 
       {
-	/* TODO: remove this check in the future once all the
-	   variable-q DSA stuff makes it into the standard. */
-	if(!opt.expert
-	   && sk->pubkey_algo==PUBKEY_ALGO_DSA
+	/* If it's a DSA key, and q is 160 bits, it might be an
+	   old-style DSA key.  If the hash doesn't match the q, fail
+	   unless --enable-dsa2 is set.  If the q isn't 160 bits, then
+	   allow any hash since it must be a DSA2 key (if the hash is
+	   too small, we'll fail in encode_md_value). */
+
+	if(sk->pubkey_algo==PUBKEY_ALGO_DSA
+	   && (mpi_get_nbits(sk->skey[1])/8)==20
+	   && !opt.flags.dsa2
 	   && md_digest_length(digest_algo)!=20)
 	  {
 	    log_error(_("DSA requires the use of a 160 bit hash algorithm\n"));
@@ -384,6 +389,29 @@
     return rc;
 }
 
+static int
+match_dsa_hash(unsigned int qbytes)
+{
+  if(qbytes<=20)
+    return DIGEST_ALGO_SHA1;
+#ifdef USE_SHA256
+  if(qbytes<=28)
+    return DIGEST_ALGO_SHA224;
+  if(qbytes<=32)
+    return DIGEST_ALGO_SHA256;
+#endif
+#ifdef USE_SHA512
+  if(qbytes<=48)
+    return DIGEST_ALGO_SHA384;
+  if(qbytes<=64)
+    return DIGEST_ALGO_SHA512;
+#endif
+  return DEFAULT_DIGEST_ALGO;
+  /* DEFAULT_DIGEST_ALGO will certainly fail, but it's the best wrong
+     answer we have if the larger SHAs aren't there. */
+}
+
+
 /*
   First try --digest-algo.  If that isn't set, see if the recipient
   has a preferred algorithm (which is also filtered through
@@ -405,21 +433,50 @@
     return opt.def_digest_algo;
   else if( recipient_digest_algo )
     return recipient_digest_algo;
-  else if(sk->pubkey_algo==PUBKEY_ALGO_DSA
-	  || (sk->is_protected && sk->protect.s2k.mode==1002))
+  else if(sk->pubkey_algo==PUBKEY_ALGO_DSA)
     {
-      /* The sk lives on a smartcard, or it's a DSA key.  DSA requires
-	 a 160-bit hash, and current smartcards only handle SHA-1 and
-	 RIPEMD/160 (i.e. 160-bit hashes).  This is correct now, but
-	 may need revision as the cards add algorithms and/or DSA is
-	 expanded to use larger hashes. */
+      unsigned int qbytes=mpi_get_nbits(sk->skey[1])/8;
 
+      /* It's a DSA key, so find a hash that is the same size as q or
+	 larger.  If q is 160, assume it is an old DSA key and use a
+	 160-bit hash unless --enable-dsa2 is set, in which case act
+	 like a new DSA key that just happens to have a 160-bit q
+	 (i.e. allow truncation).  If q is not 160, by definition it
+	 must be a new DSA key. */
+
       if(opt.personal_digest_prefs)
 	{
 	  prefitem_t *prefs;
 
+	  if(qbytes!=20 || opt.flags.dsa2)
+	    {
+	      for(prefs=opt.personal_digest_prefs;prefs->type;prefs++)
+		if(md_digest_length(prefs->value)>=qbytes)
+		  return prefs->value;
+	    }
+	  else
+	    {
+	      for(prefs=opt.personal_digest_prefs;prefs->type;prefs++)
+		if(md_digest_length(prefs->value)==qbytes)
+		  return prefs->value;
+	    }
+	}
+
+      return match_dsa_hash(qbytes);
+    }
+  else if(sk->is_protected && sk->protect.s2k.mode==1002)
+    {
+      /* The sk lives on a smartcard, and current smartcards only
+	 handle SHA-1 and RIPEMD/160.  This is correct now, but may
+	 need revision as the cards add algorithms. */
+
+      if(opt.personal_digest_prefs)
+	{
+	  prefitem_t *prefs;
+
 	  for(prefs=opt.personal_digest_prefs;prefs->type;prefs++)
-	    if(md_digest_length(prefs->value)==20)
+	    if(prefs->value==DIGEST_ALGO_SHA1
+	       || prefs->value==DIGEST_ALGO_RMD160)
 	      return prefs->value;
 	}
 
@@ -822,23 +879,36 @@
 	    int hashlen=0,algo;
 
 	    /* Of course, if the recipient asks for something
-	       unreasonable (like a non-160-bit hash for DSA, for
-	       example), then don't do it.  Check all sk's - if any
-	       are DSA, then the hash must be 160-bit.  In the future
-	       this can be more complex with different hashes for each
-	       sk, but so long as there is only one signing algorithm
-	       with hash restrictions, this is ok. -dms */
+	       unreasonable (like a non-160-bit hash for DSA without
+	       --enable-dsa2, for example), then don't do it.  Check
+	       all sk's - if any are DSA, then the hash has
+	       restrictions.  In the future this can be more complex
+	       with different hashes for each sk, but so long as there
+	       is only one signing algorithm with hash restrictions,
+	       this is ok. -dms */
 
-	    /* Current smartcards only do 160-bit hashes as well.
-	       Note that this may well have to change as the cards add
-	       algorithms. */
-
 	    for( sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next )
-	      if(sk_rover->sk->pubkey_algo==PUBKEY_ALGO_DSA
-		 || (sk_rover->sk->is_protected
-		     && sk_rover->sk->protect.s2k.mode==1002))
-		hashlen=20;
+	      {
+		if(sk_rover->sk->pubkey_algo==PUBKEY_ALGO_DSA)
+		  {
+		    if(opt.flags.dsa2)
+		      hashlen=mpi_get_nbits(sk_rover->sk->skey[1])/8;
+		    else
+		      hashlen=20;
+		    break;
+		  }
+		else if(sk_rover->sk->is_protected
+			&& sk_rover->sk->protect.s2k.mode==1002)
+		  {
+		    /* Current smartcards only do 160-bit hashes.
+		       Note that this may well have to change as the
+		       cards add algorithms. */
 
+		    hashlen=20;
+		    break;
+		  }
+	      }
+
 	    if((algo=
 		select_algo_from_prefs(pk_list,PREFTYPE_HASH,-1,
 				       hashlen?&hashlen:NULL))>0)
@@ -1350,16 +1420,19 @@
       {
 	/* Basically, this means use SHA1 always unless it's a v3 RSA
 	   key making a v3 cert (use MD5), or the user specified
-	   something (use whatever they said).  They still must use a
-	   160-bit hash with DSA, or the signature will fail.  Note
-	   that this still allows the caller of make_keysig_packet to
-	   override the user setting if it must. */
+	   something (use whatever they said), or it's DSA (use the
+	   best match).  They still can't pick an inappropriate hash
+	   for DSA or the signature will fail.  Note that this still
+	   allows the caller of make_keysig_packet to override the
+	   user setting if it must. */
 
 	if(opt.cert_digest_algo)
 	  digest_algo=opt.cert_digest_algo;
 	else if(sk->pubkey_algo==PUBKEY_ALGO_RSA
 		&& pk->version<4 && sigversion<4)
 	  digest_algo = DIGEST_ALGO_MD5;
+	else if(sk->pubkey_algo==PUBKEY_ALGO_DSA)
+	  digest_algo = match_dsa_hash(mpi_get_nbits(sk->skey[1])/8);
 	else
 	  digest_algo = DIGEST_ALGO_SHA1;
       }




More information about the Gnupg-commits mailing list