* trustdb.h, trustdb.c (mark_usable_uid_certs): Add flags for the
authorDavid Shaw <dshaw@jabberwocky.com>
Sun, 24 Apr 2005 18:35:30 +0000 (18:35 +0000)
committerDavid Shaw <dshaw@jabberwocky.com>
Sun, 24 Apr 2005 18:35:30 +0000 (18:35 +0000)
no-pubkey and chosen revocation cases.  (clean_uid): New function to
clean a user ID of unusable (as defined by mark_usable_uid_certs)
certs.

* keyedit.c (keyedit_menu, menu_clean_uids): Call it here for new
"clean" command that removes unusable sigs from a key.

g10/ChangeLog
g10/keyedit.c
g10/trustdb.c
g10/trustdb.h

index d0fa926..30f8939 100644 (file)
@@ -1,5 +1,13 @@
 2005-04-24  David Shaw  <dshaw@jabberwocky.com>
 
+       * trustdb.h, trustdb.c (mark_usable_uid_certs): Add flags for the
+       no-pubkey and chosen revocation cases.
+       (clean_uid): New function to clean a user ID of unusable (as
+       defined by mark_usable_uid_certs) certs.
+
+       * keyedit.c (keyedit_menu, menu_clean_uids): Call it here for new
+       "clean" command that removes unusable sigs from a key.
+
        * trustdb.h, keyedit.c (keyedit_menu, menu_select_uid_namehash):
        Allow specifying user ID via the namehash from --with-colons
        --fixed-list-mode --list-keys.  Suggested by Peter Palfrader.
index 7a00695..00499b3 100644 (file)
@@ -53,6 +53,7 @@ static void show_key_and_fingerprint( KBNODE keyblock );
 static int menu_adduid( KBNODE keyblock, KBNODE sec_keyblock, int photo );
 static void menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock );
 static int  menu_delsig( KBNODE pub_keyblock );
+static int menu_clean_uids(KBNODE keyblock);
 static void menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock );
 static int menu_addrevoker( KBNODE pub_keyblock,
                            KBNODE sec_keyblock, int sensitive );
@@ -1327,7 +1328,7 @@ enum cmdids
     cmdADDREVOKER, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF,
     cmdEXPIRE, cmdENABLEKEY, cmdDISABLEKEY, cmdSHOWPREF, cmdSETPREF,
     cmdPREFKS, cmdINVCMD, cmdSHOWPHOTO, cmdUPDTRUST, cmdCHKTRUST,
-    cmdADDCARDKEY, cmdKEYTOCARD, cmdBKUPTOCARD, cmdNOP
+    cmdADDCARDKEY, cmdKEYTOCARD, cmdBKUPTOCARD, cmdCLEAN, cmdNOP
   };
 
 static struct
@@ -1426,6 +1427,7 @@ static struct
     { "enable"  , cmdENABLEKEY , KEYEDIT_NOT_SK, N_("enable key") },
     { "disable" , cmdDISABLEKEY, KEYEDIT_NOT_SK, N_("disable key") },
     { "showphoto",cmdSHOWPHOTO , 0, N_("show selected photo IDs") },
+    { "clean",    cmdCLEAN     , KEYEDIT_NOT_SK, NULL },
     { NULL, cmdNONE, 0, NULL }
   };
 
