* keyedit.c (keyedit_menu, menu_revuid): Add "revuid" feature to revoke a
authorDavid Shaw <dshaw@jabberwocky.com>
Fri, 27 Dec 2002 13:41:17 +0000 (13:41 +0000)
committerDavid Shaw <dshaw@jabberwocky.com>
Fri, 27 Dec 2002 13:41:17 +0000 (13:41 +0000)
user ID.  This is the same as issuing a revocation for the self-signature,
but a much simpler interface to do it.

g10/ChangeLog
g10/keyedit.c

index 3943b8e..6fc4d36 100644 (file)
@@ -1,3 +1,9 @@
+2002-12-27  David Shaw  <dshaw@jabberwocky.com>
+
+       * keyedit.c (keyedit_menu, menu_revuid): Add "revuid" feature to
+       revoke a user ID.  This is the same as issuing a revocation for
+       the self-signature, but a much simpler interface to do it.
+
 2002-12-26  David Shaw  <dshaw@jabberwocky.com>
 
        * keydb.h, getkey.c (key_byname): Flag to enable or disable
index 87830e2..02031fe 100644 (file)
@@ -63,6 +63,7 @@ static int count_selected_uids( KBNODE keyblock );
 static int real_uids_left( KBNODE keyblock );
 static int count_selected_keys( KBNODE keyblock );
 static int menu_revsig( KBNODE keyblock );
+static int menu_revuid( KBNODE keyblock, KBNODE sec_keyblock );
 static int menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock );
 static int enable_disable_key( KBNODE keyblock, int disable );
 static void menu_showphoto( KBNODE keyblock );
@@ -1016,12 +1017,12 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
 {
     enum cmdids { cmdNONE = 0,
           cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN,
-           cmdTSIGN, cmdLSIGN, cmdNRSIGN, cmdNRLSIGN, cmdREVSIG, cmdREVKEY, cmdDELSIG,
-          cmdPRIMARY, cmdDEBUG, cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID,
-           cmdADDKEY, cmdDELKEY, cmdADDREVOKER, cmdTOGGLE, cmdSELKEY,
-          cmdPASSWD, cmdTRUST, cmdPREF, cmdEXPIRE, cmdENABLEKEY,
-          cmdDISABLEKEY, cmdSHOWPREF, cmdSETPREF, cmdUPDPREF, cmdINVCMD,
-           cmdSHOWPHOTO, cmdUPDTRUST, cmdCHKTRUST, cmdNOP };
+           cmdTSIGN, cmdLSIGN, cmdNRSIGN, cmdNRLSIGN, cmdREVSIG, cmdREVKEY,
+          cmdREVUID, cmdDELSIG, cmdPRIMARY, cmdDEBUG, cmdSAVE, cmdADDUID,
+          cmdADDPHOTO, cmdDELUID, cmdADDKEY, cmdDELKEY, cmdADDREVOKER,
+          cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF, cmdEXPIRE,
+          cmdENABLEKEY, cmdDISABLEKEY, cmdSHOWPREF, cmdSETPREF, cmdUPDPREF,
+          cmdINVCMD, cmdSHOWPHOTO, cmdUPDTRUST, cmdCHKTRUST, cmdNOP };
     static struct { const char *name;
                    enum cmdids id;
                    int need_sk;
@@ -1069,6 +1070,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
        { N_("passwd")  , cmdPASSWD    , 1,1,0, N_("change the passphrase") },
        { N_("trust")   , cmdTRUST     , 0,1,0, N_("change the ownertrust") },
        { N_("revsig")  , cmdREVSIG    , 0,1,0, N_("revoke signatures") },
+       { N_("revuid")  , cmdREVUID    , 1,1,0, N_("revoke a user ID") },
        { N_("revkey")  , cmdREVKEY    , 1,1,0, N_("revoke a secondary key") },
        { N_("disable") , cmdDISABLEKEY, 0,1,0, N_("disable a key") },
        { N_("enable")  , cmdENABLEKEY , 0,1,0, N_("enable a key") },
@@ -1408,6 +1410,25 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
            }
            break;
 
+         case cmdREVUID: {
+               int n1;
+
+               if( !(n1=count_selected_uids(keyblock)) )
+                   tty_printf(_("You must select at least one user ID.\n"));
+               else if( cpr_get_answer_is_yes(
+                           "keyedit.revoke.uid.okay",
+                       n1 > 1? _("Really revoke all selected user IDs? ")
+                             : _("Really revoke this user ID? ")
+                      ) ) {
+                 if(menu_revuid(keyblock,sec_keyblock))
+                   {
+                     modified=1;
+                     redisplay=1;
+                   }
+               }
+           }
+           break;
+
          case cmdREVKEY: {
                int n1;
 
@@ -3311,6 +3332,119 @@ menu_revsig( KBNODE keyblock )
     return changed;
 }
 
