gpg: Let export-clean remove expired subkeys.
authorWerner Koch <wk@gnupg.org>
Mon, 9 Jul 2018 07:49:09 +0000 (09:49 +0200)
committerWerner Koch <wk@gnupg.org>
Mon, 9 Jul 2018 07:49:21 +0000 (09:49 +0200)
* g10/key-clean.h (KEY_CLEAN_NONE, KEY_CLEAN_INVALID)
(KEY_CLEAN_ENCR, KEY_CLEAN_AUTHENCR, KEY_CLEAN_ALL): New.
* g10/key-clean.c (clean_one_subkey): New.
(clean_all_subkeys): Add arg CLEAN_LEVEL.
* g10/import.c (import_one): Call clean_all_subkeys with
KEY_CLEAN_NONE.
* g10/export.c (do_export_stream): Call clean_all_subkeys depedning on
the export clean options.
--

GnuPG-bug-id: 3622
Signed-off-by: Werner Koch <wk@gnupg.org>
g10/export.c
g10/import.c
g10/key-clean.c
g10/key-clean.h

index 21ff23c..e94e959 100644 (file)
@@ -2003,15 +2003,18 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
         }
 
       /* Always do the cleaning on the public key part if requested.
-       * Note that both export-clean and export-minimal only apply to
-       * UID sigs (0x10, 0x11, 0x12, and 0x13).  A designated
-       * revocation is never stripped, even with export-minimal set.  */
+       * A designated revocation is never stripped, even with
+       * export-minimal set.  */
       if ((options & EXPORT_CLEAN))
         {
           merge_keys_and_selfsig (ctrl, keyblock);
           clean_all_uids (ctrl, keyblock, opt.verbose,
                           (options&EXPORT_MINIMAL), NULL, NULL);
-          clean_all_subkeys (ctrl, keyblock, opt.verbose, NULL, NULL);
+          clean_all_subkeys (ctrl, keyblock, opt.verbose,
+                             (options&EXPORT_MINIMAL)? KEY_CLEAN_ALL
+                             /**/                    : KEY_CLEAN_AUTHENCR,
+                             NULL, NULL);
+          commit_kbnode (&keyblock);
         }
 
       if (export_keep_uid)
index 66ff925..1eb3ecc 100644 (file)
@@ -1764,7 +1764,8 @@ import_one (ctrl_t ctrl,
       merge_keys_and_selfsig (ctrl, keyblock);
       clean_all_uids (ctrl, keyblock,
                       opt.verbose, (options&IMPORT_MINIMAL), NULL, NULL);
-      clean_all_subkeys (ctrl, keyblock, opt.verbose, NULL, NULL);
+      clean_all_subkeys (ctrl, keyblock, opt.verbose, KEY_CLEAN_NONE,
+                         NULL, NULL);
     }
 
   clear_kbnode_flags( keyblock );