@@ -1952,7 +1954,7 @@ keyedit_menu( const char *username, STRLIST locusr,
            {
              int sensitive=0;
 
-             if(arg_string && ascii_strcasecmp(arg_string,"sensitive")==0)
+             if(ascii_strcasecmp(arg_string,"sensitive")==0)
                sensitive=1;
              if( menu_addrevoker( keyblock, sec_keyblock, sensitive ) ) {
                redisplay = 1;
@@ -2123,9 +2125,27 @@ keyedit_menu( const char *username, STRLIST locusr,
            }
            break;
 
-         case cmdSHOWPHOTO:
-           menu_showphoto(keyblock);
-           break;
+         case cmdSHOWPHOTO:
+           menu_showphoto(keyblock);
+           break;
+
+         case cmdCLEAN:
+           {
+             if(*arg_string)
+               {
+                 if(ascii_strcasecmp(arg_string,"sigs")!=0
+                    && ascii_strcasecmp(arg_string,"signatures")!=0
+                    && ascii_strcasecmp(arg_string,"certs")!=0
+                    && ascii_strcasecmp(arg_string,"certificates")!=0)
+                   {
+                     tty_printf(_("Unable to clean `%s'\n"),arg_string);
+                     break;
+                   }
+               }
+
+             modified=menu_clean_uids(keyblock);
+           }
+           break;
 
          case cmdQUIT:
            if( have_commands )
@@ -3108,6 +3128,41 @@ menu_delsig( KBNODE pub_keyblock )
     return changed;
 }
 
+static int
+menu_clean_uids(KBNODE keyblock)
+{
+  KBNODE uidnode;
+  int modified=0;
+  int select_all=!count_selected_uids(keyblock);
+
+  for(uidnode=keyblock;uidnode;uidnode=uidnode->next)
+    {
+      if(uidnode->pkt->pkttype==PKT_USER_ID
+        && (uidnode->flag&NODFLG_SELUID || select_all))
+       {
+         int deleted;
+         char *user=utf8_to_native(uidnode->pkt->pkt.user_id->name,
+                                   uidnode->pkt->pkt.user_id->len,
+                                   0);
+         deleted=clean_uid(keyblock,uidnode,opt.verbose);
+         if(deleted)
+           {
+             tty_printf(deleted==1?
+                        _("User ID \"%s\": %d signature removed.\n"):
+                        _("User ID \"%s\": %d signatures removed.\n"),
+                        user,deleted);
+             modified=1;
+           }
+         else
+           tty_printf(_("User ID \"%s\": already clean.\n"),user);
+
+         m_free(user);
+       }
+    }
+
+  return modified;
+}
+
 
 /****************
  * Remove some of the secondary keys
index d69b872..751f1b4 100644 (file)
@@ -1,6 +1,6 @@
 /* trustdb.c
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
- *               2004 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+ *               2005 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -1409,8 +1409,9 @@ is_in_klist (struct key_item *k, PKT_signature *sig)
  * To do this, we first revmove all signatures which are not valid and
  * from the remain ones we look for the latest one.  If this is not a
  * certification revocation signature we mark the signature by setting
- * node flag bit 8.  Note that flag bits 9 and 10 are used for internal
- * purposes.  
+ * node flag bit 8.  Revocations are marked with flag 11, and sigs
+ * from unavailable keys are marked with flag 12.  Note that flag bits
+ * 9 and 10 are used for internal purposes.
  */
 static void
 mark_usable_uid_certs (KBNODE keyblock, KBNODE uidnode,
@@ -1423,34 +1424,44 @@ mark_usable_uid_certs (KBNODE keyblock, KBNODE uidnode,
   /* first check all signatures */
   for (node=uidnode->next; node; node = node->next)
     {
-      node->flag &= ~(1<<8 | 1<<9 | 1<<10);
+      int rc;
+
+      node->flag &= ~(1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12);
       if (node->pkt->pkttype == PKT_USER_ID
           || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
         break; /* ready */
       if (node->pkt->pkttype != PKT_SIGNATURE)
         continue;
-      
       sig = node->pkt->pkt.signature;
-      if (sig->keyid[0] == main_kid[0] && sig->keyid[1] == main_kid[1])
-        continue; /* ignore self-signatures */
+      if (main_kid
+         && sig->keyid[0] == main_kid[0] && sig->keyid[1] == main_kid[1])
+        continue; /* ignore self-signatures if we pass in a main_kid */
       if (!IS_UID_SIG(sig) && !IS_UID_REV(sig))
         continue; /* we only look at these signature classes */
       if(sig->sig_class>=0x11 && sig->sig_class<=0x13 &&
         sig->sig_class-0x10<opt.min_cert_level)
-       continue;
-      if (!is_in_klist (klist, sig))
+       continue; /* treat anything under our min_cert_level as an
+                    invalid signature */
+      if (klist && !is_in_klist (klist, sig))
         continue;  /* no need to check it then */
-      if (check_key_signature (keyblock, node, NULL))
-        continue; /* ignore invalid signatures */
+      if ((rc=check_key_signature (keyblock, node, NULL)))
+       {
+         /* we ignore anything that won't verify, but tag the
+            no_pubkey case */
+         if(rc==G10ERR_NO_PUBKEY)
+           node->flag |= 1<<12;
+         continue;
+       }
       node->flag |= 1<<9;
     }      
   /* reset the remaining flags */
   for (; node; node = node->next)
-      node->flag &= ~(1<<8 | 1<<9 | 1 << 10);
+      node->flag &= ~(1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12);
 
   /* kbnode flag usage: bit 9 is here set for signatures to consider,
    * bit 10 will be set by the loop to keep track of keyIDs already
-   * processed, bit 8 will be set for the usable signatures */
+   * processed, bit 8 will be set for the usable signatures, and bit
+   * 11 will be set for usable revocations. */
 
   /* for each cert figure out the latest valid one */
   for (node=uidnode->next; node; node = node->next)
@@ -1458,7 +1469,7 @@ mark_usable_uid_certs (KBNODE keyblock, KBNODE uidnode,
       KBNODE n, signode;
       u32 kid[2];
       u32 sigdate;
-      
+
       if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
         break;
       if ( !(node->flag & (1<<9)) )
@@ -1470,6 +1481,8 @@ mark_usable_uid_certs (KBNODE keyblock, KBNODE uidnode,
       signode = node;
       sigdate = sig->timestamp;
       kid[0] = sig->keyid[0]; kid[1] = sig->keyid[1];
+
+      /* Now find the latest and greatest signature */
       for (n=uidnode->next; n; n = n->next)
         {
           if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY)
@@ -1532,6 +1545,7 @@ mark_usable_uid_certs (KBNODE keyblock, KBNODE uidnode,
               sigdate = sig->timestamp;
             }
         }
+
       sig = signode->pkt->pkt.signature;
       if (IS_UID_SIG (sig))
         { /* this seems to be a usable one which is not revoked. 
@@ -1550,11 +1564,75 @@ mark_usable_uid_certs (KBNODE keyblock, KBNODE uidnode,
           if (expire==0 || expire > curtime )
             {
               signode->flag |= (1<<8); /* yeah, found a good cert */
-              if (expire && expire < *next_expire)
+              if (next_expire && expire && expire < *next_expire)
                 *next_expire = expire;
             }
         }
+      else
+       signode->flag |= (1<<11);
+    }
+}
+
+int
+clean_uid(KBNODE keyblock,KBNODE uidnode,int noisy)
+{
+  int deleted=0;
+  KBNODE node;
+
+  assert(keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
+
+  /* Passing in a 0 for current time here means that we'll never weed
+     out an expired sig.  This is correct behavior since we want to
+     keep the most recent expired sig in a series. */
+  mark_usable_uid_certs(keyblock,uidnode,NULL,NULL,0,NULL);
+
+  /* What we want to do here is remove signatures that are not
+     considered as part of the trust calculations.  Thus, all invalid
+     signatures are out, as are any signatures that aren't the last of
+     a series of uid sigs or revocations It breaks down like this:
+     coming out of mark_usable_uid_certs, if a sig is unflagged, it is
+     not even a candidate.  If a sig has flag 9 or 10, that means it
+     was selected as a candidate and vetted.  If a sig has flag 8 it
+     is a usable signature.  If a sig has flag 11 it is a usable
+     revocation.  If a sig has flag 12 it was issued by an unavailable
+     key.  "Usable" here means the most recent valid
+     signature/revocation in a series from a particular signer.
+
+     Delete everything that isn't a usable uid sig (which might be
+     expired), a usable revocation, or a sig from an unavailable
+     key. */
+
+  for(node=uidnode->next;
+      node && node->pkt->pkttype==PKT_SIGNATURE;
+      node=node->next)
+    {
+      /* Keep usable uid sigs ... */
+      if(node->flag & (1<<8))
+       continue;
+
+      /* ... and usable revocations... */
+      if(node->flag & (1<<11))
+       continue;
+
+      /* ... and sigs from unavailable keys. */
+      if(node->flag & (1<<12))
+       continue;
+
+      /* Everything else we delete */
+
+      /* if 9 or 10 is set, but we get this far, it's superceded,
+        otherwise, it's invalid */
+
+      if(noisy)
+       log_info("removing signature issued by key %s: %s\n",
+                keystr(node->pkt->pkt.signature->keyid),
+                node->flag&(1<<9)?"superceded":"invalid");
+
+      delete_kbnode(node);
+      deleted++;
     }
+    
+  return deleted;
 }
 
 /* Used by validate_one_keyblock to confirm a regexp within a trust
index 710c13b..a9f98c7 100644 (file)
@@ -81,6 +81,8 @@ const char *get_ownertrust_string (PKT_public_key *pk);
 void update_ownertrust (PKT_public_key *pk, unsigned int new_trust );
 int clear_ownertrusts (PKT_public_key *pk);
 
+int clean_uid(KBNODE keyblock,KBNODE uidnode,int noisy);
+
 /*-- tdbdump.c --*/
 void list_trustdb(const char *username);
 void export_ownertrust(void);