[Announce] Key validity bug in GnuPG 1.2.1 and earlier

David Shaw dshaw@jabberwocky.com
Sun May 4 04:44:12 2003


--OwLcNYc0lM97+oe1
Content-Type: multipart/mixed; boundary="5vNYLRcllDrimb99"
Content-Disposition: inline


--5vNYLRcllDrimb99
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

As part of the development of GnuPG 1.2.2, a bug was discovered in the
key validation code.  This bug causes keys with more than one user ID
to give all user IDs on the key the amount of validity given to the
most-valid key.

This bug does not impact any key with only one user ID.  Photo IDs
("user attribute IDs") do not count as an additional user ID for the
purposes of this bug.

For example, given a key with two user IDs:
   Alice <alice@example.com>
and
   Alice's other address <alice@corp.example.net>

If the encrypting user has a trust path to to the ID
alice@example.com, then this ID is fully valid, and there is no
warning message when encrypting to alice@example.com.

If the encrypting user has either an insufficient or no trust path to
the ID "alice@corp.example.net", then that ID is either not fully
valid, or not valid at all respectively.  There should be a warning
message given when encrypting to this other user ID ("it is not
certain this key belongs to the user named in the user ID / do you
want to encrypt to it anyway?"), but due to the bug, the invalid user
ID is accepted as valid and no warning message is given.

This bug has been fixed in the newly released GnuPG 1.2.2, and
upgrading is the recommended fix for this problem.  For those who
cannot upgrade for whatever reason, the attached patch fixes the
problem as well.  The patch should apply (perhaps with some offsets)
to GnuPG 1.2,1, 1.2.0, or 1.0.7.  Note that GnuPG 1.0.6 (and possibly
earlier) versions have the same problem, but these versions are too
old to successfully apply the patch.  If you are using GnuPG 1.0.6 or
earlier versions, please upgrade.

The GnuPG Team (David, Stefan, Timo and Werner)


--5vNYLRcllDrimb99
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="patch-gnupg-1.2.1-trustfix.txt"
Content-Transfer-Encoding: quoted-printable

Index: g10/trustdb.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvs/gnupg/gnupg/g10/trustdb.c,v
retrieving revision 1.89.2.1
diff -u -r1.89.2.1 trustdb.c
--- g10/trustdb.c	2 Oct 2002 21:56:03 -0000	1.89.2.1
+++ g10/trustdb.c	4 May 2003 01:12:38 -0000
@@ -808,16 +808,27 @@
   while (recno)
     {
       read_record (recno, &vrec, RECTYPE_VALID);
-      if ( validity < (vrec.r.valid.validity & TRUST_MASK) )
-        validity =3D (vrec.r.valid.validity & TRUST_MASK);
-      if ( namehash && !memcmp (vrec.r.valid.namehash, namehash, 20) )
-        break;
+      if(namehash)
+	{
+	  /* If namehash is given we return the trust for that user ID
+	     ONLY.  If the namehash is not found, then there is no
+	     validity at all (i.e. the user ID wasn't signed). */
+	  if(memcmp(vrec.r.valid.namehash,namehash,20)=3D=3D0)
+	    {
+	      validity=3D(vrec.r.valid.validity & TRUST_MASK);
+	      break;
+	    }
+	}
+      else
+	{
+	  /* If no namehash is given, we take the maximum validity
+	     over all user IDs */
+	  if ( validity < (vrec.r.valid.validity & TRUST_MASK) )
+	    validity =3D (vrec.r.valid.validity & TRUST_MASK);
+	}
       recno =3D vrec.r.valid.next;
     }
  =20
-  if (recno) /* okay, use the user ID associated one */
-    validity =3D (vrec.r.valid.validity & TRUST_MASK);
-
   if ( (trec.r.trust.ownertrust & TRUST_FLAG_DISABLED) )
     validity |=3D TRUST_FLAG_DISABLED;
=20
Index: g10/pkclist.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvs/gnupg/gnupg/g10/pkclist.c,v
retrieving revision 1.73.2.1
diff -u -r1.73.2.1 pkclist.c
--- g10/pkclist.c	17 Oct 2002 13:49:30 -0000	1.73.2.1
+++ g10/pkclist.c	4 May 2003 01:12:39 -0000
@@ -524,17 +524,23 @@
 	return 0;
=20
     if( !opt.batch && !rc ) {
-	char *p;
 	u32 keyid[2];
-	size_t n;
=20
 	keyid_from_pk( pk, keyid);
 	tty_printf( "%4u%c/%08lX %s \"",
 		  nbits_from_pk( pk ), pubkey_letter( pk->pubkey_algo ),
 		  (ulong)keyid[1], datestr_from_pk( pk ) );
-	p =3D get_user_id( keyid, &n );
-	tty_print_utf8_string( p, n ),
-	m_free(p);
+	/* If the pk was chosen by a particular user ID, this is the
+	   one to ask about. */
+	if(pk->user_id)
+	  tty_print_utf8_string(pk->user_id->name,pk->user_id->len);
+	else
+	  {
+	    size_t n;
+	    char *p =3D get_user_id( keyid, &n );
+	    tty_print_utf8_string( p, n );
+	    m_free(p);
+	  }
 	tty_printf("\"\n");
         print_fingerprint (pk, NULL, 2);
 	tty_printf("\n");
@@ -887,8 +893,27 @@
 		}
 		else {
 		    int trustlevel;
+		   =20
+		    /* Fill in the namehash so we can get the validity
+		       for this particular UID.  If we start using it
+		       in more places than here, it might be good to
+		       fill this in for all PKs. */
+=20
+		    if(pk->user_id)
+		      {
+			pk->namehash=3Dm_alloc(20);
+=20
+			if( pk->user_id->attrib_data )
+			  rmd160_hash_buffer (pk->namehash,
+					      pk->user_id->attrib_data,
+					      pk->user_id->attrib_len);
+			else
+			  rmd160_hash_buffer (pk->namehash,
+					      pk->user_id->name,
+					      pk->user_id->len );
+		      }
=20
-		    trustlevel =3D get_validity (pk, NULL);
+		    trustlevel =3D get_validity (pk, pk->namehash);
 		    if( (trustlevel & TRUST_FLAG_DISABLED) ) {
 			tty_printf(_("Public key is disabled.\n") );
 		    }
@@ -901,8 +926,6 @@
 			}
 			else {
 			    PK_LIST r;
-			    char *p;
-			    size_t n;
 			    u32 keyid[2];
=20
 			    keyid_from_pk( pk, keyid);
@@ -911,9 +934,16 @@
 				       pubkey_letter( pk->pubkey_algo ),
 				       (ulong)keyid[1],
 				       datestr_from_pk( pk ) );
-			    p =3D get_user_id( keyid, &n );
-			    tty_print_utf8_string( p, n );
-			    m_free(p);
+			    if(pk->user_id)
+			      tty_print_utf8_string(pk->user_id->name,
+						    pk->user_id->len);
+			    else
+			      {
+				size_t n;
+				char *p =3D get_user_id( keyid, &n );
+				tty_print_utf8_string( p, n );
+				m_free(p);
+			      }
 			    tty_printf("\"\n");
=20
 			    r =3D m_alloc( sizeof *r );
@@ -981,6 +1011,25 @@
 	    }
 	    else if( !(rc=3Dcheck_pubkey_algo2(pk->pubkey_algo, use )) ) {
 		int trustlevel;
+
+		/* Fill in the namehash so we can get the validity
+		   for this particular UID.  If we start using it
+		   in more places than here, it might be good to
+		   fill this in for all PKs. */
+=20
+		if(pk->user_id)
+		  {
+		    pk->namehash=3Dm_alloc(20);
+=20
+		    if( pk->user_id->attrib_data )
+		      rmd160_hash_buffer (pk->namehash,
+					  pk->user_id->attrib_data,
+					  pk->user_id->attrib_len);
+		    else
+		      rmd160_hash_buffer (pk->namehash,
+					  pk->user_id->name,
+					  pk->user_id->len );
+		  }
=20
 		trustlevel =3D get_validity (pk, pk->namehash);
 		if( (trustlevel & TRUST_FLAG_DISABLED) ) {

--5vNYLRcllDrimb99--

--OwLcNYc0lM97+oe1
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.3.2-cvs (GNU/Linux)
Comment: http://www.jabberwocky.com/david/keys.asc

iD8DBQE+tG5d4mZch0nhy8kRAtCZAJ0VnEX0CY0kIZzFuNu+jfMgbD2bMACfRey6
QqvErtdN8LUieDGnA3PIkb0=
=ndLi
-----END PGP SIGNATURE-----

--OwLcNYc0lM97+oe1--

_______________________________________________
Gnupg-announce mailing list
Gnupg-announce@gnupg.org
http://lists.gnupg.org/mailman/listinfo/gnupg-announce