[git] GnuPG - branch, master, updated. gnupg-2.1.13-71-g55d112e

by Daniel Kahn Gillmor cvs at cvs.gnupg.org
Thu Jun 30 12:02:52 CEST 2016


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, master has been updated
       via  55d112eeb0743e90be46d15dbae67368ee7d4b50 (commit)
      from  5d6c83deaa11327366b0038928200b9f9f85b426 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 55d112eeb0743e90be46d15dbae67368ee7d4b50
Author: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
Date:   Thu Jun 16 18:05:57 2016 -0400

    g10: Implement gpg --quick-revuid
    
    * g10/revoke.c (get_default_uid_revocation_reason): New.
    * g10/keyedit.c (menu_revuid): Break out creation of uid revocation
    into new function core_revuid.
    * g10/keyedit.c (keyedit_quick_revuid): New. Selects key and
    uid, invokes core_revuid.
    * g10/gpg.c (main): Handle --quick-revuid argument.
    * doc/gpg.texi: Document --quick-revuid.
    
    --
    
    This functionality is a counterpart to --quick-adduid, and will be
    useful for projects that depend programmatically on gpg to revoke user
    IDs (one such example is "monkeysphere-host revoke-servicename").
    
    Signed-off-by: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
    
    - Minor re-indentation work.
    - Changed a "0 == memcmp" to "!memcmp"
    - Removed tests/openpgp/quick-key-manipulation.test from the
      Makefile.  This test needs to be converted to gpgscm.
    - Removed example from whats-new-in-2.1.txt because that is generated.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/doc/gpg.texi b/doc/gpg.texi
index b8fda96..6f0249a 100644
--- a/doc/gpg.texi
+++ b/doc/gpg.texi
@@ -1041,6 +1041,15 @@ the interactive sub-command @code{adduid} of @option{--edit-key} the
 white space removed, it is expected to be UTF-8 encoded, and no checks
 on its form are applied.
 
+ at item --quick-revuid  @var{user-id} @var{user-id-to-revoke}
+ at opindex quick-revuid
+This command revokes a User ID on an existing key.  It cannot be used
+to revoke the last User ID on key (some non-revoked User ID must
+remain), with revocation reason ``User ID is no longer valid''.  If
+you want to specify a different revocation reason, or to supply
+supplementary revocation text, you should use the interactive
+sub-command @code{revuid} of @option{--edit-key}.
+
 @item --passwd @var{user_id}
 @opindex passwd
 Change the passphrase of the secret key belonging to the certificate
diff --git a/g10/gpg.c b/g10/gpg.c
index 9750c57..b1d6c34 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -118,6 +118,7 @@ enum cmd_and_opt_values
     aQuickLSignKey,
     aQuickAddUid,
     aQuickAddKey,
+    aQuickRevUid,
     aListConfig,
     aListGcryptConfig,
     aGPGConfList,
@@ -431,6 +432,8 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_c (aQuickAddUid,  "quick-adduid",
               N_("quickly add a new user-id")),
   ARGPARSE_c (aQuickAddKey,  "quick-addkey", "@"),
+  ARGPARSE_c (aQuickRevUid,  "quick-revuid",
+              N_("quickly revoke a user-id")),
   ARGPARSE_c (aFullKeygen,  "full-gen-key" ,
               N_("full featured key pair generation")),
   ARGPARSE_c (aGenRevoke, "gen-revoke",N_("generate a revocation certificate")),
@@ -2434,6 +2437,7 @@ main (int argc, char **argv)
 	  case aQuickKeygen:
 	  case aQuickAddUid:
 	  case aQuickAddKey:
+	  case aQuickRevUid:
 	  case aExportOwnerTrust:
 	  case aImportOwnerTrust:
           case aRebuildKeydbCaches:
@@ -3785,6 +3789,7 @@ main (int argc, char **argv)
       case aQuickKeygen:
       case aQuickAddUid:
       case aQuickAddKey:
+      case aQuickRevUid:
       case aFullKeygen:
       case aKeygen:
       case aImport:
@@ -4204,6 +4209,18 @@ main (int argc, char **argv)
         }
 	break;
 
+      case aQuickRevUid:
+        {
+          const char *uid, *uidtorev;
+
+          if (argc != 2)
+            wrong_args ("--quick-revuid USER-ID USER-ID-TO-REVOKE");
+          uid = *argv++; argc--;
+          uidtorev = *argv++; argc--;
+          keyedit_quick_revuid (ctrl, uid, uidtorev);
+        }
+	break;
+
       case aFastImport:
         opt.import_options |= IMPORT_FAST;
       case aImport:
