diff --git a/doc/gpg.texi b/doc/gpg.texi index 901d1ee15..8864a0ad5 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -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 diff --git a/g10/export.c b/g10/export.c index e0699db03..78cb85f34 100644 --- a/g10/export.c +++ b/g10/export.c @@ -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, diff --git a/g10/import.c b/g10/import.c index 14abd2bb2..f32a3dafe 100644 --- a/g10/import.c +++ b/g10/import.c @@ -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;