gpg: New export filter drop-subkey.
authorWerner Koch <wk@gnupg.org>
Mon, 5 Sep 2016 07:51:16 +0000 (09:51 +0200)
committerWerner Koch <wk@gnupg.org>
Mon, 5 Sep 2016 07:52:04 +0000 (09:52 +0200)
* g10/import.c (impex_filter_getval): Add properties for key packets.
* g10/export.c (export_drop_subkey): New var.
(cleanup_export_globals): Release that var.
(parse_and_set_export_filter): Add filter "drop-subkey".
(apply_drop_subkey_filter): New.
(do_export_stream): Run that filter.

Signed-off-by: Werner Koch <wk@gnupg.org>
doc/gpg.texi
g10/export.c
g10/import.c

index 901d1ee..8864a0a 100644 (file)
@@ -2254,6 +2254,10 @@ The available filter types are:
   This filter will keep a user id packet and its dependent packets in
   the keyblock if the expression evaluates to true.
 
+  @item drop-subkey
+  This filter drops the selected subkeys.
+  Currently only implemented for --export-filter.
+
   @item drop-sig
   This filter drops the selected key signatures on user ids.
   Self-signatures are not consideres.
@@ -2276,9 +2280,23 @@ The available properties are:
   The addr-spec part of a user id with mailbox or the empty string.
   (keep-uid)
 
+  @item key_algo
+  A number with the public key algorithm of a key or subkey packet.
+  (drop-subkey)
+
+  @item key_created
+  @itemx key_created_d
+  The first is the timestamp a public key or subkey packet was
+  created.  The second is the same but given as an ISO string,
+  e.g. "2016-08-17". (drop-subkey)
+
   @item primary
   Boolean indicating whether the user id is the primary one.  (keep-uid)
 
+  @item secret
+  Boolean indicating whether a key or subkey is a secret one.
+  drop-subkey)
+
   @item sig_created
   @itemx sig_created_d
   The first is the timestamp a signature packet was created.  The
index e0699db..78cb85f 100644 (file)
@@ -62,11 +62,13 @@ struct export_stats_s
 
 /* A global variable to store the selector created from
  * --export-filter keep-uid=EXPR.
+ * --export-filter drop-subkey=EXPR.
  *
  * FIXME: We should put this into the CTRL object but that requires a
  * lot more changes right now.
  */
 static recsel_expr_t export_keep_uid;
+static recsel_expr_t export_drop_subkey;
 
 
 
@@ -88,6 +90,8 @@ cleanup_export_globals (void)
 {
   recsel_release (export_keep_uid);
   export_keep_uid = NULL;
+  recsel_release (export_drop_subkey);
+  export_drop_subkey = NULL;
 }
 
 
@@ -142,6 +146,14 @@ parse_export_options(char *str,unsigned int *options,int noisy)
  *                - uid  :: The entire user ID.
  *                - mbox :: The mail box part of the user ID.
  *                - primary :: Evaluate to true for the primary user ID.
+ *
+ *  - drop-subkey :: If the expression evaluates to true for a subkey
+ *                packet that subkey and all it dependencies will be
+ *                remove from the keyblock.  The expression may use these
+ *                variables:
+ *
+ *                - secret   :: 1 for a secret subkey, else 0.
+ *                - key_algo :: Public key algorithm id
  */
 gpg_error_t
 parse_and_set_export_filter (const char *string)
@@ -153,6 +165,8 @@ parse_and_set_export_filter (const char *string)
 
   if (!strncmp (string, "keep-uid=", 9))
     err = recsel_parse_expr (&export_keep_uid, string+9);
+  else if (!strncmp (string, "drop-subkey=", 12))
+    err = recsel_parse_expr (&export_drop_subkey, string+12);
   else
     err = gpg_error (GPG_ERR_INV_NAME);
 
@@ -1329,6 +1343,38 @@ apply_keep_uid_filter (kbnode_t keyblock, recsel_expr_t selector)
 }
 
 
+/*
+ * Apply the drop-subkey filter to the keyblock.  The deleted nodes are
+ * marked and thus the caller should call commit_kbnode afterwards.
+ * KEYBLOCK must not have any blocks marked as deleted.
+ */
+static void
+apply_drop_subkey_filter (kbnode_t keyblock, recsel_expr_t selector)
+{
+  kbnode_t node;
+
+  for (node = keyblock->next; node; node = node->next )
+    {
+      if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+          || node->pkt->pkttype == PKT_SECRET_SUBKEY)
+        {
+          if (recsel_select (selector, impex_filter_getval, node))
+            {
+              log_debug ("drop-subkey: deleting a key\n");
+              /* The subkey packet and all following packets up to the
+               * next subkey.  */
+              delete_kbnode (node);
+              for (; node->next
+                     && node->next->pkt->pkttype != PKT_PUBLIC_SUBKEY
+                     && node->next->pkt->pkttype != PKT_SECRET_SUBKEY ;
+                   node = node->next)
+                delete_kbnode (node->next);
+           }
+        }
+    }
+}
+
+
 /* Print DANE or PKA records for all user IDs in KEYBLOCK to OUT.  The
  * data for the record is taken from (DATA,DATELEN).  PK is the public
  * key packet with the primary key. */
@@ -1922,6 +1968,13 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
           commit_kbnode (&keyblock);
         }
 
+      if (export_drop_subkey)
+        {
+          commit_kbnode (&keyblock);
+          apply_drop_subkey_filter (keyblock, export_drop_subkey);
+          commit_kbnode (&keyblock);
+        }
+
       /* And write it. */
       err = do_export_one_keyblock (ctrl, keyblock, keyid,
                                     out_help? out_help : out,
index 14abd2b..f32a3da 100644 (file)
@@ -1157,6 +1157,35 @@ impex_filter_getval (void *cookie, const char *propname)
       else
         result = NULL;
     }
+  else if (node->pkt->pkttype == PKT_PUBLIC_KEY
+           || node->pkt->pkttype == PKT_SECRET_KEY
+           || node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+           || node->pkt->pkttype == PKT_SECRET_SUBKEY)
+    {
+      PKT_public_key *pk = node->pkt->pkt.public_key;
+
+      if (!strcmp (propname, "secret"))
+        {
+          result = (node->pkt->pkttype == PKT_SECRET_KEY
+                    || node->pkt->pkttype == PKT_SECRET_SUBKEY)? "1":"0";
+        }
+      else if (!strcmp (propname, "key_algo"))
+        {
+          snprintf (numbuf, sizeof numbuf, "%d", pk->pubkey_algo);
+          result = numbuf;
+        }
+      if (!strcmp (propname, "key_created"))
+        {
+          snprintf (numbuf, sizeof numbuf, "%lu", (ulong)pk->timestamp);
+          result = numbuf;
+        }
+      else if (!strcmp (propname, "key_created_d"))
+        {
+          result = datestr_from_pk (pk);
+        }
+      else
+        result = NULL;
+    }
   else
     result = NULL;