From 14c1b73093e3fcbc43b04dfc520eb35d61241489 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 12 Mar 2024 18:01:24 +0100 Subject: [PATCH] gpg: new list-option show-x509-notations * g10/gpg.c (parse_list_options): Add new option. * g10/options.h (LIST_SHOW_X509_NOTATIONS): New. * g10/build-packet.c (search_sig_notations): New. * g10/keylist.c (print_x509_notations): New. (list_signature_print): Use macros for the sig classes. Call print_x509_notations. (list_keyblock_print): Call list_signature_print if x509 notation printing is enabled. --- doc/gpg.texi | 6 ++++ g10/build-packet.c | 66 ++++++++++++++++++++++++++++++++++++++++++++ g10/gpg.c | 1 + g10/keylist.c | 69 +++++++++++++++++++++++++++++++++++++--------- g10/options.h | 1 + g10/packet.h | 7 +++-- 6 files changed, 134 insertions(+), 16 deletions(-) diff --git a/doc/gpg.texi b/doc/gpg.texi index cb4506049..fb8d0f578 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -1410,6 +1410,12 @@ give the opposite meaning. The options are: Show all, IETF standard, or user-defined signature notations in the @option{--check-signatures} listings. Defaults to no. + @item show-x509-notations + @opindex list-options:show-x509-notations + Print X.509 certificates embedded in key signatures as PEM data. + This is intended for debugging and the output format may change + without notice. + @item show-keyserver-urls @opindex list-options:show-keyserver-urls Show any preferred keyserver URL in the diff --git a/g10/build-packet.c b/g10/build-packet.c index 19a13760a..9927b7695 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -1748,6 +1748,72 @@ sig_to_notation(PKT_signature *sig) return list; } + +/* Return a list of notation data matching NAME. The caller needs to + * to free the list using free_notation. Other than sig_to_notation + * this function does not return the notation in human readable format + * but always returns the raw data. The human readable flag is set + * anyway set but .value is always NULL. */ +struct notation * +search_sig_notations (PKT_signature *sig, const char *name) +{ + const byte *p; + size_t len; + int seq = 0; + int crit; + notation_t list = NULL; + + while((p=enum_sig_subpkt (sig, 1, SIGSUBPKT_NOTATION, &len, &seq, &crit))) + { + int n1,n2; + struct notation *n=NULL; + + if (len < 8) + { + log_info (_("WARNING: invalid notation data found\n")); + continue; + } + + /* name length. */ + n1=(p[4]<<8)|p[5]; + /* value length. */ + n2=(p[6]<<8)|p[7]; + + if (8 + n1 + n2 != len) + { + log_info (_("WARNING: invalid notation data found\n")); + continue; + } + + if (!name) + ; /* Return everything. */ + else if (n1 != strlen (name) || memcmp (p+8, name, n1)) + continue; /* Not the requested name. */ + + + n = xmalloc_clear (sizeof *n); + n->name = xmalloc (n1+1); + + memcpy (n->name,p + 8, n1); + n->name[n1]='\0'; + + /* In any case append a Nul. */ + n->bdat = xmalloc (n2+1); + memcpy (n->bdat, p + 8 + n1, n2); + n->bdat[n2] = '\0'; + n->blen = n2; + n->flags.human = !!(p[0] & 0x80); + + n->flags.critical = crit; + + n->next = list; + list = n; + } + + return list; +} + + /* Release the resources associated with the *list* of notations. To release a single notation, make sure that notation->next is NULL. */ diff --git a/g10/gpg.c b/g10/gpg.c index bef3b6fbd..8e0c6479e 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -2086,6 +2086,7 @@ parse_list_options(char *str) NULL}, {"show-user-notations",LIST_SHOW_USER_NOTATIONS,NULL, N_("show user-supplied notations during signature listings")}, + {"show-x509-notations",LIST_SHOW_X509_NOTATIONS,NULL, NULL }, {"show-keyserver-urls",LIST_SHOW_KEYSERVER_URLS,NULL, N_("show preferred keyserver URLs during signature listings")}, {"show-uid-validity",LIST_SHOW_UID_VALIDITY,NULL, diff --git a/g10/keylist.c b/g10/keylist.c index d0ebfc86f..20862b0f8 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -1171,6 +1171,36 @@ dump_attribs (const PKT_user_id *uid, PKT_public_key *pk) } + +static void +print_x509_notations (struct notation *nots) +{ + gpg_error_t err; + gpgrt_b64state_t state; + + for (; nots; nots = nots->next) + { + state = gpgrt_b64enc_start (es_stdout, "CERTIFICATE"); + if (!state) + { + err = gpg_err_code_from_syserror (); + goto b64fail; + } + err = gpgrt_b64enc_write (state, nots->bdat, nots->blen); + if (err) + goto b64fail; + err = gpgrt_b64enc_finish (state); + if (err) + goto b64fail; + } + return; + + b64fail: + log_error ("error writing base64 encoded notation: %s\n", gpg_strerror (err)); + gpgrt_b64enc_finish (state); +} + + /* Order two signatures. We first order by keyid and then by creation * time. */ int @@ -1278,19 +1308,18 @@ list_signature_print (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node, sigrc = ' '; } - if (sig->sig_class == 0x20 || sig->sig_class == 0x28 - || sig->sig_class == 0x30) + if (IS_KEY_REV (sig) || IS_SUBKEY_REV (sig) || IS_UID_REV (sig)) { sigstr = "rev"; reason_code = get_revocation_reason (sig, &reason_text, &reason_comment, &reason_commentlen); } - else if ((sig->sig_class & ~3) == 0x10) + else if (IS_UID_SIG (sig)) sigstr = "sig"; - else if (sig->sig_class == 0x18) + else if (IS_SUBKEY_SIG (sig)) sigstr = "sig"; - else if (sig->sig_class == 0x1F) + else if (IS_KEY_SIG (sig)) sigstr = "sig"; else { @@ -1337,13 +1366,27 @@ list_signature_print (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node, show_policy_url (sig, 3, 0); if (sig->flags.notation && (opt.list_options & LIST_SHOW_NOTATIONS)) - show_notation (sig, 3, 0, - ((opt. - list_options & LIST_SHOW_STD_NOTATIONS) ? 1 : 0) - + - ((opt. - list_options & LIST_SHOW_USER_NOTATIONS) ? 2 : - 0)); + show_notation (sig, 3, 0, + ((opt. + list_options & LIST_SHOW_STD_NOTATIONS) ? 1 : 0) + + + ((opt. + list_options & LIST_SHOW_USER_NOTATIONS) ? 2 : + 0)); + + if (sig->flags.notation + && (opt.list_options & LIST_SHOW_X509_NOTATIONS)) + { + struct notation *nots; + + if ((IS_KEY_SIG (sig) || IS_SUBKEY_SIG (sig)) + && (nots = search_sig_notations (sig, + "x509certificate@pgp.com"))) + { + print_x509_notations (nots); + free_notation (nots); + } + } if (sig->flags.pref_ks && (opt.list_options & LIST_SHOW_KEYSERVER_URLS)) @@ -1599,7 +1642,7 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr, if (opt.with_key_screening) print_pk_screening (pk2, 0); } - else if (opt.list_sigs + else if ((opt.list_sigs || (opt.list_options & LIST_SHOW_X509_NOTATIONS)) && node->pkt->pkttype == PKT_SIGNATURE && !skip_sigs) { kbnode_t n; diff --git a/g10/options.h b/g10/options.h index 476c30ad5..e4303a801 100644 --- a/g10/options.h +++ b/g10/options.h @@ -444,6 +444,7 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode; #define LIST_SHOW_PREF (1<<14) #define LIST_SHOW_PREF_VERBOSE (1<<15) #define LIST_SHOW_UNUSABLE_SIGS (1<<16) +#define LIST_SHOW_X509_NOTATIONS (1<<17) #define VERIFY_SHOW_PHOTOS (1<<0) #define VERIFY_SHOW_POLICY_URLS (1<<1) diff --git a/g10/packet.h b/g10/packet.h index 76ec78017..a13d3cdc8 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -602,8 +602,8 @@ struct notation /* Sometimes we want to %-expand the value. In these cases, we save that transformed value here. */ char *altvalue; - /* If the notation is not human readable, then the value is stored - here. */ + /* If the notation is not human readable or the function does not + want to distinguish that, then the value is stored here. */ unsigned char *bdat; /* The amount of data stored in BDAT. @@ -877,7 +877,8 @@ struct notation *string_to_notation(const char *string,int is_utf8); struct notation *blob_to_notation(const char *name, const char *data, size_t len); struct notation *sig_to_notation(PKT_signature *sig); -void free_notation(struct notation *notation); +struct notation *search_sig_notations (PKT_signature *sig, const char *name); +void free_notation (struct notation *notation); /*-- free-packet.c --*/ void free_symkey_enc( PKT_symkey_enc *enc );