diff --git a/doc/DETAILS b/doc/DETAILS index 28fb55a2c..0be55f4d6 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -241,8 +241,7 @@ described here. The origin of the key or the user ID. This is an integer optionally followed by a space and an URL. This goes along with - the previous field. The values are not yet defined. - + the previous field. The URL is quoted in C style. ** Special fields diff --git a/doc/gpg.texi b/doc/gpg.texi index 64dd50267..cae351b56 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -2531,6 +2531,13 @@ Print the ICAO spelling of the fingerprint in addition to the hex digits. Include the keygrip in the key listings. In @code{--with-colons} mode this is implicitly enable for secret keys. +@item --with-key-origin +@opindex with-key-origin +Include the locally held information on the origin and last update of +a key in a key listing. In @code{--with-colons} mode this is always +printed. This data is currently experimental and shall not be +considered part of the stable API. + @item --with-wkd-hash @opindex with-wkd-hash Print a Web Key Directory identifier along with each user ID in key diff --git a/g10/getkey.c b/g10/getkey.c index 2bec98419..484063e8e 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -4300,11 +4300,13 @@ parse_auto_key_locate (char *options) } -/* Parse the argument for --key-origin. Return false on error. */ -int -parse_key_origin (char *string) -{ - struct { const char *name; int origin; } list[] = { + +/* The list of key origins. */ +static struct { + const char *name; + int origin; +} key_origin_list[] = + { { "self", KEYORG_SELF }, { "file", KEYORG_FILE }, { "url", KEYORG_URL }, @@ -4314,27 +4316,45 @@ parse_key_origin (char *string) { "ks", KEYORG_KS }, { "unknown", KEYORG_UNKNOWN } }; + +/* Parse the argument for --key-origin. Return false on error. */ +int +parse_key_origin (char *string) +{ int i; if (!ascii_strcasecmp (string, "help")) { log_info (_("valid values for option '%s':\n"), "--key-origin"); - for (i=0; i < DIM (list); i++) - log_info (" %s\n", list[i].name); + for (i=0; i < DIM (key_origin_list); i++) + log_info (" %s\n", key_origin_list[i].name); g10_exit (1); } - for (i=0; i < DIM (list); i++) - if (!ascii_strcasecmp (string, list[i].name)) + for (i=0; i < DIM (key_origin_list); i++) + if (!ascii_strcasecmp (string, key_origin_list[i].name)) { - opt.key_origin = list[i].origin; + opt.key_origin = key_origin_list[i].origin; return 1; } return 0; } +/* Return a string or "?" for the key ORIGIN. */ +const char * +key_origin_string (int origin) +{ + int i; + for (i=0; i < DIM (key_origin_list); i++) + if (key_origin_list[i].origin == origin) + return key_origin_list[i].name; + return "?"; +} + + + /* Returns true if a secret key is available for the public key with key id KEYID; returns false if not. This function ignores legacy keys. Note: this is just a fast check and does not tell us whether diff --git a/g10/gpg.c b/g10/gpg.c index 5c60e1d1b..70b8011a5 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -201,6 +201,7 @@ enum cmd_and_opt_values oWithWKDHash, oWithColons, oWithKeyData, + oWithKeyOrigin, oWithTofuInfo, oWithSigList, oWithSigCheck, @@ -785,6 +786,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_n (oWithKeygrip, "with-keygrip", "@"), ARGPARSE_s_n (oWithSecret, "with-secret", "@"), ARGPARSE_s_n (oWithWKDHash, "with-wkd-hash", "@"), + ARGPARSE_s_n (oWithKeyOrigin, "with-key-origin", "@"), ARGPARSE_s_s (oDisableCipherAlgo, "disable-cipher-algo", "@"), ARGPARSE_s_s (oDisablePubkeyAlgo, "disable-pubkey-algo", "@"), ARGPARSE_s_n (oAllowNonSelfsignedUID, "allow-non-selfsigned-uid", "@"), @@ -2733,6 +2735,10 @@ main (int argc, char **argv) opt.with_wkd_hash = 1; break; + case oWithKeyOrigin: + opt.with_key_origin = 1; + break; + case oSecretKeyring: /* Ignore this old option. */ break; diff --git a/g10/keydb.h b/g10/keydb.h index 6416e634d..15345bb13 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -398,6 +398,7 @@ char *get_user_id_byfpr_native (ctrl_t ctrl, const byte *fpr); void release_akl(void); int parse_auto_key_locate(char *options); int parse_key_origin (char *string); +const char *key_origin_string (int origin); /*-- keyid.c --*/ int pubkey_letter( int algo ); diff --git a/g10/keylist.c b/g10/keylist.c index e4d5d06f0..37a26dc9a 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -922,6 +922,21 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr, if (opt.with_key_data) print_key_data (pk); + if (opt.with_key_origin + && (pk->keyorg || pk->keyupdate || pk->updateurl)) + { + char updatestr[MK_DATESTR_SIZE]; + + es_fprintf (es_stdout, " origin=%s last=%s %s", + key_origin_string (pk->keyorg), + mk_datestr (updatestr, sizeof updatestr, pk->keyupdate), + pk->updateurl? "url=":""); + if (pk->updateurl) + print_utf8_string (es_stdout, pk->updateurl); + es_putc ('\n', es_stdout); + } + + for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));) { if (node->pkt->pkttype == PKT_USER_ID) @@ -987,6 +1002,22 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr, xfree (mbox); } + if (opt.with_key_origin + && (uid->keyorg || uid->keyupdate || uid->updateurl)) + { + char updatestr[MK_DATESTR_SIZE]; + + es_fprintf (es_stdout, " %*sorigin=%s last=%s %s", + indent, "", + key_origin_string (uid->keyorg), + mk_datestr (updatestr, sizeof updatestr, + uid->keyupdate), + pk->updateurl? "url=":""); + if (pk->updateurl) + print_utf8_string (es_stdout, pk->updateurl); + es_putc ('\n', es_stdout); + } + if ((opt.list_options & LIST_SHOW_PHOTOS) && uid->attribs != NULL) show_photos (ctrl, uid->attribs, uid->numattribs, pk, uid); } @@ -1315,7 +1346,13 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock, es_putc (':', es_stdout); /* End of field 17. */ print_compliance_flags (pk, keylength, curvename); es_putc (':', es_stdout); /* End of field 18 (compliance). */ + if (pk->keyupdate) + es_fputs (colon_strtime (pk->keyupdate), es_stdout); es_putc (':', es_stdout); /* End of field 19 (last_update). */ + es_fprintf (es_stdout, "%d%s", pk->keyorg, pk->updateurl? " ":""); + if (pk->updateurl) + es_write_sanitized (es_stdout, pk->updateurl, strlen (pk->updateurl), + ":", NULL); es_putc (':', es_stdout); /* End of field 20 (origin). */ es_putc ('\n', es_stdout); @@ -1367,7 +1404,14 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock, else es_write_sanitized (es_stdout, uid->name, uid->len, ":", NULL); es_fputs (":::::::::", es_stdout); + if (uid->keyupdate) + es_fputs (colon_strtime (uid->keyupdate), es_stdout); es_putc (':', es_stdout); /* End of field 19 (last_update). */ + es_fprintf (es_stdout, "%d%s", uid->keyorg, uid->updateurl? " ":""); + if (uid->updateurl) + es_write_sanitized (es_stdout, + uid->updateurl, strlen (uid->updateurl), + ":", NULL); es_putc (':', es_stdout); /* End of field 20 (origin). */ es_putc ('\n', es_stdout); #ifdef USE_TOFU diff --git a/g10/options.h b/g10/options.h index 5bb506e52..21249e9ea 100644 --- a/g10/options.h +++ b/g10/options.h @@ -85,6 +85,7 @@ struct int with_tofu_info; /* Option --with-tofu_info active. */ int with_secret; /* Option --with-secret active. */ int with_wkd_hash; /* Option --with-wkd-hash. */ + int with_key_origin; /* Option --with-key-origin. */ int fingerprint; /* list fingerprints */ int list_sigs; /* list signatures */ int no_armor;