diff --git a/g10/keyedit.c b/g10/keyedit.c
index d05ea5d..65f671e 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -87,6 +87,9 @@ static int real_uids_left (KBNODE keyblock);
 static int count_selected_keys (KBNODE keyblock);
 static int menu_revsig (KBNODE keyblock);
 static int menu_revuid (ctrl_t ctrl, kbnode_t keyblock);
+static int core_revuid (ctrl_t ctrl, kbnode_t keyblock, KBNODE node,
+                        const struct revocation_reason_info *reason,
+                        int *modified);
 static int menu_revkey (KBNODE pub_keyblock);
 static int menu_revsubkey (KBNODE pub_keyblock);
 #ifndef NO_TRUST_MODELS
@@ -2937,6 +2940,110 @@ keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
   keydb_release (kdbhd);
 }
 
+/* Unattended revokation of a keyid.  USERNAME specifies the
+   key. UIDTOREV is the user id revoke from the key.  */
+void
+keyedit_quick_revuid (ctrl_t ctrl, const char *username, const char *uidtorev)
+{
+  gpg_error_t err;
+  KEYDB_HANDLE kdbhd = NULL;
+  KEYDB_SEARCH_DESC desc;
+  kbnode_t keyblock = NULL;
+  kbnode_t node;
+  int modified = 0;
+  size_t revlen;
+
+#ifdef HAVE_W32_SYSTEM
+  /* See keyedit_menu for why we need this.  */
+  check_trustdb_stale ();
+#endif
+
+  /* Search the key; we don't want the whole getkey stuff here.  */
+  kdbhd = keydb_new ();
+  if (!kdbhd)
+    {
+      /* Note that keydb_new has already used log_error.  */
+      goto leave;
+    }
+
+  err = classify_user_id (username, &desc, 1);
+  if (!err)
+    err = keydb_search (kdbhd, &desc, 1, NULL);
+  if (!err)
+    {
+      err = keydb_get_keyblock (kdbhd, &keyblock);
+      if (err)
+        {
+          log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
+          goto leave;
+        }
+      /* Now with the keyblock retrieved, search again to detect an
+         ambiguous specification.  We need to save the found state so
+         that we can do an update later.  */
+      keydb_push_found_state (kdbhd);
+      err = keydb_search (kdbhd, &desc, 1, NULL);
+      if (!err)
+        err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
+      else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
+        err = 0;
+      keydb_pop_found_state (kdbhd);
+
+      if (!err)
+        {
+          /* We require the secret primary key to revoke a UID.  */
+          node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
+          if (!node)
+            BUG ();
+          err = agent_probe_secret_key (ctrl, node->pkt->pkt.public_key);
+        }
+    }
+  if (err)
+    {
+      log_error (_("secret key \"%s\" not found: %s\n"),
+                 username, gpg_strerror (err));
+      goto leave;
+    }
+
+  fix_keyblock (&keyblock);
+  setup_main_keyids (keyblock);
+
+  revlen = strlen (uidtorev);
+  /* find the right UID */
+  for (node = keyblock; node; node = node->next)
+    {
+      if (node->pkt->pkttype == PKT_USER_ID
+          && revlen == node->pkt->pkt.user_id->len
+          && !memcmp (node->pkt->pkt.user_id->name, uidtorev, revlen))
+        {
+          struct revocation_reason_info *reason;
+
+          reason = get_default_uid_revocation_reason ();
+          err = core_revuid (ctrl, keyblock, node, reason, &modified);
+          release_revocation_reason_info (reason);
+          if (err)
+            {
+              log_error (_("User ID revocation failed: %s\n"),
+                         gpg_strerror (err));
+              goto leave;
+            }
+          err = keydb_update_keyblock (kdbhd, keyblock);
+          if (err)
+            {
+              log_error (_("update failed: %s\n"), gpg_strerror (err));
+              goto leave;
+            }
+
+          if (update_trust)
+            revalidation_mark ();
+          goto leave;
+        }
+    }
+
+ leave:
+  release_kbnode (keyblock);
+  keydb_release (kdbhd);
+}
+
 
 /* Find a keyblock by fingerprint because only this uniquely
  * identifies a key and may thus be used to select a key for
@@ -6106,6 +6213,95 @@ reloop:			/* (must use this, because we are modifing the list) */
 }
 
 