+/* Revoke a user ID (i.e. revoke a user ID selfsig).  Return true if
+   keyblock changed. */
+static int
+menu_revuid( KBNODE pub_keyblock, KBNODE sec_keyblock )
+{
+  PKT_public_key *pk = pub_keyblock->pkt->pkt.public_key;
+  PKT_secret_key *sk = copy_secret_key( NULL,
+                                       sec_keyblock->pkt->pkt.secret_key );
+  KBNODE node;
+  int changed = 0;
+  int rc;
+  struct revocation_reason_info *reason = NULL;
+
+  /* Note that this is correct as per the RFCs, but nevertheless
+     somewhat meaningless in the real world.  1991 did define the 0x30
+     sig class, but PGP 2.x did not actually implement it, so it would
+     probably be safe to use v4 revocations everywhere. -ds */
+
+  for( node = pub_keyblock; node; node = node->next )
+    if(node->pkt->pkttype==PKT_USER_ID &&
+       node->pkt->pkt.user_id->selfsigversion>3)
+      {
+       if((reason = ask_revocation_reason( 0, 1, 4 )))
+         break;
+       else
+         goto leave;
+      }
+
+ reloop: /* (better this way because we are modifing the keyring) */
+  for( node = pub_keyblock; node; node = node->next )
+    if(node->pkt->pkttype == PKT_USER_ID && (node->flag & NODFLG_SELUID))
+      {
+       PKT_user_id *uid=node->pkt->pkt.user_id;
+
+       if(uid->is_revoked)
+         {
+           char *user=utf8_to_native(uid->name,uid->len,0);
+           log_info(_("user ID \"%s\" is already revoked\n"),user);
+           m_free(user);
+         }
+       else
+         {
+           PACKET *pkt;
+           PKT_signature *sig;
+           struct sign_attrib attrib;
+           u32 timestamp=make_timestamp();
+
+           if(uid->created>=timestamp)
+             {
+               /* Okay, this is a problem.  The user ID selfsig was
+                  created in the future, so we need to warn the user and
+                  set our revocation timestamp one second after that so
+                  everything comes out clean. */
+
+               log_info(_("WARNING: a user ID signature is dated %d"
+                          " seconds in the future\n"),uid->created-timestamp);
+
+               timestamp=uid->created+1;
+             }
+
+           memset( &attrib, 0, sizeof attrib );
+           attrib.reason = reason;
+
+           node->flag &= ~NODFLG_SELUID;
+
+           rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x30, 0,
+                                    (reason==NULL)?3:0, timestamp, 0,
+                                    sign_mk_attrib, &attrib );
+           if( rc )
+             {
+               log_error(_("signing failed: %s\n"), g10_errstr(rc));
+               goto leave;
+             }
+           else
+             {
+               byte namehash[20];
+
+               pkt = m_alloc_clear( sizeof *pkt );
+               pkt->pkttype = PKT_SIGNATURE;
+               pkt->pkt.signature = sig;
+               insert_kbnode( node, new_kbnode(pkt), 0 );
+
+               if(!update_trust)
+                 {
+                   /* If the trustdb has an entry for this key+uid then the
+                      trustdb needs an update. */
+                   if( uid->attrib_data )
+                     rmd160_hash_buffer(namehash,
+                                        uid->attrib_data, uid->attrib_len);
+                   else
+                     rmd160_hash_buffer( namehash, uid->name, uid->len  );
+
+                   if((get_validity(pk,namehash)&TRUST_MASK)>=TRUST_UNDEFINED)
+                     update_trust=1;
+                 }
+
+               changed = 1;
+               node->pkt->pkt.user_id->is_revoked=1;
+
+               goto reloop;
+             }
+         }
+      }
+
+  if(changed)
+    commit_kbnode( &pub_keyblock );
+
+ leave:
+  free_secret_key(sk);
+  release_revocation_reason_info( reason );
+  return changed;
+}
+
 /****************
  * Revoke some of the secondary keys.
  * Hmmm: Should we add a revocation to the secret keyring too?
@@ -3330,7 +3464,6 @@ menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock )
        return 0;
     }
 
-
   reloop: /* (better this way because we are modifing the keyring) */
     mainpk = pub_keyblock->pkt->pkt.public_key;
     for( node = pub_keyblock; node; node = node->next ) {