diff options
Diffstat (limited to 'g10/keylist.c')
-rw-r--r-- | g10/keylist.c | 454 |
1 files changed, 284 insertions, 170 deletions
diff --git a/g10/keylist.c b/g10/keylist.c index cc1e23d7f..81d6805a5 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -82,7 +82,7 @@ static estream_t attrib_fp; -static void list_keyblock (ctrl_t ctrl, +static gpg_error_t list_keyblock (ctrl_t ctrl, kbnode_t keyblock, int secret, int has_secret, int fpr, struct keylist_context *listctx); @@ -745,6 +745,7 @@ list_all (ctrl_t ctrl, int secret, int mark_secret) int any_secret; const char *lastresname, *resname; struct keylist_context listctx; + gpg_error_t listerr = 0; memset (&listctx, 0, sizeof (listctx)); if (opt.check_sigs) @@ -802,13 +803,13 @@ list_all (ctrl_t ctrl, int secret, int mark_secret) } } merge_keys_and_selfsig (ctrl, keyblock); - list_keyblock (ctrl, keyblock, secret, any_secret, opt.fingerprint, - &listctx); + listerr = list_keyblock (ctrl, keyblock, secret, any_secret, + opt.fingerprint, &listctx); } release_kbnode (keyblock); keyblock = NULL; } - while (!(rc = keydb_search_next (hd))); + while (!listerr && !(rc = keydb_search_next (hd))); es_fflush (es_stdout); if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND) log_error ("keydb_search_next failed: %s\n", gpg_strerror (rc)); @@ -839,6 +840,7 @@ list_one (ctrl_t ctrl, strlist_t names, int secret, int mark_secret) const char *keyring_str = _("Keyring"); int i; struct keylist_context listctx; + gpg_error_t listerr = 0; memset (&listctx, 0, sizeof (listctx)); if (!secret && opt.check_sigs) @@ -887,12 +889,12 @@ list_one (ctrl_t ctrl, strlist_t names, int secret, int mark_secret) es_putc ('-', es_stdout); es_putc ('\n', es_stdout); } - list_keyblock (ctrl, keyblock, secret, any_secret, - opt.fingerprint, &listctx); + listerr = list_keyblock (ctrl, keyblock, secret, any_secret, + opt.fingerprint, &listctx); } release_kbnode (keyblock); } - while (!getkey_next (ctrl, ctx, NULL, &keyblock)); + while (!listerr && !getkey_next (ctrl, ctx, NULL, &keyblock)); getkey_end (ctrl, ctx); if (opt.check_sigs && !opt.with_colons) @@ -910,12 +912,13 @@ locate_one (ctrl_t ctrl, strlist_t names, int no_local) GETKEY_CTX ctx = NULL; KBNODE keyblock = NULL; struct keylist_context listctx; + gpg_error_t listerr = 0; memset (&listctx, 0, sizeof (listctx)); if (opt.check_sigs) listctx.check_sigs = 1; - for (sl = names; sl; sl = sl->next) + for (sl = names; sl && !listerr; sl = sl->next) { rc = get_best_pubkey_byname (ctrl, no_local? GET_PUBKEY_NO_LOCAL @@ -933,10 +936,11 @@ locate_one (ctrl_t ctrl, strlist_t names, int no_local) { do { - list_keyblock (ctrl, keyblock, 0, 0, opt.fingerprint, &listctx); + listerr = list_keyblock (ctrl, keyblock, 0, 0, + opt.fingerprint, &listctx); release_kbnode (keyblock); } - while (ctx && !getkey_next (ctrl, ctx, NULL, &keyblock)); + while (!listerr && ctx && !getkey_next (ctrl, ctx, NULL, &keyblock)); getkey_end (ctrl, ctx); ctx = NULL; } @@ -1171,6 +1175,77 @@ dump_attribs (const PKT_user_id *uid, PKT_public_key *pk) } +static void +print_keygrip (const char *keygrip) +{ + const char *s; + + s = strchr (keygrip, ','); + if (s) + es_fprintf (es_stdout, " Keygrip = %.*s,\n%*s%s\n", + (int)(s-keygrip), keygrip, 16, "", s+1); + else + es_fprintf (es_stdout, " Keygrip = %s\n", keygrip); +} + + +/* If PK is given the output is written to a new file instead of + * stdout. */ +static void +print_x509_notations (struct notation *nots, PKT_public_key *pk) +{ + gpg_error_t err; + gpgrt_b64state_t state = NULL; + char hexfpr[2*4 + 1 + 2*MAX_FINGERPRINT_LEN+4+1]; + char sha1[20]; + estream_t fp; + + for (; nots; nots = nots->next) + { + if (pk) + { + gcry_md_hash_buffer (GCRY_MD_SHA1, sha1, nots->bdat, nots->blen); + bin2hex (sha1+16, 4, hexfpr); + hexfpr[2*4] = '-'; + hexfingerprint (pk, hexfpr + 2*4+1, 2*MAX_FINGERPRINT_LEN); + strcat (hexfpr, ".pem"); + fp = es_fopen (hexfpr, "w"); + if (!fp) + { + err = gpg_err_code_from_syserror (); + goto b64fail; + } + } + else + fp = es_stdout; + state = gpgrt_b64enc_start (fp, "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; + if (fp != es_stdout) + { + es_fclose (fp); + fp = NULL; + } + } + return; + + b64fail: + log_error ("error writing base64 encoded notation: %s\n", gpg_strerror (err)); + gpgrt_b64enc_finish (state); + if (fp && fp != es_stdout) + gpgrt_fcancel (fp); +} + + /* Order two signatures. We first order by keyid and then by creation * time. */ int @@ -1220,170 +1295,186 @@ cmp_signodes (const void *av, const void *bv) * NODFLG_MARK_B to indicate self-signatures. */ static void list_signature_print (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node, - struct keylist_context *listctx) + struct keylist_context *listctx, PKT_public_key *lastpk) { - /* (extra indentation to keep the diff history short) */ - PKT_signature *sig = node->pkt->pkt.signature; - int rc, sigrc; - char *sigstr; - char *reason_text = NULL; - char *reason_comment = NULL; - size_t reason_commentlen; - int reason_code = 0; + PKT_signature *sig = node->pkt->pkt.signature; + int rc, sigrc; + char *sigstr; + char *reason_text = NULL; + char *reason_comment = NULL; + size_t reason_commentlen; + int reason_code = 0; + + if (listctx->check_sigs) + { + rc = check_key_signature (ctrl, keyblock, node, NULL); + switch (gpg_err_code (rc)) + { + case 0: + listctx->good_sigs++; + sigrc = '!'; + break; + case GPG_ERR_BAD_SIGNATURE: + listctx->inv_sigs++; + sigrc = '-'; + break; + case GPG_ERR_NO_PUBKEY: + case GPG_ERR_UNUSABLE_PUBKEY: + listctx->no_key++; + return; + case GPG_ERR_DIGEST_ALGO: + case GPG_ERR_PUBKEY_ALGO: + if (!(opt.list_options & LIST_SHOW_UNUSABLE_SIGS)) + return; + /* fallthru. */ + default: + listctx->oth_err++; + sigrc = '%'; + break; + } - if (listctx->check_sigs) - { - rc = check_key_signature (ctrl, keyblock, node, NULL); - switch (gpg_err_code (rc)) - { - case 0: - listctx->good_sigs++; - sigrc = '!'; - break; - case GPG_ERR_BAD_SIGNATURE: - listctx->inv_sigs++; - sigrc = '-'; - break; - case GPG_ERR_NO_PUBKEY: - case GPG_ERR_UNUSABLE_PUBKEY: - listctx->no_key++; - return; - case GPG_ERR_DIGEST_ALGO: - case GPG_ERR_PUBKEY_ALGO: - if (!(opt.list_options & LIST_SHOW_UNUSABLE_SIGS)) - return; - /* fallthru. */ - default: - listctx->oth_err++; - sigrc = '%'; - break; - } + /* TODO: Make sure a cached sig record here still has + the pk that issued it. See also + keyedit.c:print_and_check_one_sig */ + } + else + { + if (!(opt.list_options & LIST_SHOW_UNUSABLE_SIGS) + && (gpg_err_code (openpgp_pk_test_algo (sig->pubkey_algo) + == GPG_ERR_PUBKEY_ALGO) + || gpg_err_code (openpgp_md_test_algo (sig->digest_algo) + == GPG_ERR_DIGEST_ALGO) + || (sig->digest_algo == DIGEST_ALGO_SHA1 + && !(node->flag & NODFLG_MARK_B) /*no selfsig*/ + && !opt.flags.allow_weak_key_signatures))) + return; + rc = 0; + sigrc = ' '; + } - /* TODO: Make sure a cached sig record here still has - the pk that issued it. See also - keyedit.c:print_and_check_one_sig */ - } - else - { - if (!(opt.list_options & LIST_SHOW_UNUSABLE_SIGS) - && (gpg_err_code (openpgp_pk_test_algo (sig->pubkey_algo) - == GPG_ERR_PUBKEY_ALGO) - || gpg_err_code (openpgp_md_test_algo (sig->digest_algo) - == GPG_ERR_DIGEST_ALGO) - || (sig->digest_algo == DIGEST_ALGO_SHA1 - && !(node->flag & NODFLG_MARK_B) /*no selfsig*/ - && !opt.flags.allow_weak_key_signatures))) - return; - rc = 0; - sigrc = ' '; - } + 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 (IS_UID_SIG (sig)) + sigstr = "sig"; + else if (IS_SUBKEY_SIG (sig)) + sigstr = "sig"; + else if (IS_KEY_SIG (sig)) + sigstr = "sig"; + else + { + es_fprintf (es_stdout, "sig " + "[unexpected signature class 0x%02x]\n", + sig->sig_class); + return; + } - if (sig->sig_class == 0x20 || sig->sig_class == 0x28 - || sig->sig_class == 0x30) - { - sigstr = "rev"; - reason_code = get_revocation_reason (sig, &reason_text, - &reason_comment, - &reason_commentlen); - } - else if ((sig->sig_class & ~3) == 0x10) - sigstr = "sig"; - else if (sig->sig_class == 0x18) - sigstr = "sig"; - else if (sig->sig_class == 0x1F) - sigstr = "sig"; - else - { - es_fprintf (es_stdout, "sig " - "[unexpected signature class 0x%02x]\n", - sig->sig_class); - return; - } + es_fputs (sigstr, es_stdout); + es_fprintf (es_stdout, "%c%c %c%c%c%c%c%c %s %s", + sigrc, (sig->sig_class - 0x10 > 0 && + sig->sig_class - 0x10 < + 4) ? '0' + sig->sig_class - 0x10 : ' ', + sig->flags.exportable ? ' ' : 'L', + sig->flags.revocable ? ' ' : 'R', + sig->flags.policy_url ? 'P' : ' ', + sig->flags.notation ? 'N' : ' ', + sig->flags.expired ? 'X' : ' ', + (sig->trust_depth > 9) ? 'T' : (sig->trust_depth > + 0) ? '0' + + sig->trust_depth : ' ', keystr (sig->keyid), + datestr_from_sig (sig)); + if (opt.list_options & LIST_SHOW_SIG_EXPIRE) + es_fprintf (es_stdout, " %s", expirestr_from_sig (sig)); + es_fprintf (es_stdout, " "); + if (sigrc == '%') + es_fprintf (es_stdout, "[%s] ", gpg_strerror (rc)); + else if (sigrc == '?') + ; + else if ((node->flag & NODFLG_MARK_B)) + es_fputs (_("[self-signature]"), es_stdout); + else if (!opt.fast_list_mode ) + { + size_t n; + char *p = get_user_id (ctrl, sig->keyid, &n, NULL); + print_utf8_buffer (es_stdout, p, n); + xfree (p); + } + es_putc ('\n', es_stdout); - es_fputs (sigstr, es_stdout); - es_fprintf (es_stdout, "%c%c %c%c%c%c%c%c %s %s", - sigrc, (sig->sig_class - 0x10 > 0 && - sig->sig_class - 0x10 < - 4) ? '0' + sig->sig_class - 0x10 : ' ', - sig->flags.exportable ? ' ' : 'L', - sig->flags.revocable ? ' ' : 'R', - sig->flags.policy_url ? 'P' : ' ', - sig->flags.notation ? 'N' : ' ', - sig->flags.expired ? 'X' : ' ', - (sig->trust_depth > 9) ? 'T' : (sig->trust_depth > - 0) ? '0' + - sig->trust_depth : ' ', keystr (sig->keyid), - datestr_from_sig (sig)); - if (opt.list_options & LIST_SHOW_SIG_EXPIRE) - es_fprintf (es_stdout, " %s", expirestr_from_sig (sig)); - es_fprintf (es_stdout, " "); - if (sigrc == '%') - es_fprintf (es_stdout, "[%s] ", gpg_strerror (rc)); - else if (sigrc == '?') - ; - else if ((node->flag & NODFLG_MARK_B)) - es_fputs (_("[self-signature]"), es_stdout); - else if (!opt.fast_list_mode ) - { - size_t n; - char *p = get_user_id (ctrl, sig->keyid, &n, NULL); - print_utf8_buffer (es_stdout, p, n); - xfree (p); - } - es_putc ('\n', es_stdout); + if (sig->flags.policy_url + && (opt.list_options & LIST_SHOW_POLICY_URLS)) + 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)); + + if (sig->flags.notation + && (opt.list_options + & (LIST_SHOW_X509_NOTATIONS|LIST_STORE_X509_NOTATIONS))) + { + struct notation *nots; - if (sig->flags.policy_url - && (opt.list_options & LIST_SHOW_POLICY_URLS)) - show_policy_url (sig, 3, 0); + if ((IS_KEY_SIG (sig) || IS_SUBKEY_SIG (sig)) + && (nots = search_sig_notations (sig, + "[email protected]"))) + { + if ((opt.list_options & LIST_STORE_X509_NOTATIONS)) + print_x509_notations (nots, lastpk); + else + print_x509_notations (nots, NULL); + free_notation (nots); + } + } - 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)); + if (sig->flags.pref_ks + && (opt.list_options & LIST_SHOW_KEYSERVER_URLS)) + show_keyserver_url (sig, 3, 0); - if (sig->flags.pref_ks - && (opt.list_options & LIST_SHOW_KEYSERVER_URLS)) - show_keyserver_url (sig, 3, 0); + if (reason_text && (reason_code || reason_comment)) + { + es_fprintf (es_stdout, " %s%s\n", + _("reason for revocation: "), reason_text); + if (reason_comment) + { + const byte *s, *s_lf; + size_t n, n_lf; - if (reason_text && (reason_code || reason_comment)) + s = reason_comment; + n = reason_commentlen; + s_lf = NULL; + do { - es_fprintf (es_stdout, " %s%s\n", - _("reason for revocation: "), reason_text); - if (reason_comment) + /* We don't want any empty lines, so we skip them. */ + for (;n && *s == '\n'; s++, n--) + ; + if (n) { - const byte *s, *s_lf; - size_t n, n_lf; - - s = reason_comment; - n = reason_commentlen; - s_lf = NULL; - do - { - /* We don't want any empty lines, so we skip them. */ - for (;n && *s == '\n'; s++, n--) - ; - if (n) - { - s_lf = memchr (s, '\n', n); - n_lf = s_lf? s_lf - s : n; - es_fprintf (es_stdout, " %s", - _("revocation comment: ")); - es_write_sanitized (es_stdout, s, n_lf, NULL, NULL); - es_putc ('\n', es_stdout); - s += n_lf; n -= n_lf; - } - } while (s_lf); + s_lf = memchr (s, '\n', n); + n_lf = s_lf? s_lf - s : n; + es_fprintf (es_stdout, " %s", + _("revocation comment: ")); + es_write_sanitized (es_stdout, s, n_lf, NULL, NULL); + es_putc ('\n', es_stdout); + s += n_lf; n -= n_lf; } - } + } while (s_lf); + } + } - xfree (reason_text); - xfree (reason_comment); + xfree (reason_text); + xfree (reason_comment); - /* fixme: check or list other sigs here */ + /* fixme: check or list other sigs here */ } @@ -1394,6 +1485,7 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr, int rc; kbnode_t node; PKT_public_key *pk; + PKT_public_key *lastpk; u32 *mainkid; int skip_sigs = 0; char *hexgrip = NULL; @@ -1410,6 +1502,7 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr, pk = node->pkt->pkt.public_key; mainkid = pk_keyid (pk); + lastpk = pk; if (secret || opt.with_keygrip) { @@ -1437,7 +1530,7 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr, print_fingerprint (ctrl, NULL, pk, 0); if (opt.with_keygrip && hexgrip) - es_fprintf (es_stdout, " Keygrip = %s\n", hexgrip); + print_keygrip (hexgrip); if (serialno) print_card_serialno (serialno); @@ -1558,6 +1651,7 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr, { PKT_public_key *pk2 = node->pkt->pkt.public_key; + lastpk = pk2; if ((pk2->flags.revoked || pk2->has_expired) && !(opt.list_options & LIST_SHOW_UNUSABLE_SUBKEYS)) { @@ -1593,13 +1687,15 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr, print_card_serialno (serialno); } if (opt.with_keygrip && hexgrip) - es_fprintf (es_stdout, " Keygrip = %s\n", hexgrip); + print_keygrip (hexgrip); if (opt.with_key_data) print_key_data (pk2); 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|LIST_STORE_X509_NOTATIONS))) && node->pkt->pkttype == PKT_SIGNATURE && !skip_sigs) { kbnode_t n; @@ -1627,7 +1723,8 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr, qsort (sigarray, sigcount, sizeof *sigarray, cmp_signodes); for (idx=0; idx < sigcount; idx++) - list_signature_print (ctrl, keyblock, sigarray[idx], listctx); + list_signature_print (ctrl, keyblock, sigarray[idx], listctx, + lastpk); xfree (sigarray); } } @@ -2232,11 +2329,18 @@ reorder_keyblock (KBNODE keyblock) } -static void +/* Note: If this function returns an error the caller is expected to + * honor this and stop all further processing. Any error returned + * will be a write error (to stdout) and a diagnostics is always + * printed using log_error. */ +static gpg_error_t list_keyblock (ctrl_t ctrl, KBNODE keyblock, int secret, int has_secret, int fpr, struct keylist_context *listctx) { + gpg_error_t err = 0; + + es_clearerr (es_stdout); reorder_keyblock (keyblock); if (list_filter.selkey) @@ -2254,7 +2358,7 @@ list_keyblock (ctrl_t ctrl, } } if (!selected) - return; /* Skip this one. */ + return 0; /* Skip this one. */ } if (opt.with_colons) @@ -2268,24 +2372,34 @@ list_keyblock (ctrl_t ctrl, else list_keyblock_print (ctrl, keyblock, secret, fpr, listctx); - if (secret) - es_fflush (es_stdout); + if (es_ferror (es_stdout)) + err = gpg_error_from_syserror (); + + if (secret && es_fflush (es_stdout) && !err) + err = gpg_error_from_syserror (); + + if (err) + log_error (_("error writing to stdout: %s\n"), gpg_strerror (err)); + + return err; } /* Public function used by keygen to list a keyblock. If NO_VALIDITY * is set the validity of a key is never shown. */ -void +gpg_error_t list_keyblock_direct (ctrl_t ctrl, kbnode_t keyblock, int secret, int has_secret, int fpr, int no_validity) { struct keylist_context listctx; + gpg_error_t err; memset (&listctx, 0, sizeof (listctx)); listctx.no_validity = !!no_validity; - list_keyblock (ctrl, keyblock, secret, has_secret, fpr, &listctx); + err = list_keyblock (ctrl, keyblock, secret, has_secret, fpr, &listctx); keylist_context_release (&listctx); + return err; } |