+/* return 0 if revocation of NODE (which must be a User ID) was
+   successful, non-zero if there was an error.  *modified will be set
+   to 1 if a change was made. */
+static int
+core_revuid (ctrl_t ctrl, kbnode_t keyblock, KBNODE node,
+             const struct revocation_reason_info *reason, int *modified)
+{
+  PKT_public_key *pk = keyblock->pkt->pkt.public_key;
+  gpg_error_t rc;
+
+  if (node->pkt->pkttype != PKT_USER_ID)
+    {
+      rc = gpg_error (GPG_ERR_NO_USER_ID);
+      write_status_error ("keysig", rc);
+      log_error (_("tried to revoke a non-user ID: %s\n"), gpg_strerror (rc));
+      return 1;
+    }
+  else
+    {
+      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);
+          xfree (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);
+          /* should not need to cast away const here; but
+             revocation_reason_build_cb needs to take a non-const
+             void* in order to meet the function signtuare for the
+             mksubpkt argument to make_keysig_packet */
+          attrib.reason = (struct revocation_reason_info *)reason;
+
+          rc = make_keysig_packet (&sig, pk, uid, NULL, pk, 0x30, 0,
+                                   timestamp, 0,
+                                   sign_mk_attrib, &attrib, NULL);
+          if (rc)
+            {
+              write_status_error ("keysig", rc);
+              log_error (_("signing failed: %s\n"), gpg_strerror (rc));
+              return 1;
+            }
+          else
+            {
+              pkt = xmalloc_clear (sizeof *pkt);
+              pkt->pkttype = PKT_SIGNATURE;
+              pkt->pkt.signature = sig;
+              insert_kbnode (node, new_kbnode (pkt), 0);
+
+#ifndef NO_TRUST_MODELS
+              /* If the trustdb has an entry for this key+uid then the
+                 trustdb needs an update. */
+              if (!update_trust
+                  && ((get_validity (ctrl, pk, uid, NULL, 0) & TRUST_MASK)
+                      >= TRUST_UNDEFINED))
+                update_trust = 1;
+#endif /*!NO_TRUST_MODELS*/
+
+              node->pkt->pkt.user_id->is_revoked = 1;
+              if (modified)
+                *modified = 1;
+            }
+        }
+      return 0;
+    }
+}
+
 /* Revoke a user ID (i.e. revoke a user ID selfsig).  Return true if
    keyblock changed.  */
 static int
@@ -6132,75 +6328,20 @@ menu_revuid (ctrl_t ctrl, kbnode_t pub_keyblock)
 	  goto leave;
       }
 
- reloop: /* (better this way because we are modifing the keyring) */
+ reloop: /* (better this way because we are modifying 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);
-	    xfree (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;
-
+        int modified = 0;
+        rc = core_revuid (ctrl, pub_keyblock, node, reason, &modified);
+        if (rc)
+          goto leave;
+        if (modified)
+          {
 	    node->flag &= ~NODFLG_SELUID;
-
-	    rc = make_keysig_packet (&sig, pk, uid, NULL, pk, 0x30, 0,
-				     timestamp, 0,
-				     sign_mk_attrib, &attrib, NULL);
-	    if (rc)
-	      {
-                write_status_error ("keysig", rc);
-		log_error (_("signing failed: %s\n"), gpg_strerror (rc));
-		goto leave;
-	      }
-	    else
-	      {
-		pkt = xmalloc_clear (sizeof *pkt);
-		pkt->pkttype = PKT_SIGNATURE;
-		pkt->pkt.signature = sig;
-		insert_kbnode (node, new_kbnode (pkt), 0);
-
-#ifndef NO_TRUST_MODELS
-		/* If the trustdb has an entry for this key+uid then the
-		   trustdb needs an update. */
-		if (!update_trust
-		    && (get_validity (ctrl, pk, uid, NULL, 0) & TRUST_MASK) >=
-		    TRUST_UNDEFINED)
-		  update_trust = 1;
-#endif /*!NO_TRUST_MODELS*/
-
-		changed = 1;
-		node->pkt->pkt.user_id->is_revoked = 1;
-
-		goto reloop;
-	      }
-	  }
+            changed = 1;
+            goto reloop;
+          }
       }
 
   if (changed)
diff --git a/g10/main.h b/g10/main.h
index e6f2070..322f43c 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -289,6 +289,8 @@ void keyedit_quick_adduid (ctrl_t ctrl, const char *username,
                            const char *newuid);
 void keyedit_quick_addkey (ctrl_t ctrl, const char *fpr, const char *algostr,
                            const char *usagestr, const char *expirestr);
