Line | Count | Source |
1 | | /* keylist.c - Print information about OpenPGP keys |
2 | | * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, |
3 | | * 2008, 2010, 2012 Free Software Foundation, Inc. |
4 | | * Copyright (C) 2013, 2014 Werner Koch |
5 | | * |
6 | | * This file is part of GnuPG. |
7 | | * |
8 | | * GnuPG is free software; you can redistribute it and/or modify |
9 | | * it under the terms of the GNU General Public License as published by |
10 | | * the Free Software Foundation; either version 3 of the License, or |
11 | | * (at your option) any later version. |
12 | | * |
13 | | * GnuPG is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | * GNU General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU General Public License |
19 | | * along with this program; if not, see <https://www.gnu.org/licenses/>. |
20 | | */ |
21 | | |
22 | | #include <config.h> |
23 | | #include <stdio.h> |
24 | | #include <stdlib.h> |
25 | | #include <string.h> |
26 | | #include <errno.h> |
27 | | #ifdef HAVE_DOSISH_SYSTEM |
28 | | # include <fcntl.h> /* for setmode() */ |
29 | | #endif |
30 | | |
31 | | #include "gpg.h" |
32 | | #include "options.h" |
33 | | #include "packet.h" |
34 | | #include "../common/status.h" |
35 | | #include "keydb.h" |
36 | | #include "photoid.h" |
37 | | #include "../common/util.h" |
38 | | #include "../common/ttyio.h" |
39 | | #include "trustdb.h" |
40 | | #include "main.h" |
41 | | #include "../common/i18n.h" |
42 | | #include "../common/status.h" |
43 | | #include "call-agent.h" |
44 | | #include "../common/mbox-util.h" |
45 | | #include "../common/zb32.h" |
46 | | #include "tofu.h" |
47 | | #include "../common/init.h" |
48 | | #include "../common/recsel.h" |
49 | | #include "../common/compliance.h" |
50 | | #include "../common/pkscreening.h" |
51 | | |
52 | | |
53 | | static void list_all (ctrl_t, int, int); |
54 | | static void list_one (ctrl_t ctrl, |
55 | | strlist_t names, int secret, int mark_secret); |
56 | | static void locate_one (ctrl_t ctrl, strlist_t names, int no_local); |
57 | | static void print_card_serialno (const char *serialno); |
58 | | |
59 | | struct keylist_context |
60 | | { |
61 | | int check_sigs; /* If set signatures shall be verified. */ |
62 | | int good_sigs; /* Counter used if CHECK_SIGS is set. */ |
63 | | int inv_sigs; /* Counter used if CHECK_SIGS is set. */ |
64 | | int no_key; /* Counter used if CHECK_SIGS is set. */ |
65 | | int oth_err; /* Counter used if CHECK_SIGS is set. */ |
66 | | int no_validity; /* Do not show validity. */ |
67 | | }; |
68 | | |
69 | | /* An object and a global instance to store selectors created from |
70 | | * --list-filter select=EXPR. |
71 | | */ |
72 | | struct list_filter_s |
73 | | { |
74 | | recsel_expr_t selkey; |
75 | | }; |
76 | | struct list_filter_s list_filter; |
77 | | |
78 | | |
79 | | /* The stream used to write attribute packets to. */ |
80 | | static estream_t attrib_fp; |
81 | | |
82 | | |
83 | | |
84 | | |
85 | | static gpg_error_t list_keyblock (ctrl_t ctrl, |
86 | | kbnode_t keyblock, int secret, int has_secret, |
87 | | int fpr, struct keylist_context *listctx); |
88 | | |
89 | | /* Release resources from a keylist context. */ |
90 | | static void |
91 | | keylist_context_release (struct keylist_context *listctx) |
92 | 1 | { |
93 | 1 | (void)listctx; /* Nothing to release. */ |
94 | 1 | } |
95 | | |
96 | | |
97 | | static void |
98 | | release_list_filter (struct list_filter_s *filt) |
99 | 0 | { |
100 | 0 | recsel_release (filt->selkey); |
101 | 0 | filt->selkey = NULL; |
102 | 0 | } |
103 | | |
104 | | |
105 | | static void |
106 | | cleanup_keylist_globals (void) |
107 | 0 | { |
108 | 0 | release_list_filter (&list_filter); |
109 | 0 | } |
110 | | |
111 | | |
112 | | /* Parse and set an list filter from string. STRING has the format |
113 | | * "NAME=EXPR" with NAME being the name of the filter. Spaces before |
114 | | * and after NAME are not allowed. If this function is all called |
115 | | * several times all expressions for the same NAME are concatenated. |
116 | | * Supported filter names are: |
117 | | * |
118 | | * - select :: If the expression evaluates to true for a certain key |
119 | | * this key will be listed. The expression may use any |
120 | | * variable defined for the export and import filters. |
121 | | * |
122 | | */ |
123 | | gpg_error_t |
124 | | parse_and_set_list_filter (const char *string) |
125 | 0 | { |
126 | 0 | gpg_error_t err; |
127 | | |
128 | | /* Auto register the cleanup function. */ |
129 | 0 | register_mem_cleanup_func (cleanup_keylist_globals); |
130 | |
|
131 | 0 | if (!strncmp (string, "select=", 7)) |
132 | 0 | err = recsel_parse_expr (&list_filter.selkey, string+7); |
133 | 0 | else |
134 | 0 | err = gpg_error (GPG_ERR_INV_NAME); |
135 | 0 | if (!err && DBG_RECSEL) |
136 | 0 | recsel_dump (list_filter.selkey); |
137 | |
|
138 | 0 | return err; |
139 | 0 | } |
140 | | |
141 | | |
142 | | /* List the keys. If list is NULL, all available keys are listed. |
143 | | * With LOCATE_MODE set the locate algorithm is used to find a key; if |
144 | | * in addition NO_LOCAL is set the locate does not look into the local |
145 | | * keyring. */ |
146 | | void |
147 | | public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode, int no_local) |
148 | 1 | { |
149 | 1 | #ifndef NO_TRUST_MODELS |
150 | 1 | if (opt.with_colons) |
151 | 0 | { |
152 | 0 | byte trust_model, marginals, completes, cert_depth, min_cert_level; |
153 | 0 | ulong created, nextcheck; |
154 | |
|
155 | 0 | read_trust_options (ctrl, &trust_model, &created, &nextcheck, |
156 | 0 | &marginals, &completes, &cert_depth, &min_cert_level); |
157 | |
|
158 | 0 | es_fprintf (es_stdout, "tru:"); |
159 | |
|
160 | 0 | if (nextcheck && nextcheck <= make_timestamp ()) |
161 | 0 | es_fprintf (es_stdout, "o"); |
162 | 0 | if (trust_model != opt.trust_model) |
163 | 0 | es_fprintf (es_stdout, "t"); |
164 | 0 | if (opt.trust_model == TM_PGP || opt.trust_model == TM_CLASSIC |
165 | 0 | || opt.trust_model == TM_TOFU_PGP) |
166 | 0 | { |
167 | 0 | if (marginals != opt.marginals_needed) |
168 | 0 | es_fprintf (es_stdout, "m"); |
169 | 0 | if (completes != opt.completes_needed) |
170 | 0 | es_fprintf (es_stdout, "c"); |
171 | 0 | if (cert_depth != opt.max_cert_depth) |
172 | 0 | es_fprintf (es_stdout, "d"); |
173 | 0 | if (min_cert_level != opt.min_cert_level) |
174 | 0 | es_fprintf (es_stdout, "l"); |
175 | 0 | } |
176 | |
|
177 | 0 | es_fprintf (es_stdout, ":%d:%lu:%lu", trust_model, created, nextcheck); |
178 | | |
179 | | /* Only show marginals, completes, and cert_depth in the classic |
180 | | or PGP trust models since they are not meaningful |
181 | | otherwise. */ |
182 | |
|
183 | 0 | if (trust_model == TM_PGP || trust_model == TM_CLASSIC) |
184 | 0 | es_fprintf (es_stdout, ":%d:%d:%d", marginals, completes, cert_depth); |
185 | 0 | es_fprintf (es_stdout, "\n"); |
186 | 0 | } |
187 | 1 | #endif /*!NO_TRUST_MODELS*/ |
188 | | |
189 | | /* We need to do the stale check right here because it might need to |
190 | | update the keyring while we already have the keyring open. This |
191 | | is very bad for W32 because of a sharing violation. For real OSes |
192 | | it might lead to false results if we are later listing a keyring |
193 | | which is associated with the inode of a deleted file. */ |
194 | 1 | check_trustdb_stale (ctrl); |
195 | | |
196 | | #ifdef USE_TOFU |
197 | | tofu_begin_batch_update (ctrl); |
198 | | #endif |
199 | | |
200 | 1 | if (locate_mode) |
201 | 0 | locate_one (ctrl, list, no_local); |
202 | 1 | else if (!list) |
203 | 1 | list_all (ctrl, 0, opt.with_secret); |
204 | 0 | else |
205 | 0 | list_one (ctrl, list, 0, opt.with_secret); |
206 | | |
207 | | #ifdef USE_TOFU |
208 | | tofu_end_batch_update (ctrl); |
209 | | #endif |
210 | 1 | } |
211 | | |
212 | | |
213 | | void |
214 | | secret_key_list (ctrl_t ctrl, strlist_t list) |
215 | 0 | { |
216 | 0 | (void)ctrl; |
217 | |
|
218 | 0 | check_trustdb_stale (ctrl); |
219 | |
|
220 | 0 | if (!list) |
221 | 0 | list_all (ctrl, 1, 0); |
222 | 0 | else /* List by user id */ |
223 | 0 | list_one (ctrl, list, 1, 0); |
224 | 0 | } |
225 | | |
226 | | |
227 | | /* Helper for print_key_info and print_key_info_log. */ |
228 | | static char * |
229 | | format_key_info (ctrl_t ctrl, PKT_public_key *pk, int secret) |
230 | 0 | { |
231 | 0 | u32 keyid[2]; |
232 | 0 | char *p; |
233 | 0 | char pkstrbuf[PUBKEY_STRING_SIZE]; |
234 | 0 | char *result; |
235 | |
|
236 | 0 | keyid_from_pk (pk, keyid); |
237 | | |
238 | | /* If the pk was chosen by a particular user ID, that is the one to |
239 | | print. */ |
240 | 0 | if (pk->user_id) |
241 | 0 | p = utf8_to_native (pk->user_id->name, pk->user_id->len, 0); |
242 | 0 | else |
243 | 0 | p = get_user_id_native (ctrl, keyid); |
244 | |
|
245 | 0 | result = xtryasprintf ("%s %s/%s %s %s", |
246 | 0 | secret? (pk->flags.primary? "sec":"ssb") |
247 | 0 | /* */ : (pk->flags.primary? "pub":"sub"), |
248 | 0 | pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), |
249 | 0 | keystr (keyid), datestr_from_pk (pk), p); |
250 | 0 | xfree (p); |
251 | 0 | return result; |
252 | 0 | } |
253 | | |
254 | | |
255 | | /* Print basic information about a public or secret key. With FP |
256 | | * passed as NULL, the tty output interface is used, otherwise output |
257 | | * is directed to the given stream. INDENT gives the requested |
258 | | * indentation; if that is a negative value indentation is suppressed |
259 | | * for the first line. SECRET tells that the PK has a secret part. |
260 | | * FIXME: This is similar in use to print_key_line and thus both |
261 | | * functions should eventually be united. |
262 | | */ |
263 | | void |
264 | | print_key_info (ctrl_t ctrl, estream_t fp, |
265 | | int indent, PKT_public_key *pk, int secret) |
266 | 0 | { |
267 | 0 | int indentabs = indent >= 0? indent : -indent; |
268 | 0 | char *info; |
269 | | |
270 | | /* Note: Negative values for INDENT are not yet needed. */ |
271 | |
|
272 | 0 | info = format_key_info (ctrl, pk, secret); |
273 | |
|
274 | 0 | if (!fp && indent >= 0) |
275 | 0 | tty_printf ("\n"); /* (Backward compatibility to old code) */ |
276 | 0 | tty_fprintf (fp, "%*s%s\n", indentabs, "", |
277 | 0 | info? info : "[Ooops - out of core]"); |
278 | |
|
279 | 0 | xfree (info); |
280 | 0 | } |
281 | | |
282 | | |
283 | | /* Same as print_key_info put print using the log functions at |
284 | | * LOGLEVEL. */ |
285 | | void |
286 | | print_key_info_log (ctrl_t ctrl, int loglevel, |
287 | | int indent, PKT_public_key *pk, int secret) |
288 | 0 | { |
289 | 0 | int indentabs = indent >= 0? indent : -indent; |
290 | 0 | char *info; |
291 | |
|
292 | 0 | info = format_key_info (ctrl, pk, secret); |
293 | |
|
294 | 0 | log_log (loglevel, "%*s%s\n", indentabs, "", |
295 | 0 | info? info : "[Ooops - out of core]"); |
296 | |
|
297 | 0 | xfree (info); |
298 | 0 | } |
299 | | |
300 | | |
301 | | /* Print basic information of a secret key including the card serial |
302 | | number information. */ |
303 | | #ifdef ENABLE_CARD_SUPPORT |
304 | | void |
305 | | print_card_key_info (estream_t fp, kbnode_t keyblock) |
306 | | { |
307 | | kbnode_t node; |
308 | | char *hexgrip; |
309 | | char *serialno; |
310 | | int s2k_char; |
311 | | char pkstrbuf[PUBKEY_STRING_SIZE]; |
312 | | int indent; |
313 | | |
314 | | for (node = keyblock; node; node = node->next) |
315 | | { |
316 | | if (node->pkt->pkttype == PKT_PUBLIC_KEY |
317 | | || node->pkt->pkttype == PKT_PUBLIC_SUBKEY) |
318 | | { |
319 | | int rc; |
320 | | PKT_public_key *pk = node->pkt->pkt.public_key; |
321 | | |
322 | | serialno = NULL; |
323 | | rc = hexkeygrip_from_pk (pk, &hexgrip); |
324 | | if (rc) |
325 | | { |
326 | | log_error ("error computing a keygrip: %s\n", gpg_strerror (rc)); |
327 | | s2k_char = '?'; |
328 | | } |
329 | | else if (!agent_get_keyinfo (NULL, hexgrip, &serialno, NULL)) |
330 | | s2k_char = serialno? '>':' '; |
331 | | else |
332 | | s2k_char = '#'; /* Key not found. */ |
333 | | |
334 | | tty_fprintf (fp, "%s%c %s/%s %n", |
335 | | node->pkt->pkttype == PKT_PUBLIC_KEY ? "sec" : "ssb", |
336 | | s2k_char, |
337 | | pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), |
338 | | keystr_from_pk (pk), |
339 | | &indent); |
340 | | tty_fprintf (fp, _("created: %s"), datestr_from_pk (pk)); |
341 | | tty_fprintf (fp, " "); |
342 | | tty_fprintf (fp, _("expires: %s"), expirestr_from_pk (pk)); |
343 | | if (serialno) |
344 | | { |
345 | | tty_fprintf (fp, "\n%*s%s", indent, "", _("card-no: ")); |
346 | | if (strlen (serialno) == 32 |
347 | | && !strncmp (serialno, "D27600012401", 12)) |
348 | | { |
349 | | /* This is an OpenPGP card. Print the relevant part. */ |
350 | | /* Example: D2760001240101010001000003470000 */ |
351 | | /* xxxxyyyyyyyy */ |
352 | | tty_fprintf (fp, "%.*s %.*s", 4, serialno+16, 8, serialno+20); |
353 | | } |
354 | | else |
355 | | tty_fprintf (fp, "%s", serialno); |
356 | | } |
357 | | tty_fprintf (fp, "\n"); |
358 | | xfree (hexgrip); |
359 | | xfree (serialno); |
360 | | } |
361 | | } |
362 | | } |
363 | | #endif /*ENABLE_CARD_SUPPORT*/ |
364 | | |
365 | | |
366 | | /* Print the preferences line. Allowed values for MODE are: |
367 | | * -1 - print to the TTY |
368 | | * 0 - print to stdout. |
369 | | * 1 - use log_info |
370 | | * 2 - print colon delimited pfc record to stdout. |
371 | | */ |
372 | | void |
373 | | show_preferences (PKT_user_id *uid, int indent, int mode, int verbose) |
374 | 0 | { |
375 | 0 | estream_t fp; |
376 | 0 | const prefitem_t fake = { 0, 0 }; |
377 | 0 | const prefitem_t *prefs; |
378 | 0 | int i; |
379 | |
|
380 | 0 | if (!uid) |
381 | 0 | return; |
382 | | |
383 | 0 | if (uid->prefs) |
384 | 0 | prefs = uid->prefs; |
385 | 0 | else if (verbose) |
386 | 0 | prefs = &fake; |
387 | 0 | else |
388 | 0 | return; |
389 | | |
390 | 0 | if (mode < 0 ) |
391 | 0 | fp = NULL; |
392 | 0 | else if (mode == 1) |
393 | 0 | fp = log_get_stream (); |
394 | 0 | else /* Mode 0 or 2 */ |
395 | 0 | fp = es_stdout; |
396 | |
|
397 | 0 | if (mode == 2) /* Print preference record. */ |
398 | 0 | { |
399 | 0 | static char ptypes[] = { PREFTYPE_SYM, PREFTYPE_HASH, |
400 | 0 | PREFTYPE_ZIP, PREFTYPE_AEAD }; |
401 | 0 | int t, any; |
402 | |
|
403 | 0 | es_fputs ("pfc::", fp); /* Second field is RFU */ |
404 | 0 | for (t=0; t < DIM (ptypes); t++) |
405 | 0 | { |
406 | 0 | any = 0; |
407 | 0 | for (i = 0; prefs[i].type; i++) |
408 | 0 | if (prefs[i].type == ptypes[t]) |
409 | 0 | { |
410 | 0 | es_fprintf (fp, "%s%d", any? ",":"", prefs[i].value); |
411 | 0 | any = 1; |
412 | 0 | } |
413 | 0 | es_putc (':', fp); |
414 | 0 | } |
415 | 0 | es_putc (':', fp); /* Two more reserved fields. */ |
416 | 0 | es_putc (':', fp); |
417 | 0 | any = 0; |
418 | 0 | if (uid->flags.mdc) |
419 | 0 | { es_fprintf (fp, "mdc"); any = 1; } |
420 | 0 | if (uid->flags.aead) |
421 | 0 | { es_fprintf (fp, "%saead", any?",":""); any = 1; }; |
422 | 0 | if (!uid->flags.ks_modify) |
423 | 0 | { es_fprintf (fp, "%sno-ks-modify", any?",":""); } |
424 | 0 | es_putc (':', fp); /* One final colon for easier reading. */ |
425 | 0 | es_putc ('\n', fp); |
426 | 0 | } |
427 | 0 | else if (verbose) |
428 | 0 | { |
429 | 0 | int any, des_seen = 0, sha1_seen = 0, uncomp_seen = 0; |
430 | |
|
431 | 0 | tty_fprintf (fp, "%*s %s", indent, "", _("Cipher: ")); |
432 | 0 | for (i = any = 0; prefs[i].type; i++) |
433 | 0 | { |
434 | 0 | if (prefs[i].type == PREFTYPE_SYM) |
435 | 0 | { |
436 | 0 | if (any) |
437 | 0 | tty_fprintf (fp, ", "); |
438 | 0 | any = 1; |
439 | | /* We don't want to display strings for experimental algos */ |
440 | 0 | if (!openpgp_cipher_test_algo (prefs[i].value) |
441 | 0 | && prefs[i].value < 100) |
442 | 0 | tty_fprintf (fp, "%s", openpgp_cipher_algo_name (prefs[i].value)); |
443 | 0 | else |
444 | 0 | tty_fprintf (fp, "[%d]", prefs[i].value); |
445 | 0 | if (prefs[i].value == CIPHER_ALGO_3DES) |
446 | 0 | des_seen = 1; |
447 | 0 | } |
448 | 0 | } |
449 | 0 | if (!des_seen) |
450 | 0 | { |
451 | 0 | if (any) |
452 | 0 | tty_fprintf (fp, ", "); |
453 | 0 | tty_fprintf (fp, "%s", openpgp_cipher_algo_name (CIPHER_ALGO_3DES)); |
454 | 0 | } |
455 | 0 | tty_fprintf (fp, "\n%*s %s", indent, "", _("AEAD: ")); |
456 | 0 | for (i = any = 0; prefs[i].type; i++) |
457 | 0 | { |
458 | 0 | if (prefs[i].type == PREFTYPE_AEAD) |
459 | 0 | { |
460 | 0 | if (any) |
461 | 0 | tty_fprintf (fp, ", "); |
462 | 0 | any = 1; |
463 | | /* We don't want to display strings for experimental algos */ |
464 | 0 | if (!openpgp_aead_test_algo (prefs[i].value) |
465 | 0 | && prefs[i].value < 100) |
466 | 0 | tty_fprintf (fp, "%s", openpgp_aead_algo_name (prefs[i].value)); |
467 | 0 | else |
468 | 0 | tty_fprintf (fp, "[%d]", prefs[i].value); |
469 | 0 | } |
470 | 0 | } |
471 | 0 | tty_fprintf (fp, "\n%*s %s", indent, "", _("Digest: ")); |
472 | 0 | for (i = any = 0; prefs[i].type; i++) |
473 | 0 | { |
474 | 0 | if (prefs[i].type == PREFTYPE_HASH) |
475 | 0 | { |
476 | 0 | if (any) |
477 | 0 | tty_fprintf (fp, ", "); |
478 | 0 | any = 1; |
479 | | /* We don't want to display strings for experimental algos */ |
480 | 0 | if (!gcry_md_test_algo (prefs[i].value) && prefs[i].value < 100) |
481 | 0 | tty_fprintf (fp, "%s", gcry_md_algo_name (prefs[i].value)); |
482 | 0 | else |
483 | 0 | tty_fprintf (fp, "[%d]", prefs[i].value); |
484 | 0 | if (prefs[i].value == DIGEST_ALGO_SHA1) |
485 | 0 | sha1_seen = 1; |
486 | 0 | } |
487 | 0 | } |
488 | 0 | if (!sha1_seen) |
489 | 0 | { |
490 | 0 | if (any) |
491 | 0 | tty_fprintf (fp, ", "); |
492 | 0 | tty_fprintf (fp, "%s", gcry_md_algo_name (DIGEST_ALGO_SHA1)); |
493 | 0 | } |
494 | 0 | tty_fprintf (fp, "\n%*s %s", indent, "", _("Compression: ")); |
495 | 0 | for (i = any = 0; prefs[i].type; i++) |
496 | 0 | { |
497 | 0 | if (prefs[i].type == PREFTYPE_ZIP) |
498 | 0 | { |
499 | 0 | const char *s = compress_algo_to_string (prefs[i].value); |
500 | |
|
501 | 0 | if (any) |
502 | 0 | tty_fprintf (fp, ", "); |
503 | 0 | any = 1; |
504 | | /* We don't want to display strings for experimental algos */ |
505 | 0 | if (s && prefs[i].value < 100) |
506 | 0 | tty_fprintf (fp, "%s", s); |
507 | 0 | else |
508 | 0 | tty_fprintf (fp, "[%d]", prefs[i].value); |
509 | 0 | if (prefs[i].value == COMPRESS_ALGO_NONE) |
510 | 0 | uncomp_seen = 1; |
511 | 0 | } |
512 | 0 | } |
513 | 0 | if (!uncomp_seen) |
514 | 0 | { |
515 | 0 | if (any) |
516 | 0 | tty_fprintf (fp, ", "); |
517 | 0 | else |
518 | 0 | { |
519 | 0 | tty_fprintf (fp, "%s", |
520 | 0 | compress_algo_to_string (COMPRESS_ALGO_ZIP)); |
521 | 0 | tty_fprintf (fp, ", "); |
522 | 0 | } |
523 | 0 | tty_fprintf (fp, "%s", compress_algo_to_string (COMPRESS_ALGO_NONE)); |
524 | 0 | } |
525 | 0 | if (uid->flags.mdc || uid->flags.aead || !uid->flags.ks_modify) |
526 | 0 | { |
527 | 0 | tty_fprintf (fp, "\n%*s %s", indent, "", _("Features: ")); |
528 | 0 | any = 0; |
529 | 0 | if (uid->flags.mdc) |
530 | 0 | { |
531 | 0 | tty_fprintf (fp, "MDC"); |
532 | 0 | any = 1; |
533 | 0 | } |
534 | 0 | if (uid->flags.aead) |
535 | 0 | { |
536 | 0 | if (any) |
537 | 0 | tty_fprintf (fp, ", "); |
538 | 0 | tty_fprintf (fp, "AEAD"); |
539 | 0 | } |
540 | 0 | if (!uid->flags.ks_modify) |
541 | 0 | { |
542 | 0 | if (any) |
543 | 0 | tty_fprintf (fp, ", "); |
544 | 0 | tty_fprintf (fp, _("Keyserver no-modify")); |
545 | 0 | } |
546 | 0 | } |
547 | 0 | tty_fprintf (fp, "\n"); |
548 | 0 | } |
549 | 0 | else |
550 | 0 | { |
551 | 0 | tty_fprintf (fp, "%*s", indent, ""); |
552 | 0 | for (i = 0; prefs[i].type; i++) |
553 | 0 | { |
554 | 0 | tty_fprintf (fp, " %c%d", prefs[i].type == PREFTYPE_SYM ? 'S' : |
555 | 0 | prefs[i].type == PREFTYPE_AEAD ? 'A' : |
556 | 0 | prefs[i].type == PREFTYPE_HASH ? 'H' : |
557 | 0 | prefs[i].type == PREFTYPE_ZIP ? 'Z' : '?', |
558 | 0 | prefs[i].value); |
559 | 0 | } |
560 | 0 | if (uid->flags.mdc) |
561 | 0 | tty_fprintf (fp, " [mdc]"); |
562 | 0 | if (uid->flags.aead) |
563 | 0 | tty_fprintf (fp, " [aead]"); |
564 | 0 | if (!uid->flags.ks_modify) |
565 | 0 | tty_fprintf (fp, " [no-ks-modify]"); |
566 | 0 | tty_fprintf (fp, "\n"); |
567 | 0 | } |
568 | 0 | } |
569 | | |
570 | | |
571 | | /* Flags = 0x01 hashed 0x02 critical. */ |
572 | | static void |
573 | | status_one_subpacket (sigsubpkttype_t type, size_t len, int flags, |
574 | | const byte * buf) |
575 | 0 | { |
576 | 0 | char status[40]; |
577 | | |
578 | | /* Don't print these. */ |
579 | 0 | if (len > 256) |
580 | 0 | return; |
581 | | |
582 | 0 | snprintf (status, sizeof status, |
583 | 0 | "%d %u %u ", type, flags, (unsigned int) len); |
584 | |
|
585 | 0 | write_status_text_and_buffer (STATUS_SIG_SUBPACKET, status, buf, len, 0); |
586 | 0 | } |
587 | | |
588 | | |
589 | | /* Print a policy URL. Allowed values for MODE are: |
590 | | * -1 - print to the TTY |
591 | | * 0 - print to stdout. |
592 | | * 1 - use log_info and emit status messages. |
593 | | * 2 - emit only status messages. |
594 | | */ |
595 | | void |
596 | | show_policy_url (PKT_signature * sig, int indent, int mode) |
597 | 0 | { |
598 | 0 | const byte *p; |
599 | 0 | size_t len; |
600 | 0 | int seq = 0, crit; |
601 | 0 | estream_t fp = mode < 0? NULL : mode ? log_get_stream () : es_stdout; |
602 | |
|
603 | 0 | while ((p = enum_sig_subpkt (sig, 1, SIGSUBPKT_POLICY, &len, &seq, &crit))) |
604 | 0 | { |
605 | 0 | if (mode != 2) |
606 | 0 | { |
607 | 0 | const char *str; |
608 | |
|
609 | 0 | tty_fprintf (fp, "%*s", indent, ""); |
610 | |
|
611 | 0 | if (crit) |
612 | 0 | str = _("Critical signature policy: "); |
613 | 0 | else |
614 | 0 | str = _("Signature policy: "); |
615 | 0 | if (mode > 0) |
616 | 0 | log_info ("%s", str); |
617 | 0 | else |
618 | 0 | tty_fprintf (fp, "%s", str); |
619 | 0 | tty_print_utf8_string2 (fp, p, len, 0); |
620 | 0 | tty_fprintf (fp, "\n"); |
621 | 0 | } |
622 | |
|
623 | 0 | if (mode > 0) |
624 | 0 | write_status_buffer (STATUS_POLICY_URL, p, len, 0); |
625 | 0 | } |
626 | 0 | } |
627 | | |
628 | | |
629 | | /* Print a keyserver URL. Allowed values for MODE are: |
630 | | * -1 - print to the TTY |
631 | | * 0 - print to stdout. |
632 | | * 1 - use log_info and emit status messages. |
633 | | * 2 - emit only status messages. |
634 | | */ |
635 | | void |
636 | | show_keyserver_url (PKT_signature * sig, int indent, int mode) |
637 | 0 | { |
638 | 0 | const byte *p; |
639 | 0 | size_t len; |
640 | 0 | int seq = 0, crit; |
641 | 0 | estream_t fp = mode < 0? NULL : mode ? log_get_stream () : es_stdout; |
642 | |
|
643 | 0 | while ((p = enum_sig_subpkt (sig, 1, SIGSUBPKT_PREF_KS, &len, &seq, &crit))) |
644 | 0 | { |
645 | 0 | if (mode != 2) |
646 | 0 | { |
647 | 0 | const char *str; |
648 | |
|
649 | 0 | tty_fprintf (fp, "%*s", indent, ""); |
650 | |
|
651 | 0 | if (crit) |
652 | 0 | str = _("Critical preferred keyserver: "); |
653 | 0 | else |
654 | 0 | str = _("Preferred keyserver: "); |
655 | 0 | if (mode > 0) |
656 | 0 | log_info ("%s", str); |
657 | 0 | else |
658 | 0 | tty_fprintf (fp, "%s", str); |
659 | 0 | tty_print_utf8_string2 (fp, p, len, 0); |
660 | 0 | tty_fprintf (fp, "\n"); |
661 | 0 | } |
662 | |
|
663 | 0 | if (mode > 0) |
664 | 0 | status_one_subpacket (SIGSUBPKT_PREF_KS, len, |
665 | 0 | (crit ? 0x02 : 0) | 0x01, p); |
666 | 0 | } |
667 | 0 | } |
668 | | |
669 | | |
670 | | /* Print notation data. Allowed values for MODE are: |
671 | | * -1 - print to the TTY |
672 | | * 0 - print to stdout. |
673 | | * 1 - use log_info and emit status messages. |
674 | | * 2 - emit only status messages. |
675 | | * |
676 | | * Defined bits in WHICH: |
677 | | * 1 - standard notations |
678 | | * 2 - user notations |
679 | | * 4 - print notations normally hidden |
680 | | */ |
681 | | void |
682 | | show_notation (PKT_signature * sig, int indent, int mode, int which) |
683 | 0 | { |
684 | 0 | estream_t fp = mode < 0? NULL : mode ? log_get_stream () : es_stdout; |
685 | 0 | notation_t nd, notations; |
686 | |
|
687 | 0 | if (which == 0) |
688 | 0 | which = 3; |
689 | |
|
690 | 0 | notations = sig_to_notation (sig); |
691 | | |
692 | | /* There may be multiple notations in the same sig. */ |
693 | 0 | for (nd = notations; nd; nd = nd->next) |
694 | 0 | { |
695 | 0 | if (!(which & 4) && !strcmp (nd->name, "manu")) |
696 | 0 | continue; |
697 | | |
698 | 0 | if (mode != 2) |
699 | 0 | { |
700 | 0 | int has_at = !!strchr (nd->name, '@'); |
701 | |
|
702 | 0 | if ((which & 1 && !has_at) || (which & 2 && has_at)) |
703 | 0 | { |
704 | 0 | const char *str; |
705 | |
|
706 | 0 | tty_fprintf (fp, "%*s", indent, ""); |
707 | |
|
708 | 0 | if (nd->flags.critical) |
709 | 0 | str = _("Critical signature notation: "); |
710 | 0 | else |
711 | 0 | str = _("Signature notation: "); |
712 | 0 | if (mode > 0) |
713 | 0 | log_info ("%s", str); |
714 | 0 | else |
715 | 0 | tty_fprintf (fp, "%s", str); |
716 | | /* This is all UTF8 */ |
717 | 0 | tty_print_utf8_string2 (fp, nd->name, strlen (nd->name), 0); |
718 | 0 | tty_fprintf (fp, "="); |
719 | 0 | tty_print_utf8_string2 (fp, nd->value, strlen (nd->value), 0); |
720 | | /* (We need to use log_printf so that the next call to a |
721 | | log function does not insert an extra LF.) */ |
722 | 0 | if (mode > 0) |
723 | 0 | log_printf ("\n"); |
724 | 0 | else |
725 | 0 | tty_fprintf (fp, "\n"); |
726 | 0 | } |
727 | 0 | } |
728 | |
|
729 | 0 | if (mode > 0) |
730 | 0 | { |
731 | 0 | write_status_buffer (STATUS_NOTATION_NAME, |
732 | 0 | nd->name, strlen (nd->name), 0); |
733 | 0 | if (nd->flags.critical || nd->flags.human) |
734 | 0 | write_status_text (STATUS_NOTATION_FLAGS, |
735 | 0 | nd->flags.critical && nd->flags.human? "1 1" : |
736 | 0 | nd->flags.critical? "1 0" : "0 1"); |
737 | 0 | if (!nd->flags.human && nd->bdat && nd->blen) |
738 | 0 | write_status_buffer (STATUS_NOTATION_DATA, |
739 | 0 | nd->bdat, nd->blen, 250); |
740 | 0 | else |
741 | 0 | write_status_buffer (STATUS_NOTATION_DATA, |
742 | 0 | nd->value, strlen (nd->value), 50); |
743 | 0 | } |
744 | 0 | } |
745 | |
|
746 | 0 | free_notation (notations); |
747 | 0 | } |
748 | | |
749 | | |
750 | | /* Output all the notation data in SIG matching a name given by |
751 | | * --print-notation to stdout. */ |
752 | | void |
753 | | print_matching_notations (PKT_signature *sig) |
754 | 0 | { |
755 | 0 | notation_t nd, notations; |
756 | 0 | strlist_t sl; |
757 | 0 | const char *s; |
758 | |
|
759 | 0 | if (!opt.print_notations) |
760 | 0 | return; |
761 | | |
762 | 0 | notations = sig_to_notation (sig); |
763 | 0 | for (nd = notations; nd; nd = nd->next) |
764 | 0 | { |
765 | 0 | for (sl=opt.print_notations; sl; sl = sl->next) |
766 | 0 | if (!strcmp (sl->d, nd->name)) |
767 | 0 | break; |
768 | 0 | if (!sl || !*nd->value) |
769 | 0 | continue; |
770 | 0 | es_fprintf (es_stdout, "%s: ", nd->name); |
771 | 0 | for (s = nd->value; *s; s++) |
772 | 0 | { |
773 | 0 | if (*s == '\n') |
774 | 0 | es_fprintf (es_stdout, "\n%*s", (int)strlen (nd->name)+2, ""); |
775 | 0 | else if (*s >= ' ' || *s != '\t') |
776 | 0 | es_putc (*s, es_stdout); |
777 | 0 | } |
778 | 0 | es_putc ('\n', es_stdout); |
779 | 0 | } |
780 | |
|
781 | 0 | free_notation (notations); |
782 | 0 | } |
783 | | |
784 | | |
785 | | static void |
786 | | print_signature_stats (struct keylist_context *s) |
787 | 0 | { |
788 | 0 | if (!s->check_sigs) |
789 | 0 | return; /* Signature checking was not requested. */ |
790 | | |
791 | | /* Better flush stdout so that the stats are always printed after |
792 | | * the output. */ |
793 | 0 | es_fflush (es_stdout); |
794 | |
|
795 | 0 | if (s->good_sigs) |
796 | 0 | log_info (ngettext("%d good signature\n", |
797 | 0 | "%d good signatures\n", s->good_sigs), s->good_sigs); |
798 | |
|
799 | 0 | if (s->inv_sigs) |
800 | 0 | log_info (ngettext("%d bad signature\n", |
801 | 0 | "%d bad signatures\n", s->inv_sigs), s->inv_sigs); |
802 | |
|
803 | 0 | if (s->no_key) |
804 | 0 | log_info (ngettext("%d signature not checked due to a missing key\n", |
805 | 0 | "%d signatures not checked due to missing keys\n", |
806 | 0 | s->no_key), s->no_key); |
807 | |
|
808 | 0 | if (s->oth_err) |
809 | 0 | log_info (ngettext("%d signature not checked due to an error\n", |
810 | 0 | "%d signatures not checked due to errors\n", |
811 | 0 | s->oth_err), s->oth_err); |
812 | 0 | } |
813 | | |
814 | | |
815 | | /* List all keys. If SECRET is true only secret keys are listed. If |
816 | | MARK_SECRET is true secret keys are indicated in a public key |
817 | | listing. */ |
818 | | static void |
819 | | list_all (ctrl_t ctrl, int secret, int mark_secret) |
820 | 1 | { |
821 | 1 | KEYDB_HANDLE hd; |
822 | 1 | KBNODE keyblock = NULL; |
823 | 1 | int rc = 0; |
824 | 1 | int any_secret; |
825 | 1 | const char *lastresname, *resname; |
826 | 1 | struct keylist_context listctx; |
827 | 1 | gpg_error_t listerr = 0; |
828 | | |
829 | 1 | memset (&listctx, 0, sizeof (listctx)); |
830 | 1 | if (opt.check_sigs) |
831 | 0 | listctx.check_sigs = 1; |
832 | | |
833 | 1 | hd = keydb_new (ctrl); |
834 | 1 | if (!hd) |
835 | 0 | rc = gpg_error_from_syserror (); |
836 | 1 | else |
837 | 1 | rc = keydb_search_first (hd); |
838 | 1 | if (rc) |
839 | 1 | { |
840 | 1 | if (gpg_err_code (rc) != GPG_ERR_NOT_FOUND) |
841 | 1 | log_error ("keydb_search_first failed: %s\n", gpg_strerror (rc)); |
842 | 1 | goto leave; |
843 | 1 | } |
844 | | |
845 | 0 | lastresname = NULL; |
846 | 0 | do |
847 | 0 | { |
848 | 0 | if (secret) |
849 | 0 | glo_ctrl.silence_parse_warnings++; |
850 | 0 | rc = keydb_get_keyblock (hd, &keyblock); |
851 | 0 | if (secret) |
852 | 0 | glo_ctrl.silence_parse_warnings--; |
853 | 0 | if (rc) |
854 | 0 | { |
855 | 0 | if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY) |
856 | 0 | continue; /* Skip legacy keys. */ |
857 | 0 | log_error ("keydb_get_keyblock failed: %s\n", gpg_strerror (rc)); |
858 | 0 | goto leave; |
859 | 0 | } |
860 | | |
861 | 0 | if (secret || mark_secret) |
862 | 0 | any_secret = !agent_probe_any_secret_key (ctrl, keyblock); |
863 | 0 | else |
864 | 0 | any_secret = 0; |
865 | |
|
866 | 0 | if (secret && !any_secret) |
867 | 0 | ; /* Secret key listing requested but this isn't one. */ |
868 | 0 | else |
869 | 0 | { |
870 | 0 | if (!opt.with_colons && !(opt.list_options & LIST_SHOW_ONLY_FPR_MBOX)) |
871 | 0 | { |
872 | 0 | resname = keydb_get_resource_name (hd); |
873 | 0 | if (lastresname != resname) |
874 | 0 | { |
875 | 0 | int i; |
876 | |
|
877 | 0 | es_fprintf (es_stdout, "%s\n", resname); |
878 | 0 | for (i = strlen (resname); i; i--) |
879 | 0 | es_putc ('-', es_stdout); |
880 | 0 | es_putc ('\n', es_stdout); |
881 | 0 | lastresname = resname; |
882 | 0 | } |
883 | 0 | } |
884 | 0 | merge_keys_and_selfsig (ctrl, keyblock); |
885 | 0 | listerr = list_keyblock (ctrl, keyblock, secret, any_secret, |
886 | 0 | opt.fingerprint, &listctx); |
887 | 0 | } |
888 | 0 | release_kbnode (keyblock); |
889 | 0 | keyblock = NULL; |
890 | 0 | } |
891 | 0 | while (!listerr && !(rc = keydb_search_next (hd))); |
892 | 0 | es_fflush (es_stdout); |
893 | 0 | if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND) |
894 | 0 | log_error ("keydb_search_next failed: %s\n", gpg_strerror (rc)); |
895 | 0 | if (keydb_get_skipped_counter (hd)) |
896 | 0 | log_info (ngettext("Warning: %lu key skipped due to its large size\n", |
897 | 0 | "Warning: %lu keys skipped due to their large sizes\n", |
898 | 0 | keydb_get_skipped_counter (hd)), |
899 | 0 | keydb_get_skipped_counter (hd)); |
900 | |
|
901 | 0 | if (opt.check_sigs && !opt.with_colons) |
902 | 0 | print_signature_stats (&listctx); |
903 | |
|
904 | 1 | leave: |
905 | 1 | keylist_context_release (&listctx); |
906 | 1 | release_kbnode (keyblock); |
907 | 1 | keydb_release (hd); |
908 | 1 | } |
909 | | |
910 | | |
911 | | static void |
912 | | list_one (ctrl_t ctrl, strlist_t names, int secret, int mark_secret) |
913 | 0 | { |
914 | 0 | int rc = 0; |
915 | 0 | KBNODE keyblock = NULL; |
916 | 0 | GETKEY_CTX ctx; |
917 | 0 | int any_secret; |
918 | 0 | const char *resname; |
919 | 0 | const char *keyring_str = _("Keyring"); |
920 | 0 | int i; |
921 | 0 | struct keylist_context listctx; |
922 | 0 | gpg_error_t listerr = 0; |
923 | |
|
924 | 0 | memset (&listctx, 0, sizeof (listctx)); |
925 | 0 | if (!secret && opt.check_sigs) |
926 | 0 | listctx.check_sigs = 1; |
927 | | |
928 | | /* fixme: using the bynames function has the disadvantage that we |
929 | | * don't know whether one of the names given was not found. OTOH, |
930 | | * this function has the advantage to list the names in the |
931 | | * sequence as defined by the keyDB and does not duplicate |
932 | | * outputs. A solution could be do test whether all given have |
933 | | * been listed (this needs a way to use the keyDB search |
934 | | * functions) or to have the search function return indicators for |
935 | | * found names. Yet another way is to use the keydb search |
936 | | * facilities directly. */ |
937 | 0 | rc = getkey_bynames (ctrl, &ctx, NULL, names, |
938 | 0 | (GETKEY_ALLOW_ADSK |
939 | 0 | | (secret ? GETKEY_WANT_SECRET : 0)), |
940 | 0 | &keyblock); |
941 | 0 | if (rc) |
942 | 0 | { |
943 | 0 | log_error ("error reading key: %s\n", gpg_strerror (rc)); |
944 | 0 | getkey_end (ctrl, ctx); |
945 | 0 | write_status_error ("keylist.getkey", rc); |
946 | 0 | return; |
947 | 0 | } |
948 | | |
949 | 0 | do |
950 | 0 | { |
951 | | /* getkey_bynames makes sure that only secret keys are returned |
952 | | * if requested, thus we do not need to test again. With |
953 | | * MARK_SECRET set (ie. option --with-secret) we have to test |
954 | | * for a secret key, though. */ |
955 | 0 | if (secret) |
956 | 0 | any_secret = 1; |
957 | 0 | else if (mark_secret) |
958 | 0 | any_secret = !agent_probe_any_secret_key (ctrl, keyblock); |
959 | 0 | else |
960 | 0 | any_secret = 0; |
961 | |
|
962 | 0 | if (secret && !any_secret) |
963 | 0 | ;/* Secret key listing requested but getkey_bynames failed. */ |
964 | 0 | else |
965 | 0 | { |
966 | 0 | if ((opt.list_options & LIST_SHOW_KEYRING) && !opt.with_colons) |
967 | 0 | { |
968 | 0 | resname = keydb_get_resource_name (get_ctx_handle (ctx)); |
969 | 0 | es_fprintf (es_stdout, "%s: %s\n", keyring_str, resname); |
970 | 0 | for (i = strlen (resname) + strlen (keyring_str) + 2; i; i--) |
971 | 0 | es_putc ('-', es_stdout); |
972 | 0 | es_putc ('\n', es_stdout); |
973 | 0 | } |
974 | 0 | listerr = list_keyblock (ctrl, keyblock, secret, any_secret, |
975 | 0 | opt.fingerprint, &listctx); |
976 | 0 | } |
977 | 0 | release_kbnode (keyblock); |
978 | 0 | } |
979 | 0 | while (!listerr && !getkey_next (ctrl, ctx, NULL, &keyblock)); |
980 | 0 | getkey_end (ctrl, ctx); |
981 | |
|
982 | 0 | if (opt.check_sigs && !opt.with_colons) |
983 | 0 | print_signature_stats (&listctx); |
984 | |
|
985 | 0 | keylist_context_release (&listctx); |
986 | 0 | } |
987 | | |
988 | | |
989 | | static void |
990 | | locate_one (ctrl_t ctrl, strlist_t names, int no_local) |
991 | 0 | { |
992 | 0 | int rc = 0; |
993 | 0 | strlist_t sl; |
994 | 0 | GETKEY_CTX ctx = NULL; |
995 | 0 | KBNODE keyblock = NULL; |
996 | 0 | struct keylist_context listctx; |
997 | 0 | gpg_error_t listerr = 0; |
998 | |
|
999 | 0 | memset (&listctx, 0, sizeof (listctx)); |
1000 | 0 | if (opt.check_sigs) |
1001 | 0 | listctx.check_sigs = 1; |
1002 | |
|
1003 | 0 | for (sl = names; sl && !listerr; sl = sl->next) |
1004 | 0 | { |
1005 | 0 | rc = get_best_pubkey_byname (ctrl, |
1006 | 0 | no_local? GET_PUBKEY_NO_LOCAL |
1007 | 0 | /* */: GET_PUBKEY_NORMAL, |
1008 | 0 | &ctx, NULL, sl->d, &keyblock, 1); |
1009 | 0 | if (rc) |
1010 | 0 | { |
1011 | 0 | if (gpg_err_code (rc) != GPG_ERR_NO_PUBKEY) |
1012 | 0 | log_error ("error reading key: %s\n", gpg_strerror (rc)); |
1013 | 0 | else if (opt.verbose) |
1014 | 0 | log_info (_("key \"%s\" not found: %s\n"), |
1015 | 0 | sl->d, gpg_strerror (rc)); |
1016 | 0 | } |
1017 | 0 | else |
1018 | 0 | { |
1019 | 0 | do |
1020 | 0 | { |
1021 | 0 | listerr = list_keyblock (ctrl, keyblock, 0, 0, |
1022 | 0 | opt.fingerprint, &listctx); |
1023 | 0 | release_kbnode (keyblock); |
1024 | 0 | } |
1025 | 0 | while (!listerr && ctx && !getkey_next (ctrl, ctx, NULL, &keyblock)); |
1026 | 0 | getkey_end (ctrl, ctx); |
1027 | 0 | ctx = NULL; |
1028 | 0 | } |
1029 | 0 | } |
1030 | |
|
1031 | 0 | if (opt.check_sigs && !opt.with_colons) |
1032 | 0 | print_signature_stats (&listctx); |
1033 | |
|
1034 | 0 | keylist_context_release (&listctx); |
1035 | 0 | } |
1036 | | |
1037 | | |
1038 | | static void |
1039 | | print_key_data (PKT_public_key * pk) |
1040 | 0 | { |
1041 | 0 | int n = pk ? pubkey_get_npkey (pk->pubkey_algo) : 0; |
1042 | 0 | int i; |
1043 | |
|
1044 | 0 | for (i = 0; i < n; i++) |
1045 | 0 | { |
1046 | 0 | es_fprintf (es_stdout, "pkd:%d:%u:", i, mpi_get_nbits (pk->pkey[i])); |
1047 | 0 | mpi_print (es_stdout, pk->pkey[i], 1); |
1048 | 0 | es_putc (':', es_stdout); |
1049 | 0 | es_putc ('\n', es_stdout); |
1050 | 0 | } |
1051 | 0 | } |
1052 | | |
1053 | | |
1054 | | /* Various public key screenings. (Right now just ROCA). With |
1055 | | * COLON_MODE set the output is formatted for use in the compliance |
1056 | | * field of a colon listing. |
1057 | | */ |
1058 | | static void |
1059 | | print_pk_screening (PKT_public_key *pk, int colon_mode) |
1060 | 0 | { |
1061 | 0 | gpg_error_t err; |
1062 | |
|
1063 | 0 | if (is_RSA (pk->pubkey_algo) && pubkey_get_npkey (pk->pubkey_algo)) |
1064 | 0 | { |
1065 | 0 | err = screen_key_for_roca (pk->pkey[0]); |
1066 | 0 | if (!err) |
1067 | 0 | ; |
1068 | 0 | else if (gpg_err_code (err) == GPG_ERR_TRUE) |
1069 | 0 | { |
1070 | 0 | if (colon_mode) |
1071 | 0 | es_fprintf (es_stdout, colon_mode > 1? " %d":"%d", 6001); |
1072 | 0 | else |
1073 | 0 | es_fprintf (es_stdout, |
1074 | 0 | " Screening: ROCA vulnerability detected\n"); |
1075 | 0 | } |
1076 | 0 | else if (!colon_mode) |
1077 | 0 | es_fprintf (es_stdout, " Screening: [ROCA check failed: %s]\n", |
1078 | 0 | gpg_strerror (err)); |
1079 | 0 | } |
1080 | |
|
1081 | 0 | } |
1082 | | |
1083 | | |
1084 | | static void |
1085 | | print_capabilities (ctrl_t ctrl, PKT_public_key *pk, KBNODE keyblock) |
1086 | 0 | { |
1087 | 0 | unsigned int use = pk->pubkey_usage; |
1088 | 0 | int c_printed = 0; |
1089 | |
|
1090 | 0 | if (use & PUBKEY_USAGE_ENC) |
1091 | 0 | es_putc ('e', es_stdout); |
1092 | |
|
1093 | 0 | if (use & PUBKEY_USAGE_SIG) |
1094 | 0 | { |
1095 | 0 | es_putc ('s', es_stdout); |
1096 | 0 | if (pk->flags.primary) |
1097 | 0 | { |
1098 | 0 | es_putc ('c', es_stdout); |
1099 | | /* The PUBKEY_USAGE_CERT flag was introduced later and we |
1100 | | used to always print 'c' for a primary key. To avoid any |
1101 | | regression here we better track whether we printed 'c' |
1102 | | already. */ |
1103 | 0 | c_printed = 1; |
1104 | 0 | } |
1105 | 0 | } |
1106 | |
|
1107 | 0 | if ((use & PUBKEY_USAGE_CERT) && !c_printed) |
1108 | 0 | es_putc ('c', es_stdout); |
1109 | |
|
1110 | 0 | if ((use & PUBKEY_USAGE_AUTH)) |
1111 | 0 | es_putc ('a', es_stdout); |
1112 | |
|
1113 | 0 | if (use & PUBKEY_USAGE_RENC) |
1114 | 0 | es_putc ('r', es_stdout); |
1115 | 0 | if ((use & PUBKEY_USAGE_TIME)) |
1116 | 0 | es_putc ('t', es_stdout); |
1117 | 0 | if ((use & PUBKEY_USAGE_GROUP)) |
1118 | 0 | es_putc ('g', es_stdout); |
1119 | |
|
1120 | 0 | if ((use & PUBKEY_USAGE_UNKNOWN)) |
1121 | 0 | es_putc ('?', es_stdout); |
1122 | |
|
1123 | 0 | if (keyblock) |
1124 | 0 | { |
1125 | | /* Figure out the usable capabilities. */ |
1126 | 0 | KBNODE k; |
1127 | 0 | int enc = 0, sign = 0, cert = 0, auth = 0, disabled = 0; |
1128 | |
|
1129 | 0 | for (k = keyblock; k; k = k->next) |
1130 | 0 | { |
1131 | 0 | if (k->pkt->pkttype == PKT_PUBLIC_KEY |
1132 | 0 | || k->pkt->pkttype == PKT_PUBLIC_SUBKEY) |
1133 | 0 | { |
1134 | 0 | pk = k->pkt->pkt.public_key; |
1135 | |
|
1136 | 0 | if (pk->flags.primary) |
1137 | 0 | disabled = pk_is_disabled (pk); |
1138 | |
|
1139 | 0 | if (pk->flags.valid && !pk->flags.revoked && !pk->has_expired) |
1140 | 0 | { |
1141 | 0 | if (pk->pubkey_usage & PUBKEY_USAGE_ENC) |
1142 | 0 | enc = 1; |
1143 | 0 | if (pk->pubkey_usage & PUBKEY_USAGE_SIG) |
1144 | 0 | { |
1145 | 0 | sign = 1; |
1146 | 0 | if (pk->flags.primary) |
1147 | 0 | cert = 1; |
1148 | 0 | } |
1149 | 0 | if (pk->pubkey_usage & PUBKEY_USAGE_CERT) |
1150 | 0 | cert = 1; |
1151 | 0 | if ((pk->pubkey_usage & PUBKEY_USAGE_AUTH)) |
1152 | 0 | auth = 1; |
1153 | 0 | } |
1154 | 0 | } |
1155 | 0 | } |
1156 | 0 | if (enc) |
1157 | 0 | es_putc ('E', es_stdout); |
1158 | 0 | if (sign) |
1159 | 0 | es_putc ('S', es_stdout); |
1160 | 0 | if (cert) |
1161 | 0 | es_putc ('C', es_stdout); |
1162 | 0 | if (auth) |
1163 | 0 | es_putc ('A', es_stdout); |
1164 | 0 | if (disabled) |
1165 | 0 | es_putc ('D', es_stdout); |
1166 | 0 | } |
1167 | |
|
1168 | 0 | es_putc (':', es_stdout); |
1169 | 0 | } |
1170 | | |
1171 | | |
1172 | | /* FLAGS: 0x01 hashed |
1173 | | 0x02 critical */ |
1174 | | static void |
1175 | | print_one_subpacket (sigsubpkttype_t type, size_t len, int flags, |
1176 | | const byte * buf) |
1177 | 0 | { |
1178 | 0 | size_t i; |
1179 | |
|
1180 | 0 | es_fprintf (es_stdout, "spk:%d:%u:%u:", type, flags, (unsigned int) len); |
1181 | |
|
1182 | 0 | for (i = 0; i < len; i++) |
1183 | 0 | { |
1184 | | /* printable ascii other than : and % */ |
1185 | 0 | if (buf[i] >= 32 && buf[i] <= 126 && buf[i] != ':' && buf[i] != '%') |
1186 | 0 | es_fprintf (es_stdout, "%c", buf[i]); |
1187 | 0 | else |
1188 | 0 | es_fprintf (es_stdout, "%%%02X", buf[i]); |
1189 | 0 | } |
1190 | |
|
1191 | 0 | es_fprintf (es_stdout, "\n"); |
1192 | 0 | } |
1193 | | |
1194 | | |
1195 | | void |
1196 | | print_subpackets_colon (PKT_signature * sig) |
1197 | 0 | { |
1198 | 0 | byte *i; |
1199 | |
|
1200 | 0 | log_assert (opt.show_subpackets); |
1201 | | |
1202 | 0 | for (i = opt.show_subpackets; *i; i++) |
1203 | 0 | { |
1204 | 0 | const byte *p; |
1205 | 0 | size_t len; |
1206 | 0 | int seq, crit; |
1207 | |
|
1208 | 0 | seq = 0; |
1209 | |
|
1210 | 0 | while ((p = enum_sig_subpkt (sig, 1, *i, &len, &seq, &crit))) |
1211 | 0 | print_one_subpacket (*i, len, 0x01 | (crit ? 0x02 : 0), p); |
1212 | |
|
1213 | 0 | seq = 0; |
1214 | |
|
1215 | 0 | while ((p = enum_sig_subpkt (sig, 0, *i, &len, &seq, &crit))) |
1216 | 0 | print_one_subpacket (*i, len, 0x00 | (crit ? 0x02 : 0), p); |
1217 | 0 | } |
1218 | 0 | } |
1219 | | |
1220 | | |
1221 | | void |
1222 | | dump_attribs (const PKT_user_id *uid, PKT_public_key *pk) |
1223 | 0 | { |
1224 | 0 | int i; |
1225 | |
|
1226 | 0 | if (!attrib_fp) |
1227 | 0 | return; |
1228 | | |
1229 | 0 | for (i = 0; i < uid->numattribs; i++) |
1230 | 0 | { |
1231 | 0 | if (is_status_enabled ()) |
1232 | 0 | { |
1233 | 0 | byte array[MAX_FINGERPRINT_LEN], *p; |
1234 | 0 | char buf[(MAX_FINGERPRINT_LEN * 2) + 90]; |
1235 | 0 | size_t j, n; |
1236 | |
|
1237 | 0 | if (!pk) |
1238 | 0 | BUG (); |
1239 | 0 | fingerprint_from_pk (pk, array, &n); |
1240 | |
|
1241 | 0 | p = array; |
1242 | 0 | for (j = 0; j < n; j++, p++) |
1243 | 0 | sprintf (buf + 2 * j, "%02X", *p); |
1244 | |
|
1245 | 0 | sprintf (buf + strlen (buf), " %lu %u %u %u %lu %lu %u", |
1246 | 0 | (ulong) uid->attribs[i].len, uid->attribs[i].type, i + 1, |
1247 | 0 | uid->numattribs, (ulong) uid->created, |
1248 | 0 | (ulong) uid->expiredate, |
1249 | 0 | ((uid->flags.primary ? 0x01 : 0) | (uid->flags.revoked ? 0x02 : 0) | |
1250 | 0 | (uid->flags.expired ? 0x04 : 0))); |
1251 | 0 | write_status_text (STATUS_ATTRIBUTE, buf); |
1252 | 0 | } |
1253 | | |
1254 | 0 | es_fwrite (uid->attribs[i].data, uid->attribs[i].len, 1, attrib_fp); |
1255 | 0 | es_fflush (attrib_fp); |
1256 | 0 | } |
1257 | 0 | } |
1258 | | |
1259 | | |
1260 | | static void |
1261 | | print_keygrip (const char *keygrip) |
1262 | 0 | { |
1263 | 0 | const char *s; |
1264 | |
|
1265 | 0 | s = strchr (keygrip, ','); |
1266 | 0 | if (s) |
1267 | 0 | es_fprintf (es_stdout, " Keygrip = %.*s,\n%*s%s\n", |
1268 | 0 | (int)(s-keygrip), keygrip, 16, "", s+1); |
1269 | 0 | else |
1270 | 0 | es_fprintf (es_stdout, " Keygrip = %s\n", keygrip); |
1271 | 0 | } |
1272 | | |
1273 | | |
1274 | | /* If PK is given the output is written to a new file instead of |
1275 | | * stdout. */ |
1276 | | static void |
1277 | | print_x509_notations (struct notation *nots, PKT_public_key *pk) |
1278 | 0 | { |
1279 | 0 | gpg_error_t err; |
1280 | 0 | gpgrt_b64state_t state = NULL; |
1281 | 0 | char hexfpr[2*4 + 1 + 2*MAX_FINGERPRINT_LEN+4+1]; |
1282 | 0 | char sha1[20]; |
1283 | 0 | estream_t fp; |
1284 | |
|
1285 | 0 | for (; nots; nots = nots->next) |
1286 | 0 | { |
1287 | 0 | if (pk) |
1288 | 0 | { |
1289 | 0 | gcry_md_hash_buffer (GCRY_MD_SHA1, sha1, nots->bdat, nots->blen); |
1290 | 0 | bin2hex (sha1+16, 4, hexfpr); |
1291 | 0 | hexfpr[2*4] = '-'; |
1292 | 0 | hexfingerprint (pk, hexfpr + 2*4+1, 2*MAX_FINGERPRINT_LEN); |
1293 | 0 | strcat (hexfpr, ".pem"); |
1294 | 0 | fp = es_fopen (hexfpr, "w"); |
1295 | 0 | if (!fp) |
1296 | 0 | { |
1297 | 0 | err = gpg_err_code_from_syserror (); |
1298 | 0 | goto b64fail; |
1299 | 0 | } |
1300 | 0 | } |
1301 | 0 | else |
1302 | 0 | fp = es_stdout; |
1303 | 0 | state = gpgrt_b64enc_start (fp, "CERTIFICATE"); |
1304 | 0 | if (!state) |
1305 | 0 | { |
1306 | 0 | err = gpg_err_code_from_syserror (); |
1307 | 0 | goto b64fail; |
1308 | 0 | } |
1309 | 0 | err = gpgrt_b64enc_write (state, nots->bdat, nots->blen); |
1310 | 0 | if (err) |
1311 | 0 | goto b64fail; |
1312 | 0 | err = gpgrt_b64enc_finish (state); |
1313 | 0 | if (err) |
1314 | 0 | goto b64fail; |
1315 | 0 | if (fp != es_stdout) |
1316 | 0 | { |
1317 | 0 | es_fclose (fp); |
1318 | 0 | fp = NULL; |
1319 | 0 | } |
1320 | 0 | } |
1321 | 0 | return; |
1322 | | |
1323 | 0 | b64fail: |
1324 | 0 | log_error ("error writing base64 encoded notation: %s\n", gpg_strerror (err)); |
1325 | 0 | gpgrt_b64enc_finish (state); |
1326 | 0 | if (fp && fp != es_stdout) |
1327 | 0 | gpgrt_fcancel (fp); |
1328 | 0 | } |
1329 | | |
1330 | | |
1331 | | /* Order two signatures. We first order by keyid and then by creation |
1332 | | * time. */ |
1333 | | int |
1334 | | cmp_signodes (const void *av, const void *bv) |
1335 | 0 | { |
1336 | 0 | const kbnode_t an = *(const kbnode_t *)av; |
1337 | 0 | const kbnode_t bn = *(const kbnode_t *)bv; |
1338 | 0 | const PKT_signature *a; |
1339 | 0 | const PKT_signature *b; |
1340 | 0 | int i; |
1341 | | |
1342 | | /* log_assert (an->pkt->pkttype == PKT_SIGNATURE); */ |
1343 | | /* log_assert (bn->pkt->pkttype == PKT_SIGNATURE); */ |
1344 | |
|
1345 | 0 | a = an->pkt->pkt.signature; |
1346 | 0 | b = bn->pkt->pkt.signature; |
1347 | | |
1348 | | /* Self-signatures are ordered first. */ |
1349 | 0 | if ((an->flag & NODFLG_MARK_B) && !(bn->flag & NODFLG_MARK_B)) |
1350 | 0 | return -1; |
1351 | 0 | if (!(an->flag & NODFLG_MARK_B) && (bn->flag & NODFLG_MARK_B)) |
1352 | 0 | return 1; |
1353 | | |
1354 | | /* then the keyids. (which are or course the same for self-sigs). */ |
1355 | 0 | i = keyid_cmp (a->keyid, b->keyid); |
1356 | 0 | if (i) |
1357 | 0 | return i; |
1358 | | |
1359 | | /* Followed by creation time */ |
1360 | 0 | if (a->timestamp > b->timestamp) |
1361 | 0 | return 1; |
1362 | 0 | if (a->timestamp < b->timestamp) |
1363 | 0 | return -1; |
1364 | | |
1365 | | /* followed by the class in a way that a rev comes first. */ |
1366 | 0 | if (a->sig_class > b->sig_class) |
1367 | 0 | return 1; |
1368 | 0 | if (a->sig_class < b->sig_class) |
1369 | 0 | return -1; |
1370 | | |
1371 | | /* To make the sort stable we compare the entire structure as last resort. */ |
1372 | 0 | return memcmp (a, b, sizeof *a); |
1373 | 0 | } |
1374 | | |
1375 | | |
1376 | | /* Given a domain name at NAME with length NAME, check whether this is |
1377 | | * a valid domain name and in that case return a malloced string ith |
1378 | | * the name. Escaped dots are ignored and removed from the result. |
1379 | | * Example: "example\.org" -> "example.org" Note that the input may |
1380 | | * not be Nul terminated. */ |
1381 | | static char * |
1382 | | parse_trust_name (const char *name, size_t namelen) |
1383 | 0 | { |
1384 | 0 | char *buffer, *p; |
1385 | |
|
1386 | 0 | p = buffer = xtrymalloc (namelen+1); |
1387 | 0 | if (!buffer) |
1388 | 0 | return NULL; /* Oops - caller needs to use some fallback */ |
1389 | | |
1390 | 0 | for (; namelen; name++, namelen--) |
1391 | 0 | { |
1392 | 0 | if (*name == '\\' && namelen > 1 && name[1] == '.') |
1393 | 0 | ; /* Skip the escape character. */ |
1394 | 0 | else |
1395 | 0 | *p++ = *name; |
1396 | 0 | } |
1397 | 0 | *p = 0; |
1398 | 0 | if (!is_valid_domain_name (buffer)) |
1399 | 0 | { |
1400 | 0 | xfree (buffer); |
1401 | 0 | buffer = NULL; |
1402 | 0 | } |
1403 | 0 | return buffer; |
1404 | 0 | } |
1405 | | |
1406 | | |
1407 | | void |
1408 | | print_revocation_reason_comment (const char *comment, size_t comment_len) |
1409 | 0 | { |
1410 | 0 | const byte *s, *s_lf; |
1411 | 0 | size_t n, n_lf; |
1412 | |
|
1413 | 0 | if (!comment || !comment_len) |
1414 | 0 | return; |
1415 | | |
1416 | 0 | s = comment; |
1417 | 0 | n = comment_len; |
1418 | 0 | s_lf = NULL; |
1419 | 0 | do |
1420 | 0 | { |
1421 | | /* We don't want any empty lines, so we skip them. */ |
1422 | 0 | for (;n && *s == '\n'; s++, n--) |
1423 | 0 | ; |
1424 | 0 | if (n) |
1425 | 0 | { |
1426 | 0 | s_lf = memchr (s, '\n', n); |
1427 | 0 | n_lf = s_lf? s_lf - s : n; |
1428 | 0 | es_fprintf (es_stdout, " %s", |
1429 | 0 | _("revocation comment: ")); |
1430 | 0 | es_write_sanitized (es_stdout, s, n_lf, NULL, NULL); |
1431 | 0 | es_putc ('\n', es_stdout); |
1432 | 0 | s += n_lf; n -= n_lf; |
1433 | 0 | } |
1434 | 0 | } while (s_lf); |
1435 | 0 | } |
1436 | | |
1437 | | |
1438 | | static void |
1439 | | print_revocation_reason (PKT_public_key *pk) |
1440 | 0 | { |
1441 | 0 | char *freeme; |
1442 | 0 | const char *codestr; |
1443 | |
|
1444 | 0 | if (!pk->revoked.got_reason) |
1445 | 0 | return; |
1446 | | |
1447 | 0 | if (!pk->revoked.reason_code && !pk->revoked.reason_comment) |
1448 | 0 | return; /* Do not print "revocation reason: No reason specified". */ |
1449 | | |
1450 | 0 | codestr = revocation_reason_code_to_str (pk->revoked.reason_code, &freeme); |
1451 | 0 | es_fprintf (es_stdout, " %s%s\n", |
1452 | 0 | _("reason for revocation: "), codestr); |
1453 | 0 | xfree (freeme); |
1454 | 0 | print_revocation_reason_comment (pk->revoked.reason_comment, |
1455 | 0 | pk->revoked.reason_comment_len); |
1456 | 0 | } |
1457 | | |
1458 | | |
1459 | | /* Helper for list_keyblock_print. The caller must have set |
1460 | | * NODFLG_MARK_B to indicate self-signatures. */ |
1461 | | static void |
1462 | | list_signature_print (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node, |
1463 | | struct keylist_context *listctx, PKT_public_key *lastpk) |
1464 | 0 | { |
1465 | 0 | PKT_signature *sig = node->pkt->pkt.signature; |
1466 | 0 | int rc, sigrc; |
1467 | 0 | char *sigstr; |
1468 | 0 | char *reason_text = NULL; |
1469 | 0 | char *reason_comment = NULL; |
1470 | 0 | size_t reason_commentlen; |
1471 | 0 | int reason_code = 0; |
1472 | |
|
1473 | 0 | if (listctx->check_sigs) |
1474 | 0 | { |
1475 | 0 | rc = check_key_signature (ctrl, keyblock, node, NULL); |
1476 | 0 | switch (gpg_err_code (rc)) |
1477 | 0 | { |
1478 | 0 | case 0: |
1479 | 0 | listctx->good_sigs++; |
1480 | 0 | sigrc = '!'; |
1481 | 0 | break; |
1482 | 0 | case GPG_ERR_BAD_SIGNATURE: |
1483 | 0 | listctx->inv_sigs++; |
1484 | 0 | sigrc = '-'; |
1485 | 0 | break; |
1486 | 0 | case GPG_ERR_NO_PUBKEY: |
1487 | 0 | case GPG_ERR_UNUSABLE_PUBKEY: |
1488 | 0 | listctx->no_key++; |
1489 | 0 | return; |
1490 | 0 | case GPG_ERR_DIGEST_ALGO: |
1491 | 0 | case GPG_ERR_PUBKEY_ALGO: |
1492 | 0 | if (!(opt.list_options & LIST_SHOW_UNUSABLE_SIGS)) |
1493 | 0 | return; |
1494 | | /* fallthru. */ |
1495 | 0 | default: |
1496 | 0 | listctx->oth_err++; |
1497 | 0 | sigrc = '%'; |
1498 | 0 | break; |
1499 | 0 | } |
1500 | | |
1501 | | /* TODO: Make sure a cached sig record here still has |
1502 | | the pk that issued it. See also |
1503 | | keyedit.c:print_and_check_one_sig */ |
1504 | 0 | } |
1505 | 0 | else |
1506 | 0 | { |
1507 | 0 | if (!(opt.list_options & LIST_SHOW_UNUSABLE_SIGS) |
1508 | 0 | && (gpg_err_code (openpgp_pk_test_algo (sig->pubkey_algo) |
1509 | 0 | == GPG_ERR_PUBKEY_ALGO) |
1510 | 0 | || gpg_err_code (openpgp_md_test_algo (sig->digest_algo) |
1511 | 0 | == GPG_ERR_DIGEST_ALGO) |
1512 | 0 | || (sig->digest_algo == DIGEST_ALGO_SHA1 |
1513 | 0 | && !(node->flag & NODFLG_MARK_B) /*no selfsig*/ |
1514 | 0 | && !opt.flags.allow_weak_key_signatures))) |
1515 | 0 | return; |
1516 | 0 | rc = 0; |
1517 | 0 | sigrc = ' '; |
1518 | 0 | } |
1519 | | |
1520 | 0 | if (IS_KEY_REV (sig) || IS_SUBKEY_REV (sig) || IS_UID_REV (sig)) |
1521 | 0 | { |
1522 | 0 | sigstr = "rev"; |
1523 | 0 | reason_code = get_revocation_reason (sig, &reason_text, |
1524 | 0 | &reason_comment, |
1525 | 0 | &reason_commentlen); |
1526 | 0 | } |
1527 | 0 | else if (IS_UID_SIG (sig)) |
1528 | 0 | sigstr = "sig"; |
1529 | 0 | else if (IS_SUBKEY_SIG (sig)) |
1530 | 0 | sigstr = "sig"; |
1531 | 0 | else if (IS_KEY_SIG (sig)) |
1532 | 0 | sigstr = "sig"; |
1533 | 0 | else |
1534 | 0 | { |
1535 | 0 | es_fprintf (es_stdout, "sig " |
1536 | 0 | "[unexpected signature class 0x%02x]\n", |
1537 | 0 | sig->sig_class); |
1538 | 0 | return; |
1539 | 0 | } |
1540 | | |
1541 | 0 | es_fputs (sigstr, es_stdout); |
1542 | 0 | es_fprintf (es_stdout, "%c%c %c%c%c%c%c%c %s %s", |
1543 | 0 | sigrc, (sig->sig_class - 0x10 > 0 && |
1544 | 0 | sig->sig_class - 0x10 < |
1545 | 0 | 4) ? '0' + sig->sig_class - 0x10 : ' ', |
1546 | 0 | sig->flags.exportable ? ' ' : 'L', |
1547 | 0 | sig->flags.revocable ? ' ' : 'R', |
1548 | 0 | sig->flags.policy_url ? 'P' : ' ', |
1549 | 0 | sig->flags.notation ? 'N' : ' ', |
1550 | 0 | sig->flags.expired ? 'X' : ' ', |
1551 | 0 | (sig->trust_depth > 9) ? 'T' : (sig->trust_depth > |
1552 | 0 | 0) ? '0' + |
1553 | 0 | sig->trust_depth : ' ', keystr (sig->keyid), |
1554 | 0 | datestr_from_sig (sig)); |
1555 | 0 | if (opt.list_options & LIST_SHOW_SIG_EXPIRE) |
1556 | 0 | es_fprintf (es_stdout, " %s", expirestr_from_sig (sig)); |
1557 | 0 | es_fprintf (es_stdout, " "); |
1558 | 0 | if (sigrc == '%') |
1559 | 0 | es_fprintf (es_stdout, "[%s] ", gpg_strerror (rc)); |
1560 | 0 | else if (sigrc == '?') |
1561 | 0 | ; |
1562 | 0 | else if ((node->flag & NODFLG_MARK_B)) |
1563 | 0 | es_fputs (_("[self-signature]"), es_stdout); |
1564 | 0 | else if (!opt.fast_list_mode ) |
1565 | 0 | { |
1566 | 0 | size_t n; |
1567 | 0 | char *p = get_user_id (ctrl, sig->keyid, &n, NULL); |
1568 | 0 | print_utf8_buffer (es_stdout, p, n); |
1569 | 0 | xfree (p); |
1570 | 0 | } |
1571 | 0 | if ((opt.list_options & LIST_SHOW_TRUSTSIG) |
1572 | 0 | && (sig->trust_depth || sig->trust_value || sig->trust_regexp)) |
1573 | 0 | { |
1574 | 0 | es_fprintf (es_stdout, " [T=%d,%d", sig->trust_depth, sig->trust_value); |
1575 | 0 | if (sig->trust_regexp) |
1576 | 0 | { |
1577 | 0 | size_t n = strlen (sig->trust_regexp); |
1578 | 0 | char *tname = NULL; |
1579 | |
|
1580 | 0 | if (!strncmp (sig->trust_regexp, "<[^>]+[@.]", 10) |
1581 | 0 | && n > 12 && !strcmp (sig->trust_regexp+n-2, ">$") |
1582 | 0 | && (tname=parse_trust_name (sig->trust_regexp+10, n-12))) |
1583 | 0 | { |
1584 | 0 | es_fprintf (es_stdout, ",\"%s", tname); |
1585 | 0 | xfree (tname); |
1586 | 0 | } |
1587 | 0 | else |
1588 | 0 | { |
1589 | 0 | es_fputs (",R\"", es_stdout); |
1590 | 0 | es_write_sanitized (es_stdout, sig->trust_regexp, n, "\"", NULL); |
1591 | 0 | } |
1592 | 0 | es_putc ('\"', es_stdout); |
1593 | 0 | } |
1594 | 0 | es_putc (']', es_stdout); |
1595 | 0 | } |
1596 | 0 | es_putc ('\n', es_stdout); |
1597 | |
|
1598 | 0 | if (sig->flags.policy_url |
1599 | 0 | && (opt.list_options & LIST_SHOW_POLICY_URLS)) |
1600 | 0 | show_policy_url (sig, 3, 0); |
1601 | |
|
1602 | 0 | if (sig->flags.notation && (opt.list_options & LIST_SHOW_NOTATIONS)) |
1603 | 0 | show_notation (sig, 3, 0, |
1604 | 0 | ((opt. |
1605 | 0 | list_options & LIST_SHOW_STD_NOTATIONS) ? 1 : 0) + |
1606 | 0 | ((opt. |
1607 | 0 | list_options & LIST_SHOW_USER_NOTATIONS) ? 2 : 0) + |
1608 | 0 | ((opt. |
1609 | 0 | list_options & LIST_SHOW_HIDDEN_NOTATIONS) ? 4 : 0)); |
1610 | |
|
1611 | 0 | if (sig->flags.notation |
1612 | 0 | && (opt.list_options |
1613 | 0 | & (LIST_SHOW_X509_NOTATIONS|LIST_STORE_X509_NOTATIONS))) |
1614 | 0 | { |
1615 | 0 | struct notation *nots; |
1616 | |
|
1617 | 0 | if ((IS_KEY_SIG (sig) || IS_SUBKEY_SIG (sig)) |
1618 | 0 | && (nots = search_sig_notations (sig, |
1619 | 0 | "x509certificate@pgp.com"))) |
1620 | 0 | { |
1621 | 0 | if ((opt.list_options & LIST_STORE_X509_NOTATIONS)) |
1622 | 0 | print_x509_notations (nots, lastpk); |
1623 | 0 | else |
1624 | 0 | print_x509_notations (nots, NULL); |
1625 | 0 | free_notation (nots); |
1626 | 0 | } |
1627 | 0 | } |
1628 | |
|
1629 | 0 | if (sig->flags.pref_ks |
1630 | 0 | && (opt.list_options & LIST_SHOW_KEYSERVER_URLS)) |
1631 | 0 | show_keyserver_url (sig, 3, 0); |
1632 | |
|
1633 | 0 | if (reason_text && (reason_code || reason_comment)) |
1634 | 0 | { |
1635 | 0 | es_fprintf (es_stdout, " %s%s\n", |
1636 | 0 | _("reason for revocation: "), reason_text); |
1637 | 0 | print_revocation_reason_comment (reason_comment, reason_commentlen); |
1638 | 0 | } |
1639 | |
|
1640 | 0 | xfree (reason_text); |
1641 | 0 | xfree (reason_comment); |
1642 | | |
1643 | | /* fixme: check or list other sigs here */ |
1644 | 0 | } |
1645 | | |
1646 | | |
1647 | | static void |
1648 | | list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr, |
1649 | | struct keylist_context *listctx) |
1650 | 0 | { |
1651 | 0 | int rc; |
1652 | 0 | kbnode_t node; |
1653 | 0 | PKT_public_key *pk; |
1654 | 0 | PKT_public_key *lastpk; |
1655 | 0 | u32 *mainkid; |
1656 | 0 | int skip_sigs = 0; |
1657 | 0 | char *hexgrip = NULL; |
1658 | 0 | char *serialno = NULL; |
1659 | | |
1660 | | /* Get the keyid from the keyblock. */ |
1661 | 0 | node = find_kbnode (keyblock, PKT_PUBLIC_KEY); |
1662 | 0 | if (!node) |
1663 | 0 | { |
1664 | 0 | log_error ("Oops; key lost!\n"); |
1665 | 0 | dump_kbnode (keyblock); |
1666 | 0 | return; |
1667 | 0 | } |
1668 | | |
1669 | 0 | pk = node->pkt->pkt.public_key; |
1670 | 0 | mainkid = pk_keyid (pk); |
1671 | 0 | lastpk = pk; |
1672 | |
|
1673 | 0 | if (secret || opt.with_keygrip) |
1674 | 0 | { |
1675 | 0 | rc = hexkeygrip_from_pk (pk, &hexgrip); |
1676 | 0 | if (rc) |
1677 | 0 | log_error ("error computing a keygrip: %s\n", gpg_strerror (rc)); |
1678 | 0 | } |
1679 | |
|
1680 | 0 | if (secret) |
1681 | 0 | { |
1682 | | /* Encode some info about the secret key in SECRET. */ |
1683 | 0 | if (!agent_get_keyinfo (NULL, hexgrip, &serialno, NULL)) |
1684 | 0 | secret = serialno? 3 : 1; |
1685 | 0 | else |
1686 | 0 | secret = 2; /* Key not found. */ |
1687 | 0 | } |
1688 | |
|
1689 | 0 | if (!listctx->no_validity) |
1690 | 0 | check_trustdb_stale (ctrl); |
1691 | | |
1692 | | /* Print the "pub" line and in KF_NONE mode the fingerprint. */ |
1693 | 0 | print_key_line (ctrl, es_stdout, pk, secret); |
1694 | |
|
1695 | 0 | if (fpr) |
1696 | 0 | print_fingerprint (ctrl, NULL, pk, 0); |
1697 | |
|
1698 | 0 | if (opt.with_keygrip && hexgrip) |
1699 | 0 | print_keygrip (hexgrip); |
1700 | |
|
1701 | 0 | if (serialno) |
1702 | 0 | print_card_serialno (serialno); |
1703 | |
|
1704 | 0 | if (opt.with_key_data) |
1705 | 0 | print_key_data (pk); |
1706 | |
|
1707 | 0 | if (opt.with_key_screening) |
1708 | 0 | print_pk_screening (pk, 0); |
1709 | |
|
1710 | 0 | if (opt.with_key_origin |
1711 | 0 | && (pk->keyorg || pk->keyupdate || pk->updateurl)) |
1712 | 0 | { |
1713 | 0 | char updatestr[MK_DATESTR_SIZE]; |
1714 | |
|
1715 | 0 | es_fprintf (es_stdout, " origin=%s last=%s %s", |
1716 | 0 | key_origin_string (pk->keyorg), |
1717 | 0 | mk_datestr (updatestr, sizeof updatestr, pk->keyupdate), |
1718 | 0 | pk->updateurl? "url=":""); |
1719 | 0 | if (pk->updateurl) |
1720 | 0 | print_utf8_string (es_stdout, pk->updateurl); |
1721 | 0 | es_putc ('\n', es_stdout); |
1722 | 0 | } |
1723 | |
|
1724 | 0 | print_revokers (es_stdout, 0, pk); |
1725 | |
|
1726 | 0 | for (node = keyblock; node; node = node->next) |
1727 | 0 | { |
1728 | 0 | if (is_deleted_kbnode (node)) |
1729 | 0 | continue; |
1730 | | |
1731 | 0 | if (node->pkt->pkttype == PKT_USER_ID) |
1732 | 0 | { |
1733 | 0 | PKT_user_id *uid = node->pkt->pkt.user_id; |
1734 | 0 | int indent; |
1735 | 0 | int kl = opt.keyid_format == KF_NONE? 10 : keystrlen (); |
1736 | |
|
1737 | 0 | if ((uid->flags.expired || uid->flags.revoked) |
1738 | 0 | && !(opt.list_options & LIST_SHOW_UNUSABLE_UIDS)) |
1739 | 0 | { |
1740 | 0 | skip_sigs = 1; |
1741 | 0 | continue; |
1742 | 0 | } |
1743 | 0 | else |
1744 | 0 | skip_sigs = 0; |
1745 | | |
1746 | 0 | if (attrib_fp && uid->attrib_data != NULL) |
1747 | 0 | dump_attribs (uid, pk); |
1748 | |
|
1749 | 0 | if ((uid->flags.revoked || uid->flags.expired) |
1750 | 0 | || ((opt.list_options & LIST_SHOW_UID_VALIDITY) |
1751 | 0 | && !listctx->no_validity)) |
1752 | 0 | { |
1753 | 0 | const char *validity; |
1754 | |
|
1755 | 0 | validity = uid_trust_string_fixed (ctrl, pk, uid); |
1756 | 0 | indent = ((kl + (opt.legacy_list_mode? 9:11)) |
1757 | 0 | - atoi (uid_trust_string_fixed (ctrl, NULL, NULL))); |
1758 | 0 | if (indent < 0 || indent > 40) |
1759 | 0 | indent = 0; |
1760 | |
|
1761 | 0 | es_fprintf (es_stdout, "uid%*s%s ", indent, "", validity); |
1762 | 0 | } |
1763 | 0 | else |
1764 | 0 | { |
1765 | 0 | indent = kl + (opt.legacy_list_mode? 10:12); |
1766 | 0 | es_fprintf (es_stdout, "uid%*s", indent, ""); |
1767 | 0 | } |
1768 | |
|
1769 | 0 | print_utf8_buffer (es_stdout, uid->name, uid->len); |
1770 | 0 | es_putc ('\n', es_stdout); |
1771 | |
|
1772 | 0 | if ((opt.list_options & LIST_SHOW_PREF_VERBOSE)) |
1773 | 0 | show_preferences (uid, indent+2, 0, 1); |
1774 | 0 | else if ((opt.list_options & LIST_SHOW_PREF)) |
1775 | 0 | show_preferences (uid, indent+2, 0, 0); |
1776 | |
|
1777 | 0 | if (opt.with_wkd_hash) |
1778 | 0 | { |
1779 | 0 | char *mbox, *hash, *p; |
1780 | 0 | char hashbuf[32]; |
1781 | |
|
1782 | 0 | mbox = mailbox_from_userid (uid->name, 0); |
1783 | 0 | if (mbox && (p = strchr (mbox, '@'))) |
1784 | 0 | { |
1785 | 0 | *p++ = 0; |
1786 | 0 | gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, |
1787 | 0 | mbox, strlen (mbox)); |
1788 | 0 | hash = zb32_encode (hashbuf, 8*20); |
1789 | 0 | if (hash) |
1790 | 0 | { |
1791 | 0 | es_fprintf (es_stdout, " %*s%s@%s\n", |
1792 | 0 | indent, "", hash, p); |
1793 | 0 | xfree (hash); |
1794 | 0 | } |
1795 | 0 | } |
1796 | 0 | xfree (mbox); |
1797 | 0 | } |
1798 | |
|
1799 | 0 | if (opt.with_key_origin |
1800 | 0 | && (uid->keyorg || uid->keyupdate || uid->updateurl)) |
1801 | 0 | { |
1802 | 0 | char updatestr[MK_DATESTR_SIZE]; |
1803 | |
|
1804 | 0 | es_fprintf (es_stdout, " %*sorigin=%s last=%s %s", |
1805 | 0 | indent, "", |
1806 | 0 | key_origin_string (uid->keyorg), |
1807 | 0 | mk_datestr (updatestr, sizeof updatestr, |
1808 | 0 | uid->keyupdate), |
1809 | 0 | uid->updateurl? "url=":""); |
1810 | 0 | if (uid->updateurl) |
1811 | 0 | print_utf8_string (es_stdout, uid->updateurl); |
1812 | 0 | es_putc ('\n', es_stdout); |
1813 | 0 | } |
1814 | |
|
1815 | 0 | if ((opt.list_options & LIST_SHOW_PHOTOS) && uid->attribs != NULL) |
1816 | 0 | show_photos (ctrl, uid->attribs, uid->numattribs, pk, uid); |
1817 | 0 | } |
1818 | 0 | else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) |
1819 | 0 | { |
1820 | 0 | PKT_public_key *pk2 = node->pkt->pkt.public_key; |
1821 | |
|
1822 | 0 | lastpk = pk2; |
1823 | 0 | if ((pk2->flags.revoked || pk2->has_expired) |
1824 | 0 | && !(opt.list_options & LIST_SHOW_UNUSABLE_SUBKEYS)) |
1825 | 0 | { |
1826 | 0 | skip_sigs = 1; |
1827 | 0 | continue; |
1828 | 0 | } |
1829 | 0 | else |
1830 | 0 | skip_sigs = 0; |
1831 | | |
1832 | 0 | xfree (serialno); serialno = NULL; |
1833 | 0 | xfree (hexgrip); hexgrip = NULL; |
1834 | 0 | if (secret || opt.with_keygrip) |
1835 | 0 | { |
1836 | 0 | rc = hexkeygrip_from_pk (pk2, &hexgrip); |
1837 | 0 | if (rc) |
1838 | 0 | log_error ("error computing a keygrip: %s\n", |
1839 | 0 | gpg_strerror (rc)); |
1840 | 0 | } |
1841 | 0 | if (secret) |
1842 | 0 | { |
1843 | 0 | if (!agent_get_keyinfo (NULL, hexgrip, &serialno, NULL)) |
1844 | 0 | secret = serialno? 3 : 1; |
1845 | 0 | else |
1846 | 0 | secret = 2; /* Key not found. */ |
1847 | 0 | } |
1848 | | |
1849 | | /* Print the "sub" line. */ |
1850 | 0 | print_key_line (ctrl, es_stdout, pk2, secret); |
1851 | 0 | if (fpr > 1 || opt.with_subkey_fingerprint) |
1852 | 0 | { |
1853 | 0 | print_fingerprint (ctrl, NULL, pk2, 0); |
1854 | 0 | if (serialno) |
1855 | 0 | print_card_serialno (serialno); |
1856 | 0 | } |
1857 | 0 | if (opt.with_keygrip && hexgrip) |
1858 | 0 | print_keygrip (hexgrip); |
1859 | 0 | if (opt.with_key_data) |
1860 | 0 | print_key_data (pk2); |
1861 | 0 | if (opt.with_key_screening) |
1862 | 0 | print_pk_screening (pk2, 0); |
1863 | 0 | } |
1864 | 0 | else if ((opt.list_sigs |
1865 | 0 | || (opt.list_options |
1866 | 0 | & (LIST_SHOW_X509_NOTATIONS|LIST_STORE_X509_NOTATIONS))) |
1867 | 0 | && node->pkt->pkttype == PKT_SIGNATURE && !skip_sigs) |
1868 | 0 | { |
1869 | 0 | kbnode_t n; |
1870 | 0 | unsigned int sigcount = 0; |
1871 | 0 | kbnode_t *sigarray; |
1872 | 0 | unsigned int idx; |
1873 | |
|
1874 | 0 | for (n=node; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next) |
1875 | 0 | sigcount++; |
1876 | 0 | sigarray = xcalloc (sigcount, sizeof *sigarray); |
1877 | |
|
1878 | 0 | sigcount = 0; |
1879 | 0 | for (n=node; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next) |
1880 | 0 | { |
1881 | 0 | if (keyid_eq (mainkid, n->pkt->pkt.signature->keyid)) |
1882 | 0 | n->flag |= NODFLG_MARK_B; /* Is a self-sig. */ |
1883 | 0 | else |
1884 | 0 | n->flag &= ~NODFLG_MARK_B; |
1885 | |
|
1886 | 0 | sigarray[sigcount++] = node = n; |
1887 | 0 | } |
1888 | | /* Note that NODE is now at the last signature. */ |
1889 | |
|
1890 | 0 | if ((opt.list_options & LIST_SORT_SIGS)) |
1891 | 0 | qsort (sigarray, sigcount, sizeof *sigarray, cmp_signodes); |
1892 | |
|
1893 | 0 | for (idx=0; idx < sigcount; idx++) |
1894 | 0 | list_signature_print (ctrl, keyblock, sigarray[idx], listctx, |
1895 | 0 | lastpk); |
1896 | 0 | xfree (sigarray); |
1897 | 0 | } |
1898 | 0 | } |
1899 | 0 | es_putc ('\n', es_stdout); |
1900 | 0 | xfree (serialno); |
1901 | 0 | xfree (hexgrip); |
1902 | 0 | } |
1903 | | |
1904 | | |
1905 | | /* Do a simple key listing printing only the fingerprint and the mail |
1906 | | * address of valid keys. */ |
1907 | | static void |
1908 | | list_keyblock_simple (ctrl_t ctrl, kbnode_t keyblock) |
1909 | 0 | { |
1910 | 0 | gpg_err_code_t ec; |
1911 | 0 | kbnode_t kbctx; |
1912 | 0 | kbnode_t node; |
1913 | 0 | char hexfpr[2*MAX_FINGERPRINT_LEN+1]; |
1914 | 0 | char *mbox; |
1915 | |
|
1916 | 0 | (void)ctrl; |
1917 | |
|
1918 | 0 | node = find_kbnode (keyblock, PKT_PUBLIC_KEY); |
1919 | 0 | if (!node) |
1920 | 0 | { |
1921 | 0 | log_error ("Oops; key lost!\n"); |
1922 | 0 | dump_kbnode (keyblock); |
1923 | 0 | return; |
1924 | 0 | } |
1925 | 0 | hexfingerprint (node->pkt->pkt.public_key, hexfpr, sizeof hexfpr); |
1926 | |
|
1927 | 0 | for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));) |
1928 | 0 | { |
1929 | 0 | if (node->pkt->pkttype == PKT_USER_ID) |
1930 | 0 | { |
1931 | 0 | PKT_user_id *uid = node->pkt->pkt.user_id; |
1932 | |
|
1933 | 0 | if (uid->attrib_data) |
1934 | 0 | continue; |
1935 | | |
1936 | 0 | if ((uid->flags.expired || uid->flags.revoked) |
1937 | 0 | && !(opt.list_options & LIST_SHOW_UNUSABLE_UIDS)) |
1938 | 0 | continue; |
1939 | | |
1940 | 0 | mbox = mailbox_from_userid (uid->name, 0); |
1941 | 0 | if (!mbox) |
1942 | 0 | { |
1943 | 0 | ec = gpg_err_code_from_syserror (); |
1944 | 0 | if (ec != GPG_ERR_EINVAL) |
1945 | 0 | log_error ("error getting mailbox from user-id: %s\n", |
1946 | 0 | gpg_strerror (ec)); |
1947 | 0 | continue; |
1948 | 0 | } |
1949 | 0 | es_fprintf (es_stdout, "%s %s\n", hexfpr, mbox); |
1950 | 0 | xfree (mbox); |
1951 | 0 | } |
1952 | 0 | } |
1953 | 0 | } |
1954 | | |
1955 | | |
1956 | | /* Print the revoker records. */ |
1957 | | void |
1958 | | print_revokers (estream_t fp, int colon_mode, PKT_public_key * pk) |
1959 | 0 | { |
1960 | 0 | int i, j; |
1961 | 0 | const byte *p; |
1962 | |
|
1963 | 0 | if (!pk->revkey && pk->numrevkeys) |
1964 | 0 | BUG (); |
1965 | | |
1966 | 0 | for (i = 0; i < pk->numrevkeys; i++) |
1967 | 0 | { |
1968 | 0 | if (colon_mode) |
1969 | 0 | { |
1970 | 0 | es_fprintf (fp, "rvk:::%d::::::", pk->revkey[i].algid); |
1971 | 0 | p = pk->revkey[i].fpr; |
1972 | 0 | for (j = 0; j < pk->revkey[i].fprlen; j++, p++) |
1973 | 0 | es_fprintf (fp, "%02X", *p); |
1974 | 0 | es_fprintf (fp, ":%02x%s:\n", |
1975 | 0 | pk->revkey[i].class, |
1976 | 0 | (pk->revkey[i].class & 0x40) ? "s" : ""); |
1977 | 0 | } |
1978 | 0 | else |
1979 | 0 | { |
1980 | 0 | es_fprintf (fp, "%*s%s", 6, "", _("Revocable by: ")); |
1981 | 0 | p = pk->revkey[i].fpr; |
1982 | 0 | es_write_hexstring (fp, pk->revkey[i].fpr, pk->revkey[i].fprlen, |
1983 | 0 | 0, NULL); |
1984 | 0 | if ((pk->revkey[i].class & 0x40)) |
1985 | 0 | es_fprintf (fp, " %s", _("(sensitive)")); |
1986 | | /* Class bit 7 must always be set, bit 6 indicates sensitive |
1987 | | * and all others bits are reserved. */ |
1988 | 0 | if (!(pk->revkey[i].class & ~0x40) |
1989 | 0 | || (pk->revkey[i].class & ~(0x40|0x80))) |
1990 | 0 | es_fprintf (fp, " (unknown class %02x)", pk->revkey[i].class); |
1991 | 0 | es_fprintf (fp, "\n"); |
1992 | 0 | } |
1993 | 0 | } |
1994 | 0 | } |
1995 | | |
1996 | | |
1997 | | /* Print the compliance flags to field 18. PK is the public key. |
1998 | | * KEYLENGTH is the length of the key in bits and CURVENAME is either |
1999 | | * NULL or the name of the curve. The latter two args are here |
2000 | | * merely because the caller has already computed them. */ |
2001 | | static void |
2002 | | print_compliance_flags (PKT_public_key *pk, |
2003 | | unsigned int keylength, const char *curvename) |
2004 | 0 | { |
2005 | 0 | int any = 0; |
2006 | |
|
2007 | 0 | if (!keylength) |
2008 | 0 | keylength = nbits_from_pk (pk); |
2009 | |
|
2010 | 0 | if (pk->version == 5) |
2011 | 0 | { |
2012 | 0 | es_fputs (gnupg_status_compliance_flag (CO_GNUPG), es_stdout); |
2013 | 0 | any++; |
2014 | 0 | } |
2015 | 0 | if (gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, 0, pk->pkey, |
2016 | 0 | keylength, curvename)) |
2017 | 0 | { |
2018 | 0 | es_fprintf (es_stdout, any ? " %s" : "%s", |
2019 | 0 | gnupg_status_compliance_flag (CO_DE_VS)); |
2020 | 0 | any++; |
2021 | 0 | } |
2022 | |
|
2023 | 0 | if (opt.with_key_screening) |
2024 | 0 | print_pk_screening (pk, 1+any); |
2025 | 0 | } |
2026 | | |
2027 | | |
2028 | | /* List a key in colon mode. If SECRET is true this is a secret key |
2029 | | record (i.e. requested via --list-secret-key). If HAS_SECRET a |
2030 | | secret key is available even if SECRET is not set. */ |
2031 | | static void |
2032 | | list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock, |
2033 | | int secret, int has_secret) |
2034 | 0 | { |
2035 | 0 | int rc; |
2036 | 0 | KBNODE kbctx; |
2037 | 0 | KBNODE node; |
2038 | 0 | PKT_public_key *pk; |
2039 | 0 | u32 keyid[2]; |
2040 | 0 | int trustletter = 0; |
2041 | 0 | int trustletter_print; |
2042 | 0 | int ownertrust_print; |
2043 | 0 | int ulti_hack = 0; |
2044 | 0 | int i; |
2045 | 0 | char *hexgrip_buffer = NULL; |
2046 | 0 | const char *hexgrip = NULL; |
2047 | 0 | char *serialno = NULL; |
2048 | 0 | int stubkey; |
2049 | 0 | unsigned int keylength; |
2050 | 0 | char *curve = NULL; |
2051 | 0 | const char *curvename = NULL; |
2052 | 0 | char pkstrbuf[PUBKEY_STRING_SIZE]; |
2053 | | |
2054 | | /* Get the keyid from the keyblock. */ |
2055 | 0 | node = find_kbnode (keyblock, PKT_PUBLIC_KEY); |
2056 | 0 | if (!node) |
2057 | 0 | { |
2058 | 0 | log_error ("Oops; key lost!\n"); |
2059 | 0 | dump_kbnode (keyblock); |
2060 | 0 | return; |
2061 | 0 | } |
2062 | | |
2063 | 0 | pk = node->pkt->pkt.public_key; |
2064 | 0 | if (secret || has_secret || opt.with_keygrip || opt.with_key_data) |
2065 | 0 | { |
2066 | 0 | rc = hexkeygrip_from_pk (pk, &hexgrip_buffer); |
2067 | 0 | if (rc) |
2068 | 0 | log_error ("error computing a keygrip: %s\n", gpg_strerror (rc)); |
2069 | | /* In the error case we print an empty string so that we have a |
2070 | | * "grp" record for each primary and subkey - even if it is |
2071 | | * empty. This may help to prevent sync problems. */ |
2072 | 0 | hexgrip = hexgrip_buffer? hexgrip_buffer : ""; |
2073 | 0 | } |
2074 | 0 | stubkey = 0; |
2075 | 0 | if ((secret || has_secret) |
2076 | 0 | && agent_get_keyinfo (NULL, hexgrip, &serialno, NULL)) |
2077 | 0 | stubkey = 1; /* Key not found. */ |
2078 | |
|
2079 | 0 | keyid_from_pk (pk, keyid); |
2080 | 0 | if (!pk->flags.valid) |
2081 | 0 | trustletter_print = 'i'; |
2082 | 0 | else if (pk->flags.revoked) |
2083 | 0 | trustletter_print = 'r'; |
2084 | 0 | else if (pk->has_expired) |
2085 | 0 | trustletter_print = 'e'; |
2086 | 0 | else if (opt.fast_list_mode || opt.no_expensive_trust_checks) |
2087 | 0 | trustletter_print = 0; |
2088 | 0 | else |
2089 | 0 | { |
2090 | 0 | trustletter = get_validity_info (ctrl, keyblock, pk, NULL); |
2091 | 0 | if (trustletter == 'u') |
2092 | 0 | ulti_hack = 1; |
2093 | 0 | trustletter_print = trustletter; |
2094 | 0 | } |
2095 | |
|
2096 | 0 | if (!opt.fast_list_mode && !opt.no_expensive_trust_checks) |
2097 | 0 | ownertrust_print = get_ownertrust_info (ctrl, pk, 0); |
2098 | 0 | else |
2099 | 0 | ownertrust_print = 0; |
2100 | |
|
2101 | 0 | keylength = nbits_from_pk (pk); |
2102 | |
|
2103 | 0 | es_fputs (secret? "sec:":"pub:", es_stdout); |
2104 | 0 | if (trustletter_print) |
2105 | 0 | es_putc (trustletter_print, es_stdout); |
2106 | 0 | es_fprintf (es_stdout, ":%u:%d:%08lX%08lX:%s:%s::", |
2107 | 0 | keylength, |
2108 | 0 | pk->pubkey_algo, |
2109 | 0 | (ulong) keyid[0], (ulong) keyid[1], |
2110 | 0 | colon_datestr_from_pk (pk), colon_strtime (pk->expiredate)); |
2111 | |
|
2112 | 0 | if (ownertrust_print) |
2113 | 0 | es_putc (ownertrust_print, es_stdout); |
2114 | 0 | es_putc (':', es_stdout); |
2115 | |
|
2116 | 0 | es_putc (':', es_stdout); |
2117 | 0 | es_putc (':', es_stdout); |
2118 | 0 | print_capabilities (ctrl, pk, keyblock); |
2119 | 0 | es_putc (':', es_stdout); /* End of field 13. */ |
2120 | 0 | es_putc (':', es_stdout); /* End of field 14. */ |
2121 | 0 | if (secret || has_secret) |
2122 | 0 | { |
2123 | 0 | if (stubkey) |
2124 | 0 | es_putc ('#', es_stdout); |
2125 | 0 | else if (serialno) |
2126 | 0 | es_fputs (serialno, es_stdout); |
2127 | 0 | else if (has_secret) |
2128 | 0 | es_putc ('+', es_stdout); |
2129 | 0 | } |
2130 | 0 | es_putc (':', es_stdout); /* End of field 15. */ |
2131 | 0 | es_putc (':', es_stdout); /* End of field 16. */ |
2132 | 0 | if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA |
2133 | 0 | || pk->pubkey_algo == PUBKEY_ALGO_EDDSA |
2134 | 0 | || pk->pubkey_algo == PUBKEY_ALGO_ECDH) |
2135 | 0 | { |
2136 | 0 | curve = openpgp_oid_to_str (pk->pkey[0]); |
2137 | 0 | curvename = openpgp_oid_to_curve (curve, 0); |
2138 | 0 | if (!curvename) |
2139 | 0 | curvename = curve; |
2140 | 0 | es_fputs (curvename, es_stdout); |
2141 | 0 | } |
2142 | 0 | else if (pk->pubkey_algo == PUBKEY_ALGO_KYBER) |
2143 | 0 | { |
2144 | | /* Note that Kyber should actually not appear here because it is |
2145 | | * the primary key and Kyber is not able to certify. But we |
2146 | | * prepare it here for future composite algorithms and in case |
2147 | | * of faulty packets. */ |
2148 | 0 | es_fputs (pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), es_stdout); |
2149 | 0 | } |
2150 | 0 | es_putc (':', es_stdout); /* End of field 17. */ |
2151 | 0 | print_compliance_flags (pk, keylength, curvename); |
2152 | 0 | es_putc (':', es_stdout); /* End of field 18 (compliance). */ |
2153 | 0 | if (pk->keyupdate) |
2154 | 0 | es_fputs (colon_strtime (pk->keyupdate), es_stdout); |
2155 | 0 | es_putc (':', es_stdout); /* End of field 19 (last_update). */ |
2156 | 0 | es_fprintf (es_stdout, "%d%s", pk->keyorg, pk->updateurl? " ":""); |
2157 | 0 | if (pk->updateurl) |
2158 | 0 | es_write_sanitized (es_stdout, pk->updateurl, strlen (pk->updateurl), |
2159 | 0 | ":", NULL); |
2160 | 0 | es_putc (':', es_stdout); /* End of field 20 (origin). */ |
2161 | 0 | if (pk->flags.revoked && pk->revoked.got_reason |
2162 | 0 | && (pk->revoked.reason_code || pk->revoked.reason_comment)) |
2163 | 0 | { |
2164 | 0 | char *freeme; |
2165 | 0 | const char *s; |
2166 | 0 | size_t n; |
2167 | |
|
2168 | 0 | s = revocation_reason_code_to_str (pk->revoked.reason_code, &freeme); |
2169 | 0 | n = strlen (s); |
2170 | 0 | es_write_sanitized (es_stdout, s, n, ":", NULL); |
2171 | 0 | if (n && s[n-1] != '.') |
2172 | 0 | es_putc ('.', es_stdout); |
2173 | 0 | es_putc ('\\', es_stdout); /* C-style escaped colon. */ |
2174 | 0 | es_putc ('n', es_stdout); |
2175 | 0 | es_write_sanitized (es_stdout, pk->revoked.reason_comment, |
2176 | 0 | pk->revoked.reason_comment_len, |
2177 | 0 | ":", NULL); |
2178 | 0 | xfree (freeme); |
2179 | 0 | es_putc (':', es_stdout); /* End of field 21 (comment). */ |
2180 | 0 | } |
2181 | 0 | es_putc ('\n', es_stdout); |
2182 | |
|
2183 | 0 | print_revokers (es_stdout, 1, pk); |
2184 | 0 | print_fingerprint (ctrl, NULL, pk, 0); |
2185 | 0 | if (hexgrip) |
2186 | 0 | es_fprintf (es_stdout, "grp:::::::::%s:\n", hexgrip); |
2187 | 0 | if (opt.with_key_data) |
2188 | 0 | print_key_data (pk); |
2189 | |
|
2190 | 0 | for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));) |
2191 | 0 | { |
2192 | 0 | if (node->pkt->pkttype == PKT_USER_ID) |
2193 | 0 | { |
2194 | 0 | PKT_user_id *uid = node->pkt->pkt.user_id; |
2195 | 0 | int uid_validity; |
2196 | |
|
2197 | 0 | if (attrib_fp && uid->attrib_data != NULL) |
2198 | 0 | dump_attribs (uid, pk); |
2199 | |
|
2200 | 0 | if (uid->flags.revoked) |
2201 | 0 | uid_validity = 'r'; |
2202 | 0 | else if (uid->flags.expired) |
2203 | 0 | uid_validity = 'e'; |
2204 | 0 | else if (opt.no_expensive_trust_checks) |
2205 | 0 | uid_validity = 0; |
2206 | 0 | else if (ulti_hack) |
2207 | 0 | uid_validity = 'u'; |
2208 | 0 | else |
2209 | 0 | uid_validity = get_validity_info (ctrl, keyblock, pk, uid); |
2210 | |
|
2211 | 0 | es_fputs (uid->attrib_data? "uat:":"uid:", es_stdout); |
2212 | 0 | if (uid_validity) |
2213 | 0 | es_putc (uid_validity, es_stdout); |
2214 | 0 | es_fputs ("::::", es_stdout); |
2215 | |
|
2216 | 0 | es_fprintf (es_stdout, "%s:", colon_strtime (uid->created)); |
2217 | 0 | es_fprintf (es_stdout, "%s:", colon_strtime (uid->expiredate)); |
2218 | |
|
2219 | 0 | namehash_from_uid (uid); |
2220 | |
|
2221 | 0 | for (i = 0; i < 20; i++) |
2222 | 0 | es_fprintf (es_stdout, "%02X", uid->namehash[i]); |
2223 | |
|
2224 | 0 | es_fprintf (es_stdout, "::"); |
2225 | |
|
2226 | 0 | if (uid->attrib_data) |
2227 | 0 | es_fprintf (es_stdout, "%u %lu", uid->numattribs, uid->attrib_len); |
2228 | 0 | else |
2229 | 0 | es_write_sanitized (es_stdout, uid->name, uid->len, ":", NULL); |
2230 | 0 | es_fputs (":::::::::", es_stdout); |
2231 | 0 | if (uid->keyupdate) |
2232 | 0 | es_fputs (colon_strtime (uid->keyupdate), es_stdout); |
2233 | 0 | es_putc (':', es_stdout); /* End of field 19 (last_update). */ |
2234 | 0 | es_fprintf (es_stdout, "%d%s", uid->keyorg, uid->updateurl? " ":""); |
2235 | 0 | if (uid->updateurl) |
2236 | 0 | es_write_sanitized (es_stdout, |
2237 | 0 | uid->updateurl, strlen (uid->updateurl), |
2238 | 0 | ":", NULL); |
2239 | 0 | es_putc (':', es_stdout); /* End of field 20 (origin). */ |
2240 | 0 | es_putc ('\n', es_stdout); |
2241 | 0 | if ((opt.list_options & (LIST_SHOW_PREF|LIST_SHOW_PREF_VERBOSE))) |
2242 | 0 | show_preferences (uid, 0, 2, 0); |
2243 | | #ifdef USE_TOFU |
2244 | | if (!uid->attrib_data && opt.with_tofu_info |
2245 | | && (opt.trust_model == TM_TOFU || opt.trust_model == TM_TOFU_PGP)) |
2246 | | { |
2247 | | /* Print a "tfs" record. */ |
2248 | | tofu_write_tfs_record (ctrl, es_stdout, pk, uid->name); |
2249 | | } |
2250 | | #endif /*USE_TOFU*/ |
2251 | 0 | } |
2252 | 0 | else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) |
2253 | 0 | { |
2254 | 0 | u32 keyid2[2]; |
2255 | 0 | PKT_public_key *pk2; |
2256 | 0 | int need_hexgrip = !!hexgrip; |
2257 | |
|
2258 | 0 | pk2 = node->pkt->pkt.public_key; |
2259 | 0 | xfree (hexgrip_buffer); hexgrip_buffer = NULL; hexgrip = NULL; |
2260 | 0 | xfree (serialno); serialno = NULL; |
2261 | 0 | if (need_hexgrip |
2262 | 0 | || secret || has_secret || opt.with_keygrip || opt.with_key_data) |
2263 | 0 | { |
2264 | 0 | rc = hexkeygrip_from_pk (pk2, &hexgrip_buffer); |
2265 | 0 | if (rc) |
2266 | 0 | log_error ("error computing a keygrip: %s\n", |
2267 | 0 | gpg_strerror (rc)); |
2268 | 0 | hexgrip = hexgrip_buffer? hexgrip_buffer : ""; |
2269 | 0 | } |
2270 | 0 | stubkey = 0; |
2271 | 0 | if ((secret||has_secret) |
2272 | 0 | && agent_get_keyinfo (NULL, hexgrip, &serialno, NULL)) |
2273 | 0 | stubkey = 1; /* Key not found. */ |
2274 | |
|
2275 | 0 | keyid_from_pk (pk2, keyid2); |
2276 | 0 | es_fputs (secret? "ssb:":"sub:", es_stdout); |
2277 | 0 | if (!pk2->flags.valid) |
2278 | 0 | es_putc ('i', es_stdout); |
2279 | 0 | else if (pk2->flags.revoked) |
2280 | 0 | es_putc ('r', es_stdout); |
2281 | 0 | else if (pk2->has_expired) |
2282 | 0 | es_putc ('e', es_stdout); |
2283 | 0 | else if (opt.fast_list_mode || opt.no_expensive_trust_checks) |
2284 | 0 | ; |
2285 | 0 | else |
2286 | 0 | { |
2287 | | /* TRUSTLETTER should always be defined here. */ |
2288 | 0 | if (trustletter) |
2289 | 0 | es_fprintf (es_stdout, "%c", trustletter); |
2290 | 0 | } |
2291 | 0 | keylength = nbits_from_pk (pk2); |
2292 | 0 | es_fprintf (es_stdout, ":%u:%d:%08lX%08lX:%s:%s:::::", |
2293 | 0 | keylength, |
2294 | 0 | pk2->pubkey_algo, |
2295 | 0 | (ulong) keyid2[0], (ulong) keyid2[1], |
2296 | 0 | colon_datestr_from_pk (pk2), |
2297 | 0 | colon_strtime (pk2->expiredate)); |
2298 | 0 | print_capabilities (ctrl, pk2, NULL); |
2299 | 0 | es_putc (':', es_stdout); /* End of field 13. */ |
2300 | 0 | es_putc (':', es_stdout); /* End of field 14. */ |
2301 | 0 | if (secret || has_secret) |
2302 | 0 | { |
2303 | 0 | if (stubkey) |
2304 | 0 | es_putc ('#', es_stdout); |
2305 | 0 | else if (serialno) |
2306 | 0 | es_fputs (serialno, es_stdout); |
2307 | 0 | else if (has_secret) |
2308 | 0 | es_putc ('+', es_stdout); |
2309 | 0 | } |
2310 | 0 | es_putc (':', es_stdout); /* End of field 15. */ |
2311 | 0 | es_putc (':', es_stdout); /* End of field 16. */ |
2312 | 0 | if (pk2->pubkey_algo == PUBKEY_ALGO_ECDSA |
2313 | 0 | || pk2->pubkey_algo == PUBKEY_ALGO_EDDSA |
2314 | 0 | || pk2->pubkey_algo == PUBKEY_ALGO_ECDH) |
2315 | 0 | { |
2316 | 0 | xfree (curve); |
2317 | 0 | curve = openpgp_oid_to_str (pk2->pkey[0]); |
2318 | 0 | curvename = openpgp_oid_to_curve (curve, 0); |
2319 | 0 | if (!curvename) |
2320 | 0 | curvename = curve; |
2321 | 0 | es_fputs (curvename, es_stdout); |
2322 | 0 | } |
2323 | 0 | else if (pk2->pubkey_algo == PUBKEY_ALGO_KYBER) |
2324 | 0 | { |
2325 | 0 | es_fputs (pubkey_string (pk2, pkstrbuf, sizeof pkstrbuf), |
2326 | 0 | es_stdout); |
2327 | 0 | } |
2328 | 0 | es_putc (':', es_stdout); /* End of field 17. */ |
2329 | 0 | print_compliance_flags (pk2, keylength, curvename); |
2330 | 0 | es_putc (':', es_stdout); /* End of field 18. */ |
2331 | 0 | es_putc ('\n', es_stdout); |
2332 | 0 | print_fingerprint (ctrl, NULL, pk2, 0); |
2333 | 0 | if (hexgrip) |
2334 | 0 | es_fprintf (es_stdout, "grp:::::::::%s:\n", hexgrip); |
2335 | 0 | if (opt.with_key_data) |
2336 | 0 | print_key_data (pk2); |
2337 | 0 | } |
2338 | 0 | else if (opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE) |
2339 | 0 | { |
2340 | 0 | PKT_signature *sig = node->pkt->pkt.signature; |
2341 | 0 | int sigrc, fprokay = 0; |
2342 | 0 | char *sigstr; |
2343 | 0 | size_t fplen; |
2344 | 0 | byte fparray[MAX_FINGERPRINT_LEN]; |
2345 | 0 | char *siguid; |
2346 | 0 | size_t siguidlen; |
2347 | 0 | char *issuer_fpr = NULL; |
2348 | 0 | char *reason_text = NULL; |
2349 | 0 | char *reason_comment = NULL; |
2350 | 0 | size_t reason_commentlen; |
2351 | 0 | int reason_code = 0; /* Init to silence compiler warning. */ |
2352 | |
|
2353 | 0 | if (sig->sig_class == 0x20 || sig->sig_class == 0x28 |
2354 | 0 | || sig->sig_class == 0x30) |
2355 | 0 | { |
2356 | 0 | sigstr = "rev"; |
2357 | 0 | reason_code = get_revocation_reason (sig, &reason_text, |
2358 | 0 | &reason_comment, |
2359 | 0 | &reason_commentlen); |
2360 | 0 | } |
2361 | 0 | else if ((sig->sig_class & ~3) == 0x10) |
2362 | 0 | sigstr = "sig"; |
2363 | 0 | else if (sig->sig_class == 0x18) |
2364 | 0 | sigstr = "sig"; |
2365 | 0 | else if (sig->sig_class == 0x1F) |
2366 | 0 | sigstr = "sig"; |
2367 | 0 | else |
2368 | 0 | { |
2369 | 0 | es_fprintf (es_stdout, "sig::::::::::%02x%c:\n", |
2370 | 0 | sig->sig_class, sig->flags.exportable ? 'x' : 'l'); |
2371 | 0 | continue; |
2372 | 0 | } |
2373 | | |
2374 | 0 | if (opt.check_sigs) |
2375 | 0 | { |
2376 | 0 | PKT_public_key *signer_pk = NULL; |
2377 | |
|
2378 | 0 | es_fflush (es_stdout); |
2379 | 0 | if (opt.no_sig_cache) |
2380 | 0 | signer_pk = xmalloc_clear (sizeof (PKT_public_key)); |
2381 | |
|
2382 | 0 | rc = check_key_signature2 (ctrl, keyblock, node, NULL, signer_pk, |
2383 | 0 | NULL, NULL, NULL); |
2384 | 0 | switch (gpg_err_code (rc)) |
2385 | 0 | { |
2386 | 0 | case 0: |
2387 | 0 | sigrc = '!'; |
2388 | 0 | break; |
2389 | 0 | case GPG_ERR_BAD_SIGNATURE: |
2390 | 0 | sigrc = '-'; |
2391 | 0 | break; |
2392 | 0 | case GPG_ERR_NO_PUBKEY: |
2393 | 0 | case GPG_ERR_UNUSABLE_PUBKEY: |
2394 | 0 | sigrc = '?'; |
2395 | 0 | break; |
2396 | 0 | default: |
2397 | 0 | sigrc = '%'; |
2398 | 0 | break; |
2399 | 0 | } |
2400 | | |
2401 | 0 | if (opt.no_sig_cache) |
2402 | 0 | { |
2403 | 0 | if (!rc) |
2404 | 0 | { |
2405 | 0 | fingerprint_from_pk (signer_pk, fparray, &fplen); |
2406 | 0 | fprokay = 1; |
2407 | 0 | } |
2408 | 0 | free_public_key (signer_pk); |
2409 | 0 | } |
2410 | 0 | } |
2411 | 0 | else |
2412 | 0 | { |
2413 | 0 | rc = 0; |
2414 | 0 | sigrc = ' '; /* Note the fix-up below in --list-sigs mode. */ |
2415 | 0 | } |
2416 | | |
2417 | 0 | if (sigrc != '%' && sigrc != '?' && !opt.fast_list_mode) |
2418 | 0 | { |
2419 | 0 | int nouid; |
2420 | 0 | siguid = get_user_id (ctrl, sig->keyid, &siguidlen, &nouid); |
2421 | 0 | if (!opt.check_sigs && nouid) |
2422 | 0 | sigrc = '?'; /* No key in local keyring. */ |
2423 | 0 | } |
2424 | 0 | else |
2425 | 0 | { |
2426 | 0 | siguid = NULL; |
2427 | 0 | siguidlen = 0; |
2428 | 0 | } |
2429 | | |
2430 | |
|
2431 | 0 | es_fputs (sigstr, es_stdout); |
2432 | 0 | es_putc (':', es_stdout); |
2433 | 0 | if (sigrc != ' ') |
2434 | 0 | es_putc (sigrc, es_stdout); |
2435 | 0 | es_fprintf (es_stdout, "::%d:%08lX%08lX:%s:%s:", sig->pubkey_algo, |
2436 | 0 | (ulong) sig->keyid[0], (ulong) sig->keyid[1], |
2437 | 0 | colon_datestr_from_sig (sig), |
2438 | 0 | colon_expirestr_from_sig (sig)); |
2439 | |
|
2440 | 0 | if (sig->trust_depth || sig->trust_value) |
2441 | 0 | es_fprintf (es_stdout, "%d %d", sig->trust_depth, sig->trust_value); |
2442 | 0 | es_fprintf (es_stdout, ":"); |
2443 | |
|
2444 | 0 | if (sig->trust_regexp) |
2445 | 0 | es_write_sanitized (es_stdout, sig->trust_regexp, |
2446 | 0 | strlen (sig->trust_regexp), ":", NULL); |
2447 | 0 | es_fprintf (es_stdout, ":"); |
2448 | |
|
2449 | 0 | if (sigrc == '%') |
2450 | 0 | es_fprintf (es_stdout, "[%s] ", gpg_strerror (rc)); |
2451 | 0 | else if (siguid) |
2452 | 0 | es_write_sanitized (es_stdout, siguid, siguidlen, ":", NULL); |
2453 | |
|
2454 | 0 | es_fprintf (es_stdout, ":%02x%c", sig->sig_class, |
2455 | 0 | sig->flags.exportable ? 'x' : 'l'); |
2456 | 0 | if (reason_text) |
2457 | 0 | es_fprintf (es_stdout, ",%02x", reason_code); |
2458 | 0 | es_fputs ("::", es_stdout); |
2459 | |
|
2460 | 0 | if (opt.no_sig_cache && opt.check_sigs && fprokay) |
2461 | 0 | { |
2462 | 0 | for (i = 0; i < fplen; i++) |
2463 | 0 | es_fprintf (es_stdout, "%02X", fparray[i]); |
2464 | 0 | } |
2465 | 0 | else if ((issuer_fpr = issuer_fpr_string (sig))) |
2466 | 0 | es_fputs (issuer_fpr, es_stdout); |
2467 | |
|
2468 | 0 | es_fprintf (es_stdout, ":::%d:", sig->digest_algo); |
2469 | |
|
2470 | 0 | if (reason_comment) |
2471 | 0 | { |
2472 | 0 | es_fputs ("::::", es_stdout); |
2473 | 0 | es_write_sanitized (es_stdout, reason_comment, reason_commentlen, |
2474 | 0 | ":", NULL); |
2475 | 0 | es_putc (':', es_stdout); |
2476 | 0 | } |
2477 | 0 | es_putc ('\n', es_stdout); |
2478 | |
|
2479 | 0 | if (opt.show_subpackets) |
2480 | 0 | print_subpackets_colon (sig); |
2481 | | |
2482 | | /* fixme: check or list other sigs here */ |
2483 | 0 | xfree (reason_text); |
2484 | 0 | xfree (reason_comment); |
2485 | 0 | xfree (siguid); |
2486 | 0 | xfree (issuer_fpr); |
2487 | 0 | } |
2488 | 0 | } |
2489 | | |
2490 | 0 | xfree (curve); |
2491 | 0 | xfree (hexgrip_buffer); |
2492 | 0 | xfree (serialno); |
2493 | 0 | } |
2494 | | |
2495 | | /* |
2496 | | * Reorder the keyblock so that the primary user ID (and not attribute |
2497 | | * packet) comes first. Fixme: Replace this by a generic sort |
2498 | | * function. */ |
2499 | | static void |
2500 | | do_reorder_keyblock (KBNODE keyblock, int attr) |
2501 | 0 | { |
2502 | 0 | KBNODE primary = NULL, primary0 = NULL, primary2 = NULL; |
2503 | 0 | KBNODE last, node; |
2504 | |
|
2505 | 0 | for (node = keyblock; node; primary0 = node, node = node->next) |
2506 | 0 | { |
2507 | 0 | if (node->pkt->pkttype == PKT_USER_ID && |
2508 | 0 | ((attr && node->pkt->pkt.user_id->attrib_data) || |
2509 | 0 | (!attr && !node->pkt->pkt.user_id->attrib_data)) && |
2510 | 0 | node->pkt->pkt.user_id->flags.primary) |
2511 | 0 | { |
2512 | 0 | primary = primary2 = node; |
2513 | 0 | for (node = node->next; node; primary2 = node, node = node->next) |
2514 | 0 | { |
2515 | 0 | if (node->pkt->pkttype == PKT_USER_ID |
2516 | 0 | || node->pkt->pkttype == PKT_PUBLIC_SUBKEY |
2517 | 0 | || node->pkt->pkttype == PKT_SECRET_SUBKEY) |
2518 | 0 | { |
2519 | 0 | break; |
2520 | 0 | } |
2521 | 0 | } |
2522 | 0 | break; |
2523 | 0 | } |
2524 | 0 | } |
2525 | 0 | if (!primary) |
2526 | 0 | return; /* No primary key flag found (should not happen). */ |
2527 | | |
2528 | 0 | for (last = NULL, node = keyblock; node; last = node, node = node->next) |
2529 | 0 | { |
2530 | 0 | if (node->pkt->pkttype == PKT_USER_ID) |
2531 | 0 | break; |
2532 | 0 | } |
2533 | 0 | log_assert (node); |
2534 | 0 | log_assert (last); /* The user ID is never the first packet. */ |
2535 | 0 | log_assert (primary0); /* Ditto (this is the node before primary). */ |
2536 | 0 | if (node == primary) |
2537 | 0 | return; /* Already the first one. */ |
2538 | | |
2539 | 0 | last->next = primary; |
2540 | 0 | primary0->next = primary2->next; |
2541 | 0 | primary2->next = node; |
2542 | 0 | } |
2543 | | |
2544 | | void |
2545 | | reorder_keyblock (KBNODE keyblock) |
2546 | 0 | { |
2547 | 0 | do_reorder_keyblock (keyblock, 1); |
2548 | 0 | do_reorder_keyblock (keyblock, 0); |
2549 | 0 | } |
2550 | | |
2551 | | |
2552 | | /* Note: If this function returns an error the caller is expected to |
2553 | | * honor this and stop all further processing. Any error returned |
2554 | | * will be a write error (to stdout) and a diagnostics is always |
2555 | | * printed using log_error. */ |
2556 | | static gpg_error_t |
2557 | | list_keyblock (ctrl_t ctrl, |
2558 | | KBNODE keyblock, int secret, int has_secret, int fpr, |
2559 | | struct keylist_context *listctx) |
2560 | 0 | { |
2561 | 0 | gpg_error_t err = 0; |
2562 | |
|
2563 | 0 | es_clearerr (es_stdout); |
2564 | 0 | reorder_keyblock (keyblock); |
2565 | |
|
2566 | 0 | if (list_filter.selkey) |
2567 | 0 | { |
2568 | 0 | int selected = 0; |
2569 | 0 | struct impex_filter_parm_s parm; |
2570 | 0 | parm.ctrl = ctrl; |
2571 | |
|
2572 | 0 | for (parm.node = keyblock; parm.node; parm.node = parm.node->next) |
2573 | 0 | { |
2574 | 0 | if (recsel_select (list_filter.selkey, impex_filter_getval, &parm)) |
2575 | 0 | { |
2576 | 0 | selected = 1; |
2577 | 0 | break; |
2578 | 0 | } |
2579 | 0 | } |
2580 | 0 | if (!selected) |
2581 | 0 | return 0; /* Skip this one. */ |
2582 | 0 | } |
2583 | | |
2584 | 0 | if (opt.with_colons) |
2585 | 0 | list_keyblock_colon (ctrl, keyblock, secret, has_secret); |
2586 | 0 | else if ((opt.list_options & LIST_SHOW_ONLY_FPR_MBOX)) |
2587 | 0 | { |
2588 | 0 | if (!listctx->no_validity) |
2589 | 0 | check_trustdb_stale (ctrl); |
2590 | 0 | list_keyblock_simple (ctrl, keyblock); |
2591 | 0 | } |
2592 | 0 | else |
2593 | 0 | list_keyblock_print (ctrl, keyblock, secret, fpr, listctx); |
2594 | |
|
2595 | 0 | if (es_ferror (es_stdout)) |
2596 | 0 | err = gpg_error_from_syserror (); |
2597 | |
|
2598 | 0 | if (secret && es_fflush (es_stdout) && !err) |
2599 | 0 | err = gpg_error_from_syserror (); |
2600 | |
|
2601 | 0 | if (err) |
2602 | 0 | log_error (_("error writing to stdout: %s\n"), gpg_strerror (err)); |
2603 | |
|
2604 | 0 | return err; |
2605 | 0 | } |
2606 | | |
2607 | | |
2608 | | /* Public function used by keygen to list a keyblock. If NO_VALIDITY |
2609 | | * is set the validity of a key is never shown. */ |
2610 | | gpg_error_t |
2611 | | list_keyblock_direct (ctrl_t ctrl, |
2612 | | kbnode_t keyblock, int secret, int has_secret, int fpr, |
2613 | | int no_validity) |
2614 | 0 | { |
2615 | 0 | struct keylist_context listctx; |
2616 | 0 | gpg_error_t err; |
2617 | |
|
2618 | 0 | memset (&listctx, 0, sizeof (listctx)); |
2619 | 0 | listctx.no_validity = !!no_validity; |
2620 | 0 | if (opt.check_sigs) |
2621 | 0 | listctx.check_sigs = 1; |
2622 | 0 | err = list_keyblock (ctrl, keyblock, secret, has_secret, fpr, &listctx); |
2623 | 0 | keylist_context_release (&listctx); |
2624 | 0 | return err; |
2625 | 0 | } |
2626 | | |
2627 | | |
2628 | | /* Print an hex digit in ICAO spelling. */ |
2629 | | static void |
2630 | | print_icao_hexdigit (estream_t fp, int c) |
2631 | 0 | { |
2632 | 0 | static const char *list[16] = { |
2633 | 0 | "Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", |
2634 | 0 | "Eight", "Niner", "Alfa", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot" |
2635 | 0 | }; |
2636 | |
|
2637 | 0 | tty_fprintf (fp, "%s", list[c&15]); |
2638 | 0 | } |
2639 | | |
2640 | | |
2641 | | /* |
2642 | | * Function to print the finperprint. |
2643 | | * mode 0: as used in key listings, opt.with_colons is honored |
2644 | | * 1: print using log_info () |
2645 | | * 2: direct use of tty |
2646 | | * 3: direct use of tty but only primary key. |
2647 | | * 4: direct use of tty but only subkey. |
2648 | | * 10: Same as 0 but with_colons etc is ignored. |
2649 | | * 20: Same as 0 but using a compact format. |
2650 | | * |
2651 | | * Modes 1 and 2 will try and print both subkey and primary key |
2652 | | * fingerprints. A MODE with bit 7 set is used internally. If |
2653 | | * OVERRIDE_FP is not NULL that stream will be used in 0 instead |
2654 | | * of es_stdout or instead of the TTY in modes 2 and 3. |
2655 | | */ |
2656 | | void |
2657 | | print_fingerprint (ctrl_t ctrl, estream_t override_fp, |
2658 | | PKT_public_key *pk, int mode) |
2659 | 0 | { |
2660 | 0 | char hexfpr[2*MAX_FINGERPRINT_LEN+1]; |
2661 | 0 | char *p; |
2662 | 0 | size_t i; |
2663 | 0 | estream_t fp; |
2664 | 0 | const char *text; |
2665 | 0 | int primary = 0; |
2666 | 0 | int with_colons = opt.with_colons; |
2667 | 0 | int with_icao = opt.with_icao_spelling; |
2668 | 0 | int compact = 0; |
2669 | |
|
2670 | 0 | if (mode == 10) |
2671 | 0 | { |
2672 | 0 | mode = 0; |
2673 | 0 | with_colons = 0; |
2674 | 0 | with_icao = 0; |
2675 | 0 | } |
2676 | 0 | else if (mode == 20) |
2677 | 0 | { |
2678 | 0 | mode = 0; |
2679 | 0 | with_colons = 0; |
2680 | 0 | compact = 1; |
2681 | 0 | } |
2682 | |
|
2683 | 0 | if (!opt.fingerprint && !opt.with_fingerprint |
2684 | 0 | && opt.with_subkey_fingerprint) |
2685 | 0 | compact = 1; |
2686 | |
|
2687 | 0 | if (pk->main_keyid[0] == pk->keyid[0] |
2688 | 0 | && pk->main_keyid[1] == pk->keyid[1]) |
2689 | 0 | primary = 1; |
2690 | | |
2691 | | /* Just to be safe */ |
2692 | 0 | if ((mode & 0x80) && !primary) |
2693 | 0 | { |
2694 | 0 | log_error ("primary key is not really primary!\n"); |
2695 | 0 | return; |
2696 | 0 | } |
2697 | | |
2698 | 0 | mode &= ~0x80; |
2699 | |
|
2700 | 0 | if (!primary && (mode == 1 || mode == 2)) |
2701 | 0 | { |
2702 | 0 | PKT_public_key *primary_pk = xmalloc_clear (sizeof (*primary_pk)); |
2703 | 0 | get_pubkey (ctrl, primary_pk, pk->main_keyid); |
2704 | 0 | print_fingerprint (ctrl, override_fp, primary_pk, (mode | 0x80)); |
2705 | 0 | free_public_key (primary_pk); |
2706 | 0 | } |
2707 | |
|
2708 | 0 | if (mode == 1) |
2709 | 0 | { |
2710 | 0 | fp = log_get_stream (); |
2711 | 0 | if (primary) |
2712 | 0 | text = _("Primary key fingerprint:"); |
2713 | 0 | else |
2714 | 0 | text = _(" Subkey fingerprint:"); |
2715 | 0 | } |
2716 | 0 | else if (mode == 2) |
2717 | 0 | { |
2718 | 0 | fp = override_fp; /* Use tty or given stream. */ |
2719 | 0 | if (primary) |
2720 | | /* TRANSLATORS: this should fit into 24 bytes so that the |
2721 | | * fingerprint data is properly aligned with the user ID */ |
2722 | 0 | text = _(" Primary key fingerprint:"); |
2723 | 0 | else |
2724 | 0 | text = _(" Subkey fingerprint:"); |
2725 | 0 | } |
2726 | 0 | else if (mode == 3) |
2727 | 0 | { |
2728 | 0 | fp = override_fp; /* Use tty or given stream. */ |
2729 | 0 | text = _(" Key fingerprint ="); |
2730 | 0 | } |
2731 | 0 | else if (mode == 4) |
2732 | 0 | { |
2733 | 0 | fp = override_fp; /* Use tty or given stream. */ |
2734 | 0 | text = _(" Subkey fingerprint:"); |
2735 | 0 | } |
2736 | 0 | else |
2737 | 0 | { |
2738 | 0 | fp = override_fp? override_fp : es_stdout; |
2739 | 0 | if (opt.keyid_format == KF_NONE) |
2740 | 0 | { |
2741 | 0 | text = " "; /* To indent ICAO spelling. */ |
2742 | 0 | compact = 1; |
2743 | 0 | } |
2744 | 0 | else |
2745 | 0 | text = _(" Key fingerprint ="); |
2746 | 0 | } |
2747 | |
|
2748 | 0 | hexfingerprint (pk, hexfpr, sizeof hexfpr); |
2749 | 0 | if (with_colons && !mode) |
2750 | 0 | { |
2751 | 0 | es_fprintf (fp, "fpr:::::::::%s:", hexfpr); |
2752 | 0 | if (opt.with_v5_fingerprint && pk->version == 4) |
2753 | 0 | { |
2754 | 0 | char *v5fpr = v5hexfingerprint (pk, NULL, 0); |
2755 | 0 | es_fprintf (fp, "\nfp2:::::::::%s:", v5fpr); |
2756 | 0 | xfree (v5fpr); |
2757 | 0 | } |
2758 | 0 | } |
2759 | 0 | else if (compact && !opt.fingerprint && !opt.with_fingerprint) |
2760 | 0 | { |
2761 | 0 | tty_fprintf (fp, "%*s%s", 6, "", hexfpr); |
2762 | 0 | } |
2763 | 0 | else |
2764 | 0 | { |
2765 | 0 | char fmtfpr[MAX_FORMATTED_FINGERPRINT_LEN + 1]; |
2766 | 0 | format_hexfingerprint (hexfpr, fmtfpr, sizeof fmtfpr); |
2767 | 0 | if (compact) |
2768 | 0 | tty_fprintf (fp, "%*s%s", 6, "", fmtfpr); |
2769 | 0 | else |
2770 | 0 | tty_fprintf (fp, "%s %s", text, fmtfpr); |
2771 | 0 | } |
2772 | 0 | tty_fprintf (fp, "\n"); |
2773 | 0 | if (!with_colons && with_icao) |
2774 | 0 | { |
2775 | 0 | ; |
2776 | 0 | tty_fprintf (fp, "%*s\"", (int)strlen(text)+1, ""); |
2777 | 0 | for (i = 0, p = hexfpr; *p; i++, p++) |
2778 | 0 | { |
2779 | 0 | if (!i) |
2780 | 0 | ; |
2781 | 0 | else if (!(i%10)) |
2782 | 0 | tty_fprintf (fp, "\n%*s ", (int)strlen(text)+1, ""); |
2783 | 0 | else if (!(i%5)) |
2784 | 0 | tty_fprintf (fp, " "); |
2785 | 0 | else |
2786 | 0 | tty_fprintf (fp, " "); |
2787 | 0 | print_icao_hexdigit (fp, xtoi_1 (p)); |
2788 | 0 | } |
2789 | 0 | tty_fprintf (fp, "\"\n"); |
2790 | 0 | } |
2791 | 0 | } |
2792 | | |
2793 | | /* Print the serial number of an OpenPGP card if available. */ |
2794 | | static void |
2795 | | print_card_serialno (const char *serialno) |
2796 | 0 | { |
2797 | 0 | if (!serialno) |
2798 | 0 | return; |
2799 | 0 | if (opt.with_colons) |
2800 | 0 | return; /* Handled elsewhere. */ |
2801 | | |
2802 | 0 | es_fputs (_(" Card serial no. ="), es_stdout); |
2803 | 0 | es_putc (' ', es_stdout); |
2804 | 0 | if (strlen (serialno) == 32 && !strncmp (serialno, "D27600012401", 12)) |
2805 | 0 | { |
2806 | | /* This is an OpenPGP card. Print the relevant part. */ |
2807 | | /* Example: D2760001240101010001000003470000 */ |
2808 | | /* xxxxyyyyyyyy */ |
2809 | 0 | es_fprintf (es_stdout, "%.*s %.*s", 4, serialno+16, 8, serialno+20); |
2810 | 0 | } |
2811 | 0 | else |
2812 | 0 | es_fputs (serialno, es_stdout); |
2813 | 0 | es_putc ('\n', es_stdout); |
2814 | 0 | } |
2815 | | |
2816 | | |
2817 | | /* Print a public or secret (sub)key line. Example: |
2818 | | * |
2819 | | * pub dsa2048 2007-12-31 [SC] [expires: 2018-12-31] |
2820 | | * 80615870F5BAD690333686D0F2AD85AC1E42B367 |
2821 | | * |
2822 | | * pub rsa2048 2017-12-31 [SC] [expires: 2028-12-31] |
2823 | | * 80615870F5BAD690333686D0F2AD85AC1E42B3671122334455 |
2824 | | * |
2825 | | * Some global options may result in a different output format. If |
2826 | | * SECRET is set, "sec" or "ssb" is used instead of "pub" or "sub" and |
2827 | | * depending on the value a flag character is shown: |
2828 | | * |
2829 | | * 1 := ' ' Regular secret key |
2830 | | * 2 := '#' Stub secret key |
2831 | | * 3 := '>' Secret key is on a token. |
2832 | | */ |
2833 | | void |
2834 | | print_key_line (ctrl_t ctrl, estream_t fp, PKT_public_key *pk, int secret) |
2835 | 0 | { |
2836 | 0 | char pkstrbuf[PUBKEY_STRING_SIZE]; |
2837 | |
|
2838 | 0 | tty_fprintf (fp, "%s%c %s", |
2839 | 0 | pk->flags.primary? (secret? "sec":"pub") |
2840 | 0 | /**/ : (secret? "ssb":"sub"), |
2841 | 0 | secret == 2? '#' : secret == 3? '>' : ' ', |
2842 | 0 | pubkey_string (pk, pkstrbuf, sizeof pkstrbuf)); |
2843 | 0 | if (opt.keyid_format != KF_NONE) |
2844 | 0 | tty_fprintf (fp, "/%s", keystr_from_pk (pk)); |
2845 | 0 | tty_fprintf (fp, " %s", datestr_from_pk (pk)); |
2846 | |
|
2847 | 0 | if (pk->flags.primary |
2848 | 0 | && !(openpgp_pk_algo_usage (pk->pubkey_algo) |
2849 | 0 | & (PUBKEY_USAGE_CERT| PUBKEY_USAGE_SIG|PUBKEY_USAGE_AUTH))) |
2850 | 0 | { |
2851 | | /* A primary key which is really not capable to sign. */ |
2852 | 0 | tty_fprintf (fp, " [INVALID_ALGO]"); |
2853 | 0 | } |
2854 | 0 | else if ((opt.list_options & LIST_SHOW_USAGE)) |
2855 | 0 | { |
2856 | 0 | tty_fprintf (fp, " [%s]", usagestr_from_pk (pk, 0)); |
2857 | 0 | } |
2858 | |
|
2859 | 0 | if (pk->flags.primary && (opt.list_options & LIST_SHOW_OWNERTRUST)) |
2860 | 0 | { |
2861 | 0 | tty_fprintf (fp, " [%s]", get_ownertrust_string (ctrl, pk, 0)); |
2862 | 0 | } |
2863 | |
|
2864 | 0 | if (pk->flags.revoked) |
2865 | 0 | { |
2866 | 0 | tty_fprintf (fp, " ["); |
2867 | 0 | tty_fprintf (fp, _("revoked: %s"), revokestr_from_pk (pk)); |
2868 | 0 | tty_fprintf (fp, "]"); |
2869 | 0 | } |
2870 | 0 | else if (pk->has_expired) |
2871 | 0 | { |
2872 | 0 | tty_fprintf (fp, " ["); |
2873 | 0 | tty_fprintf (fp, _("expired: %s"), expirestr_from_pk (pk)); |
2874 | 0 | tty_fprintf (fp, "]"); |
2875 | 0 | } |
2876 | 0 | else if (pk->expiredate) |
2877 | 0 | { |
2878 | 0 | tty_fprintf (fp, " ["); |
2879 | 0 | tty_fprintf (fp, _("expires: %s"), expirestr_from_pk (pk)); |
2880 | 0 | tty_fprintf (fp, "]"); |
2881 | 0 | } |
2882 | |
|
2883 | 0 | if (pk->pubkey_algo >= 100) |
2884 | 0 | tty_fprintf (fp, " [experimental algorithm %d]", pk->pubkey_algo); |
2885 | |
|
2886 | 0 | tty_fprintf (fp, "\n"); |
2887 | |
|
2888 | 0 | if (pk->flags.primary && pk_is_disabled (pk)) |
2889 | 0 | es_fprintf (es_stdout, " *** %s\n", _("This key has been disabled")); |
2890 | | |
2891 | | /* if the user hasn't explicitly asked for human-readable |
2892 | | fingerprints, show compact fpr of primary key: */ |
2893 | 0 | if (pk->flags.primary && |
2894 | 0 | !opt.fingerprint && !opt.with_fingerprint) |
2895 | 0 | print_fingerprint (ctrl, fp, pk, 20); |
2896 | | |
2897 | | /* Print the revocation reason. */ |
2898 | 0 | if (pk->flags.revoked) |
2899 | 0 | print_revocation_reason (pk); |
2900 | 0 | } |
2901 | | |
2902 | | |
2903 | | void |
2904 | | set_attrib_fd (int fd) |
2905 | 0 | { |
2906 | 0 | static int last_fd = -1; |
2907 | |
|
2908 | 0 | if (fd != -1 && last_fd == fd) |
2909 | 0 | return; |
2910 | | |
2911 | | /* Fixme: Do we need to check for the log stream here? */ |
2912 | 0 | if (attrib_fp && attrib_fp != log_get_stream ()) |
2913 | 0 | es_fclose (attrib_fp); |
2914 | 0 | attrib_fp = NULL; |
2915 | 0 | if (fd == -1) |
2916 | 0 | return; |
2917 | | |
2918 | 0 | if (! gnupg_fd_valid (fd)) |
2919 | 0 | log_fatal ("attribute-fd is invalid: %s\n", strerror (errno)); |
2920 | | |
2921 | | #ifdef HAVE_DOSISH_SYSTEM |
2922 | | setmode (fd, O_BINARY); |
2923 | | #endif |
2924 | 0 | if (fd == 1) |
2925 | 0 | attrib_fp = es_stdout; |
2926 | 0 | else if (fd == 2) |
2927 | 0 | attrib_fp = es_stderr; |
2928 | 0 | else |
2929 | 0 | attrib_fp = es_fdopen (fd, "wb"); |
2930 | 0 | if (!attrib_fp) |
2931 | 0 | { |
2932 | 0 | log_fatal ("can't open fd %d for attribute output: %s\n", |
2933 | 0 | fd, strerror (errno)); |
2934 | 0 | } |
2935 | | |
2936 | 0 | last_fd = fd; |
2937 | 0 | } |