@@ -1910,7 +1911,8 @@ import_one (ctrl_t ctrl,
           merge_keys_and_selfsig (ctrl, keyblock);
           clean_all_uids (ctrl, keyblock, opt.verbose, (options&IMPORT_MINIMAL),
                           &n_uids_cleaned,&n_sigs_cleaned);
-          clean_all_subkeys (ctrl, keyblock, opt.verbose, NULL, NULL);
+          clean_all_subkeys (ctrl, keyblock, opt.verbose, KEY_CLEAN_NONE,
+                             NULL, NULL);
         }
 
       /* Unless we are in restore mode apply meta data to the
@@ -2001,7 +2003,8 @@ import_one (ctrl_t ctrl,
           clean_all_uids (ctrl, keyblock_orig, opt.verbose,
                           (options&IMPORT_MINIMAL),
                           &n_uids_cleaned,&n_sigs_cleaned);
-          clean_all_subkeys (ctrl, keyblock_orig, opt.verbose, NULL, NULL);
+          clean_all_subkeys (ctrl, keyblock_orig, opt.verbose, KEY_CLEAN_NONE,
+                             NULL, NULL);
         }
 
       if (n_uids || n_sigs || n_subk || n_sigs_cleaned || n_uids_cleaned)
index 10478a4..097ca17 100644 (file)
@@ -408,24 +408,101 @@ clean_all_uids (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only,
 }
 
 
+/* Helper for clean_all_subkeys.  */
+static int
+clean_one_subkey (ctrl_t ctrl, kbnode_t subkeynode, int noisy, int clean_level)
+{
+  kbnode_t node;
+  PKT_public_key *pk = subkeynode->pkt->pkt.public_key;
+  unsigned int use = pk->pubkey_usage;
+  int do_clean = 0;
+
+  (void)ctrl;
+  (void)noisy;
+
+  log_assert (subkeynode->pkt->pkttype == PKT_PUBLIC_SUBKEY
+              || subkeynode->pkt->pkttype == PKT_SECRET_SUBKEY);
+
+  if (DBG_LOOKUP)
+    log_debug ("\tchecking subkey %08lX [%c%c%c%c%c]\n",
+               (ulong) keyid_from_pk (pk, NULL),
+               (use & PUBKEY_USAGE_ENC)? 'e':'-',
+               (use & PUBKEY_USAGE_SIG)? 's':'-',
+               (use & PUBKEY_USAGE_CERT)? 'c':'-',
+               (use & PUBKEY_USAGE_AUTH)? 'a':'-',
+               (use & PUBKEY_USAGE_UNKNOWN)? '?':'-');
+
+  if (!pk->flags.valid)
+    {
+      if (DBG_LOOKUP)
+        log_debug ("\tsubkey not valid\n");
+      if (clean_level == KEY_CLEAN_INVALID)
+        do_clean = 1;
+    }
+  if (pk->has_expired)
+    {
+      if (DBG_LOOKUP)
+        log_debug ("\tsubkey has expired\n");
+      if (clean_level == KEY_CLEAN_ALL)
+        do_clean = 1;
+      else if (clean_level == KEY_CLEAN_AUTHENCR
+               && (use & (PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH))
+               && !(use & (PUBKEY_USAGE_SIG | PUBKEY_USAGE_CERT)))
+        do_clean = 1;
+      else if (clean_level == KEY_CLEAN_ENCR
+               && (use & PUBKEY_USAGE_ENC)
+               && !(use & (PUBKEY_USAGE_SIG | PUBKEY_USAGE_CERT
+                           | PUBKEY_USAGE_AUTH)))
+        do_clean = 1;
+    }
+  if (pk->flags.revoked)
+    {
+      if (DBG_LOOKUP)
+        log_debug ("\tsubkey has been revoked (keeping)\n");
+      /* Avoid any cleaning because revocations are important.  */
+      do_clean = 0;
+    }
+  if (!do_clean)
+    return 0;
+
+  if (DBG_LOOKUP)
+    log_debug ("\t=> removing this subkey\n");
+
+  delete_kbnode (subkeynode);
+  for (node = subkeynode->next;
+       node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+                 || node->pkt->pkttype == PKT_SECRET_SUBKEY);
+       node = node->next)
+    delete_kbnode (node);
+
+  return 1;
+}
+
+
 /* This function only marks the deleted nodes and the caller is
  * responsible to skip or remove them.  Needs to be called after a
- * merge_keys_and_selfsig.  */
+ * merge_keys_and_selfsig.  CLEAN_LEVEL is one of the KEY_CLEAN_*
+ * values.   */
 void
-clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy,
+clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy, int clean_level,
                    int *subkeys_cleaned, int *sigs_cleaned)
 {
-  kbnode_t node;
+  kbnode_t first_subkey, node;
+
+  if (DBG_LOOKUP)
+    log_debug ("clean_all_subkeys: checking key %08lX\n",
+              (ulong) keyid_from_pk (keyblock->pkt->pkt.public_key, NULL));
 
   for (node = keyblock->next; node; node = node->next)
     if (!is_deleted_kbnode (node)
         && (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
             || node->pkt->pkttype == PKT_SECRET_SUBKEY))
       break;
+  first_subkey = node;
 
   /* Remove bogus subkey binding signatures: The only signatures
    * allowed are of class 0x18 and 0x28.  */
-  for (; node; node = node->next)
+  for (node = first_subkey; node; node = node->next)
     {
       if (is_deleted_kbnode (node))
         continue;
@@ -438,4 +515,21 @@ clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy,
             ++*sigs_cleaned;
         }
     }
+
+  /* Do the selected cleaning.  */
+  if (clean_level > KEY_CLEAN_NONE)
+    {
+      for (node = first_subkey; node; node = node->next)
+        {
+          if (is_deleted_kbnode (node))
+            continue;
+          if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+              || node->pkt->pkttype == PKT_SECRET_SUBKEY)
+            if (clean_one_subkey (ctrl, node, noisy, clean_level))
+              {
+                if (subkeys_cleaned)
+                  ++*subkeys_cleaned;
+              }
+        }
+    }
 }
index 6938430..a0fb769 100644 (file)
 
 #include "gpg.h"
 
+/* No explict cleaning.  */
+#define KEY_CLEAN_NONE      0
+/* Remove only invalid subkeys (ie. missing key-bindings) */
+#define KEY_CLEAN_INVALID   1
+/* Remove expired encryption keys */
+#define KEY_CLEAN_ENCR      2
+/* Remove expired authentication and encryption keys.  */
+#define KEY_CLEAN_AUTHENCR  3
+/* Remove all expired subkeys.  */
+#define KEY_CLEAN_ALL       4
+
+
 void mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
                             u32 *main_kid, struct key_item *klist,
                             u32 curtime, u32 *next_expire);
@@ -32,7 +44,8 @@ void clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
                     int *uids_cleaned, int *sigs_cleaned);
 void clean_all_uids (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only,
                      int *uids_cleaned,int *sigs_cleaned);
-void clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy,
+void clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock,
+                        int noisy, int clean_level,
                         int *subkeys_cleaned, int *sigs_cleaned);