+void keyedit_quick_revuid (ctrl_t ctrl, const char *username,
+                           const char *uidtorev);
 void keyedit_quick_sign (ctrl_t ctrl, const char *fpr,
                          strlist_t uids, strlist_t locusr, int local);
 void show_basic_key_info (KBNODE keyblock);
@@ -407,6 +409,7 @@ int gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr);
 int revocation_reason_build_cb( PKT_signature *sig, void *opaque );
 struct revocation_reason_info *
 		ask_revocation_reason( int key_rev, int cert_rev, int hint );
+struct revocation_reason_info * get_default_uid_revocation_reason(void);
 void release_revocation_reason_info( struct revocation_reason_info *reason );
 
 /*-- keylist.c --*/
diff --git a/g10/revoke.c b/g10/revoke.c
index 218ca59..15a91ac 100644
--- a/g10/revoke.c
+++ b/g10/revoke.c
@@ -862,6 +862,16 @@ ask_revocation_reason( int key_rev, int cert_rev, int hint )
     return reason;
 }
 
+struct revocation_reason_info *
+get_default_uid_revocation_reason(void)
+{
+  struct revocation_reason_info *reason;
+  reason = xmalloc( sizeof *reason );
+  reason->code = 0x20; /* uid is no longer valid */
+  reason->desc = strdup(""); /* no text */
+  return reason;
+}
+
 void
 release_revocation_reason_info( struct revocation_reason_info *reason )
 {
diff --git a/tests/openpgp/quick-key-manipulation.test b/tests/openpgp/quick-key-manipulation.test
new file mode 100755
index 0000000..4185601
--- /dev/null
+++ b/tests/openpgp/quick-key-manipulation.test
@@ -0,0 +1,70 @@
+#!/bin/sh
+# Copyright 2016 Free Software Foundation, Inc.
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.  This file is
+# distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY, to the extent permitted by law; without even the implied
+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+. $srcdir/defs.inc || exit 3
+
+export PINENTRY_USER_DATA=test
+
+alpha="Alpha <alpha at example.net>"
+bravo="Bravo <bravo at example.net>"
+
+$GPG --with-colons --with-fingerprint --list-secret-keys ="$alpha" &&
+    error "User ID '$alpha'exists when it should not!"
+$GPG --with-colons --with-fingerprint --list-secret-keys ="$bravo" &&
+    error "User ID '$bravo' exists when it should not!"
+
+#info verify that key creation works
+$GPG --quick-gen-key "$alpha"  || \
+        error "failed to generate key"
+
+fpr=$($GPG --with-colons --with-fingerprint --list-secret-keys ="$alpha" | \
+             grep '^fpr:' | cut -f10 -d: | head -n1)
+
+$GPG --check-trustdb
+
+cleanup() {
+    $GPG --batch --yes --delete-secret-key "0x$fpr"
+    $GPG --batch --yes --delete-key "0x$fpr"
+}
+
+count_uids_of_secret() {
+    if ! [ $($GPG --with-colons --list-secret-keys ="$1" | \
+                    grep -c '^uid:u:') = "$2" ] ; then
+        cleanup
+        error "wrong number of user IDs for '$1' after $3"
+    fi
+}
+
+count_uids_of_secret "$alpha" 1 "key generation"
+
+#info verify that we can add a user ID
+if ! $GPG --quick-adduid ="$alpha" "$bravo" ; then
+    cleanup
+    error "failed to add user id"
+fi
+
+$GPG --check-trustdb
+
+count_uids_of_secret "$alpha" 2 "adding User ID"
+count_uids_of_secret "$bravo" 2 "adding User ID"
+
+#info verify that we can revoke a user ID
+if ! $GPG --quick-revuid ="$bravo" "$alpha"; then
+    cleanup
+    error "failed to revoke user id"
+fi
+
+$GPG --check-trustdb
+
+count_uids_of_secret "$bravo" 1 "revoking user ID"
+
+cleanup
+
+! $GPG --with-colons --list-secret-keys ="$bravo" ||
+    error "key still exists when it should not!"

-----------------------------------------------------------------------

Summary of changes:
 doc/gpg.texi                              |   9 +
 g10/gpg.c                                 |  17 ++
 g10/keyedit.c                             | 271 +++++++++++++++++++++++-------
 g10/main.h                                |   3 +
 g10/revoke.c                              |  10 ++
 tests/openpgp/quick-key-manipulation.test |  70 ++++++++
 6 files changed, 315 insertions(+), 65 deletions(-)
 create mode 100755 tests/openpgp/quick-key-manipulation.test


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list