From 23a714598c247d78cfda46a6dc338b17e17cc194 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 12 Apr 2018 16:41:05 +0200 Subject: gpg: Extend the ERRSIG status line with a fingerprint. * g10/mainproc.c (issuer_fpr_raw): New. (issuer_fpr_string): Re-implement using issuer_fpr_rtaw. (check_sig_and_print): Don't free ISSUER_FPR. Use ISSUER_FPR_RAW. Use write_status_printf. Extend ERRSIG status. -- Modern OpenPGP implementations put the ISSUER_FPR into the signature to make it easier to discover the, public needed to check the signature. This is also useful in error messages and thus we add it. Signed-off-by: Werner Koch --- g10/mainproc.c | 57 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 19 deletions(-) (limited to 'g10/mainproc.c') diff --git a/g10/mainproc.c b/g10/mainproc.c index 512d33c59..85828274f 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -1608,6 +1608,26 @@ akl_has_wkd_method (void) } +/* Return the ISSUER fingerprint buffer and its lenbgth at R_LEN. + * Returns NULL if not available. The returned buffer is valid as + * long as SIG is not modified. */ +static const byte * +issuer_fpr_raw (PKT_signature *sig, size_t *r_len) +{ + const byte *p; + size_t n; + + p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &n); + if (p && n == 21 && p[0] == 4) + { + *r_len = n - 1; + return p+1; + } + *r_len = 0; + return NULL; +} + + /* Return the ISSUER fingerprint string in human readbale format if * available. Caller must release the string. */ static char * @@ -1616,10 +1636,8 @@ issuer_fpr_string (PKT_signature *sig) const byte *p; size_t n; - p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &n); - if (p && n == 21 && p[0] == 4) - return bin2hex (p+1, n-1, NULL); - return NULL; + p = issuer_fpr_raw (sig, &n); + return p? bin2hex (p, n, NULL) : NULL; } @@ -1659,7 +1677,7 @@ check_sig_and_print (CTX c, kbnode_t node) int rc; int is_expkey = 0; int is_revkey = 0; - char *issuer_fpr; + char *issuer_fpr = NULL; PKT_public_key *pk = NULL; /* The public key for the signature or NULL. */ int tried_ks_by_fpr; @@ -1786,13 +1804,14 @@ check_sig_and_print (CTX c, kbnode_t node) write_status_text (STATUS_NEWSIG, NULL); astr = openpgp_pk_algo_name ( sig->pubkey_algo ); - if ((issuer_fpr = issuer_fpr_string (sig))) + issuer_fpr = issuer_fpr_string (sig); + + if (issuer_fpr) { log_info (_("Signature made %s\n"), asctimestamp(sig->timestamp)); log_info (_(" using %s key %s\n"), astr? astr: "?", issuer_fpr); - xfree (issuer_fpr); } else if (!keystrlen () || keystrlen () > 8) { @@ -1899,14 +1918,14 @@ check_sig_and_print (CTX c, kbnode_t node) const byte *p; size_t n; - p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &n); - if (p && n == 21 && p[0] == 4) + p = issuer_fpr_raw (sig, &n); + if (p) { /* v4 packet with a SHA-1 fingerprint. */ free_public_key (pk); pk = NULL; glo_ctrl.in_auto_key_retrieve++; - res = keyserver_import_fprint (c->ctrl, p+1, n-1, opt.keyserver, 1); + res = keyserver_import_fprint (c->ctrl, p, n, opt.keyserver, 1); tried_ks_by_fpr = 1; glo_ctrl.in_auto_key_retrieve--; if (!res) @@ -2273,22 +2292,22 @@ check_sig_and_print (CTX c, kbnode_t node) } else { - char buf[50]; - - snprintf (buf, sizeof buf, "%08lX%08lX %d %d %02x %lu %d", - (ulong)sig->keyid[0], (ulong)sig->keyid[1], - sig->pubkey_algo, sig->digest_algo, - sig->sig_class, (ulong)sig->timestamp, gpg_err_code (rc)); - write_status_text (STATUS_ERRSIG, buf); + write_status_printf (STATUS_ERRSIG, "%08lX%08lX %d %d %02x %lu %d %s", + (ulong)sig->keyid[0], (ulong)sig->keyid[1], + sig->pubkey_algo, sig->digest_algo, + sig->sig_class, (ulong)sig->timestamp, + gpg_err_code (rc), + issuer_fpr? issuer_fpr:"-"); if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY) { - buf[16] = 0; - write_status_text (STATUS_NO_PUBKEY, buf); + write_status_printf (STATUS_NO_PUBKEY, "%08lX%08lX", + (ulong)sig->keyid[0], (ulong)sig->keyid[1]); } if (gpg_err_code (rc) != GPG_ERR_NOT_PROCESSED) log_error (_("Can't check signature: %s\n"), gpg_strerror (rc)); } + xfree (issuer_fpr); return rc; } -- cgit From 69c3e7acb744e1e5606a4d946e3b948704cfbbae Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 12 Apr 2018 17:53:17 +0200 Subject: gpg: Extend the "sig" record in --list-mode. * g10/getkey.c (get_user_id_string): Add arg R_NOUID. Change call callers. (get_user_id): Add arg R_NOUID. Change call callers. * g10/mainproc.c (issuer_fpr_string): Make global. * g10/keylist.c (list_keyblock_colon): Print a '?' for a missing key also in --list-mode. Print the "issuer fpr" field also if there is an issuer fingerprint subpacket. -- Scripts used to rely on the "User ID not found" string even in the --with-colons listing. However, that is not a good idea because that string is subject to translations etc. Now we have an explicit way of telling that a key is missing. For example: gpg --list-sigs --with-colons | \ awk -F: '$1=="sig" && $2=="?" {if($13){print $13}else{print $5}}' Prints all keyids or fingerprint of signing keys for which we do not have the key in our local keyring. Signed-off-by: Werner Koch --- doc/DETAILS | 17 ++++++++++++++++- g10/getkey.c | 21 ++++++++++++++------- g10/keydb.h | 8 ++++---- g10/keyedit.c | 2 +- g10/keylist.c | 15 ++++++++++++--- g10/mainproc.c | 5 +++-- g10/packet.h | 2 ++ g10/passphrase.c | 2 +- g10/pkclist.c | 2 +- g10/revoke.c | 2 +- 10 files changed, 55 insertions(+), 21 deletions(-) (limited to 'g10/mainproc.c') diff --git a/doc/DETAILS b/doc/DETAILS index 2d78fecf7..16e77c79a 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -105,6 +105,19 @@ described here. certificate (i.e. for the trust anchor) and an 'f' for all other valid certificates. + In "sig" records, this field may have one of these values as first + character: + + - ! :: Signature is good. + - - :: Signature is bad. + - ? :: No public key to verify signature or public key is not usable. + - % :: Other error verifying a signature + + More values may be added later. The field may also be empty if + gpg has been invoked in a non-checking mode (--list-sigs) or in a + fast checking mode. Since 2.2.7 '?' will also be printed by the + command --list-sigs if the key is not in the local keyring. + *** Field 3 - Key length The length of key in bits. @@ -195,9 +208,11 @@ described here. gpg's --edit-key menu does. For "sig" records, this is the fingerprint of the key that issued - the signature. Note that this is only filled in if the signature + the signature. Note that this may only be filled if the signature verified correctly. Note also that for various technical reasons, this fingerprint is only available if --no-sig-cache is used. + Since 2.2.7 this field will also be set if the key is missing but + the signature carries an issuer fingerprint as meta data. *** Field 14 - Flag field diff --git a/g10/getkey.c b/g10/getkey.c index 0405d1d21..c77b40918 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -4119,15 +4119,20 @@ get_seckey_default_or_card (ctrl_t ctrl, PKT_public_key *pk, *********************************************/ /* Return a string with a printable representation of the user_id. - * this string must be freed by xfree. */ + * this string must be freed by xfree. If R_NOUID is not NULL it is + * set to true if a user id was not found; otherwise to false. */ static char * -get_user_id_string (ctrl_t ctrl, u32 * keyid, int mode, size_t *r_len) +get_user_id_string (ctrl_t ctrl, u32 * keyid, int mode, size_t *r_len, + int *r_nouid) { user_id_db_t r; keyid_list_t a; int pass = 0; char *p; + if (r_nouid) + *r_nouid = 0; + /* Try it two times; second pass reads from the database. */ do { @@ -4174,6 +4179,8 @@ get_user_id_string (ctrl_t ctrl, u32 * keyid, int mode, size_t *r_len) else p = xasprintf ("%s [?]", keystr (keyid)); + if (r_nouid) + *r_nouid = 1; if (r_len) *r_len = strlen (p); return p; @@ -4183,7 +4190,7 @@ get_user_id_string (ctrl_t ctrl, u32 * keyid, int mode, size_t *r_len) char * get_user_id_string_native (ctrl_t ctrl, u32 * keyid) { - char *p = get_user_id_string (ctrl, keyid, 0, NULL); + char *p = get_user_id_string (ctrl, keyid, 0, NULL, NULL); char *p2 = utf8_to_native (p, strlen (p), 0); xfree (p); return p2; @@ -4193,15 +4200,15 @@ get_user_id_string_native (ctrl_t ctrl, u32 * keyid) char * get_long_user_id_string (ctrl_t ctrl, u32 * keyid) { - return get_user_id_string (ctrl, keyid, 1, NULL); + return get_user_id_string (ctrl, keyid, 1, NULL, NULL); } /* Please try to use get_user_byfpr instead of this one. */ char * -get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn) +get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn, int *r_nouid) { - return get_user_id_string (ctrl, keyid, 2, rn); + return get_user_id_string (ctrl, keyid, 2, rn, r_nouid); } @@ -4210,7 +4217,7 @@ char * get_user_id_native (ctrl_t ctrl, u32 *keyid) { size_t rn; - char *p = get_user_id (ctrl, keyid, &rn); + char *p = get_user_id (ctrl, keyid, &rn, NULL); char *p2 = utf8_to_native (p, rn, 0); xfree (p); return p2; diff --git a/g10/keydb.h b/g10/keydb.h index cc99241f5..c5671d665 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -404,10 +404,10 @@ void setup_main_keyids (kbnode_t keyblock); data structures. */ void merge_keys_and_selfsig (ctrl_t ctrl, kbnode_t keyblock); -char*get_user_id_string_native (ctrl_t ctrl, u32 *keyid); -char*get_long_user_id_string (ctrl_t ctrl, u32 *keyid); -char*get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn); -char*get_user_id_native (ctrl_t ctrl, u32 *keyid); +char *get_user_id_string_native (ctrl_t ctrl, u32 *keyid); +char *get_long_user_id_string (ctrl_t ctrl, u32 *keyid); +char *get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn, int *r_nouid); +char *get_user_id_native (ctrl_t ctrl, u32 *keyid); char *get_user_id_byfpr (ctrl_t ctrl, const byte *fpr, size_t *rn); char *get_user_id_byfpr_native (ctrl_t ctrl, const byte *fpr); diff --git a/g10/keyedit.c b/g10/keyedit.c index 7cd883d78..c3eca93a0 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -264,7 +264,7 @@ keyedit_print_one_sig (ctrl_t ctrl, estream_t fp, else { size_t n; - char *p = get_user_id (ctrl, sig->keyid, &n); + char *p = get_user_id (ctrl, sig->keyid, &n, NULL); tty_print_utf8_string2 (fp, p, n, opt.screen_columns - keystrlen () - 26 - ((opt. diff --git a/g10/keylist.c b/g10/keylist.c index 86d1c564f..199cd1330 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -1145,7 +1145,7 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr, else if (!opt.fast_list_mode) { size_t n; - char *p = get_user_id (ctrl, sig->keyid, &n); + char *p = get_user_id (ctrl, sig->keyid, &n, NULL); print_utf8_buffer (es_stdout, p, n); xfree (p); } @@ -1513,6 +1513,7 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock, byte fparray[MAX_FINGERPRINT_LEN]; char *siguid; size_t siguidlen; + char *issuer_fpr = NULL; if (sig->sig_class == 0x20 || sig->sig_class == 0x28 || sig->sig_class == 0x30) @@ -1570,11 +1571,16 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock, else { rc = 0; - sigrc = ' '; + sigrc = ' '; /* Note the fix-up below in --list-sigs mode. */ } if (sigrc != '%' && sigrc != '?' && !opt.fast_list_mode) - siguid = get_user_id (ctrl, sig->keyid, &siguidlen); + { + int nouid; + siguid = get_user_id (ctrl, sig->keyid, &siguidlen, &nouid); + if (!opt.check_sigs && nouid) + sigrc = '?'; /* No key in local keyring. */ + } else { siguid = NULL; @@ -1613,6 +1619,8 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock, for (i = 0; i < fplen; i++) es_fprintf (es_stdout, "%02X", fparray[i]); } + else if ((issuer_fpr = issuer_fpr_string (sig))) + es_fputs (issuer_fpr, es_stdout); es_fprintf (es_stdout, ":::%d:\n", sig->digest_algo); @@ -1621,6 +1629,7 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock, /* fixme: check or list other sigs here */ xfree (siguid); + xfree (issuer_fpr); } } diff --git a/g10/mainproc.c b/g10/mainproc.c index 85828274f..49e728656 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -1209,7 +1209,7 @@ list_node (CTX c, kbnode_t node) } else if (!opt.fast_list_mode) { - p = get_user_id (c->ctrl, sig->keyid, &n); + p = get_user_id (c->ctrl, sig->keyid, &n, NULL); es_write_sanitized (es_stdout, p, n, opt.with_colons?":":NULL, NULL ); xfree (p); @@ -1630,7 +1630,8 @@ issuer_fpr_raw (PKT_signature *sig, size_t *r_len) /* Return the ISSUER fingerprint string in human readbale format if * available. Caller must release the string. */ -static char * +/* FIXME: Move to another file. */ +char * issuer_fpr_string (PKT_signature *sig) { const byte *p; diff --git a/g10/packet.h b/g10/packet.h index 8dca88b75..43c097e72 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -604,6 +604,8 @@ int proc_signature_packets_by_fd (ctrl_t ctrl, int proc_encryption_packets (ctrl_t ctrl, void *ctx, iobuf_t a); int list_packets( iobuf_t a ); +char *issuer_fpr_string (PKT_signature *sig); + /*-- parse-packet.c --*/ /* Sets the packet list mode to MODE (i.e., whether we are dumping a diff --git a/g10/passphrase.c b/g10/passphrase.c index ffdcdf2bd..10574ec6a 100644 --- a/g10/passphrase.c +++ b/g10/passphrase.c @@ -488,7 +488,7 @@ gpg_format_keydesc (ctrl_t ctrl, PKT_public_key *pk, int mode, int escaped) && pk->keyid[1] != pk->main_keyid[1]); algo_name = openpgp_pk_algo_name (pk->pubkey_algo); timestr = strtimestamp (pk->timestamp); - uid = get_user_id (ctrl, is_subkey? pk->main_keyid:pk->keyid, &uidlen); + uid = get_user_id (ctrl, is_subkey? pk->main_keyid:pk->keyid, &uidlen, NULL); orig_codeset = i18n_switchto_utf8 (); diff --git a/g10/pkclist.c b/g10/pkclist.c index 581cae407..dc19204de 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -1149,7 +1149,7 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list) else { size_t n; - char *p = get_user_id (ctrl, keyid, &n ); + char *p = get_user_id (ctrl, keyid, &n, NULL); tty_print_utf8_string ( p, n ); xfree(p); } diff --git a/g10/revoke.c b/g10/revoke.c index 846523295..3a089725c 100644 --- a/g10/revoke.c +++ b/g10/revoke.c @@ -571,7 +571,7 @@ gen_standard_revoke (ctrl_t ctrl, PKT_public_key *psk, const char *cache_nonce) kl = opt.keyid_format == KF_NONE? 0 : keystrlen (); - tmpstr = get_user_id (ctrl, keyid, &len); + tmpstr = get_user_id (ctrl, keyid, &len, NULL); es_fprintf (memfp, "uid%*s%.*s\n\n", kl + 10, "", (int)len, tmpstr); -- cgit From f747b8f0734338baa1e608b193b213aca2c577e8 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 13 Apr 2018 16:42:34 +0900 Subject: g10: Fix memory leak in check_sig_and_print. * g10/mainproc.c (check_sig_and_print): Free the public key. -- GnuPG-bug-id: 3900 Signed-off-by: NIIBE Yutaka --- g10/mainproc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'g10/mainproc.c') diff --git a/g10/mainproc.c b/g10/mainproc.c index 49e728656..c7deeab5f 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -2308,6 +2308,7 @@ check_sig_and_print (CTX c, kbnode_t node) log_error (_("Can't check signature: %s\n"), gpg_strerror (rc)); } + free_public_key (pk); xfree (issuer_fpr); return rc; } -- cgit