xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/packet-print.c (revision 5c46dd73a9bcb28b2994504ea090f64066b17a77)
1 /*-
2  * Copyright (c) 2009 The NetBSD Foundation, Inc.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to The NetBSD Foundation
6  * by Alistair Crooks (agc@NetBSD.org)
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 /*
30  * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
31  * All rights reserved.
32  * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
33  * their moral rights under the UK Copyright Design and Patents Act 1988 to
34  * be recorded as the authors of this copyright work.
35  *
36  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
37  * use this file except in compliance with the License.
38  *
39  * You may obtain a copy of the License at
40  *     http://www.apache.org/licenses/LICENSE-2.0
41  *
42  * Unless required by applicable law or agreed to in writing, software
43  * distributed under the License is distributed on an "AS IS" BASIS,
44  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
45  *
46  * See the License for the specific language governing permissions and
47  * limitations under the License.
48  */
49 
50 /*
51  * ! \file \brief Standard API print functions
52  */
53 #include "config.h"
54 
55 #ifdef HAVE_SYS_CDEFS_H
56 #include <sys/cdefs.h>
57 #endif
58 
59 #if defined(__NetBSD__)
60 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
61 __RCSID("$NetBSD: packet-print.c,v 1.31 2010/05/25 01:05:11 agc Exp $");
62 #endif
63 
64 #include <string.h>
65 #include <stdio.h>
66 
67 #ifdef HAVE_UNISTD_H
68 #include <unistd.h>
69 #endif
70 
71 #include "crypto.h"
72 #include "keyring.h"
73 #include "packet-show.h"
74 #include "signature.h"
75 #include "readerwriter.h"
76 #include "netpgpdefs.h"
77 #include "netpgpsdk.h"
78 #include "packet.h"
79 #include "netpgpdigest.h"
80 
81 /* static functions */
82 
83 static void
84 print_indent(int indent)
85 {
86 	int             i;
87 
88 	for (i = 0; i < indent; i++) {
89 		printf("  ");
90 	}
91 }
92 
93 static void
94 print_name(int indent, const char *name)
95 {
96 	print_indent(indent);
97 	if (name) {
98 		printf("%s: ", name);
99 	}
100 }
101 
102 static void
103 print_hexdump(int indent, const char *name, const uint8_t *data, unsigned len)
104 {
105 	print_name(indent, name);
106 
107 	printf("len=%u, data=0x", len);
108 	hexdump(stdout, data, len, "");
109 	printf("\n");
110 }
111 
112 static void
113 hexdump_data(int indent, const char *name, const uint8_t *data, unsigned len)
114 {
115 	print_name(indent, name);
116 
117 	printf("0x");
118 	hexdump(stdout, data, len, "");
119 	printf("\n");
120 }
121 
122 static void
123 print_uint(int indent, const char *name, unsigned val)
124 {
125 	print_name(indent, name);
126 	printf("%u\n", val);
127 }
128 
129 static void
130 showtime(const char *name, time_t t)
131 {
132 	printf("%s=%" PRItime "d (%.24s)", name, (long long) t, ctime(&t));
133 }
134 
135 static void
136 print_time(int indent, const char *name, time_t t)
137 {
138 	print_indent(indent);
139 	printf("%s: ", name);
140 	showtime("time", t);
141 	printf("\n");
142 }
143 
144 static void
145 print_string_and_value(int indent, const char *name, const char *str, uint8_t value)
146 {
147 	print_name(indent, name);
148 	printf("%s (0x%x)\n", str, value);
149 }
150 
151 static void
152 print_tagname(int indent, const char *str)
153 {
154 	print_indent(indent);
155 	printf("%s packet\n", str);
156 }
157 
158 static void
159 print_data(int indent, const char *name, const __ops_data_t *data)
160 {
161 	print_hexdump(indent, name, data->contents, data->len);
162 }
163 
164 static void
165 print_bn(int indent, const char *name, const BIGNUM *bn)
166 {
167 	print_indent(indent);
168 	printf("%s=", name);
169 	if (bn) {
170 		BN_print_fp(stdout, bn);
171 		putchar('\n');
172 	} else {
173 		puts("(unset)");
174 	}
175 }
176 
177 static void
178 print_packet_hex(const __ops_subpacket_t *pkt)
179 {
180 	unsigned	rem;
181 	unsigned	blksz = 4;
182 	uint8_t		*cur;
183 	int             i;
184 
185 	printf("\nhexdump of packet contents follows:\n");
186 	for (i = 1, cur = pkt->raw;
187 	     cur < (pkt->raw + pkt->length);
188 	     cur += blksz, i++) {
189 		rem = pkt->raw + pkt->length - cur;
190 		hexdump(stdout, cur, (rem <= blksz) ? rem : blksz, "");
191 		printf(" ");
192 		if (i % 8 == 0) {
193 			printf("\n");
194 		}
195 
196 	}
197 	printf("\n");
198 }
199 
200 static void
201 print_escaped(const uint8_t *data, size_t length)
202 {
203 	while (length-- > 0) {
204 		if ((*data >= 0x20 && *data < 0x7f && *data != '%') ||
205 		    *data == '\n') {
206 			putchar(*data);
207 		} else {
208 			printf("%%%02x", *data);
209 		}
210 		++data;
211 	}
212 }
213 
214 static void
215 print_string(int indent, const char *name, const char *str)
216 {
217 	print_name(indent, name);
218 	print_escaped((const uint8_t *) str, strlen(str));
219 	putchar('\n');
220 }
221 
222 static void
223 print_utf8_string(int indent, const char *name, const uint8_t *str)
224 {
225 	/* \todo Do this better for non-English character sets */
226 	print_string(indent, name, (const char *) str);
227 }
228 
229 static void
230 print_duration(int indent, const char *name, time_t t)
231 {
232 	int             mins, hours, days, years;
233 
234 	print_indent(indent);
235 	printf("%s: ", name);
236 	printf("duration %" PRItime "d seconds", (long long) t);
237 
238 	mins = (int)(t / 60);
239 	hours = mins / 60;
240 	days = hours / 24;
241 	years = days / 365;
242 
243 	printf(" (approx. ");
244 	if (years) {
245 		printf("%d %s", years, years == 1 ? "year" : "years");
246 	} else if (days) {
247 		printf("%d %s", days, days == 1 ? "day" : "days");
248 	} else if (hours) {
249 		printf("%d %s", hours, hours == 1 ? "hour" : "hours");
250 	}
251 	printf(")\n");
252 }
253 
254 static void
255 print_boolean(int indent, const char *name, uint8_t boolval)
256 {
257 	print_name(indent, name);
258 	printf("%s\n", (boolval) ? "Yes" : "No");
259 }
260 
261 static void
262 print_text_breakdown(int indent, __ops_text_t *text)
263 {
264 	const char     *prefix = ".. ";
265 	unsigned        i;
266 
267 	/* these were recognised */
268 	for (i = 0; i < text->known.used; i++) {
269 		print_indent(indent);
270 		printf("%s", prefix);
271 		printf("%s\n", text->known.strings[i]);
272 	}
273 	/*
274 	 * these were not recognised. the strings will contain the hex value
275 	 * of the unrecognised value in string format - see
276 	 * process_octet_str()
277 	 */
278 	if (text->unknown.used) {
279 		printf("\n");
280 		print_indent(indent);
281 		printf("Not Recognised: ");
282 	}
283 	for (i = 0; i < text->unknown.used; i++) {
284 		print_indent(indent);
285 		printf("%s", prefix);
286 		printf("%s\n", text->unknown.strings[i]);
287 	}
288 }
289 
290 static void
291 print_headers(const __ops_headers_t *h)
292 {
293 	unsigned        i;
294 
295 	for (i = 0; i < h->headerc; ++i) {
296 		printf("%s=%s\n", h->headers[i].key, h->headers[i].value);
297 	}
298 }
299 
300 static void
301 print_block(int indent, const char *name, const uint8_t *str, size_t length)
302 {
303 	int             o = length;
304 
305 	print_indent(indent);
306 	printf(">>>>> %s >>>>>\n", name);
307 
308 	print_indent(indent);
309 	for (; length > 0; --length) {
310 		if (*str >= 0x20 && *str < 0x7f && *str != '%') {
311 			putchar(*str);
312 		} else if (*str == '\n') {
313 			putchar(*str);
314 			print_indent(indent);
315 		} else {
316 			printf("%%%02x", *str);
317 		}
318 		++str;
319 	}
320 	if (o && str[-1] != '\n') {
321 		putchar('\n');
322 		print_indent(indent);
323 		fputs("[no newline]", stdout);
324 	} else {
325 		print_indent(indent);
326 	}
327 	printf("<<<<< %s <<<<<\n", name);
328 }
329 
330 /* return the number of bits in the public key */
331 static int
332 numkeybits(const __ops_pubkey_t *pubkey)
333 {
334 	switch(pubkey->alg) {
335 	case OPS_PKA_RSA:
336 	case OPS_PKA_RSA_ENCRYPT_ONLY:
337 	case OPS_PKA_RSA_SIGN_ONLY:
338 		return BN_num_bytes(pubkey->key.rsa.n) * 8;
339 	case OPS_PKA_DSA:
340 		switch(BN_num_bytes(pubkey->key.dsa.q)) {
341 		case 20:
342 			return 1024;
343 		case 28:
344 			return 2048;
345 		case 32:
346 			return 3072;
347 		default:
348 			return 0;
349 		}
350 	case OPS_PKA_ELGAMAL:
351 		return BN_num_bytes(pubkey->key.elgamal.y) * 8;
352 	default:
353 		return -1;
354 	}
355 }
356 
357 /* return the hexdump as a string */
358 static char *
359 strhexdump(char *dest, const uint8_t *src, size_t length, const char *sep)
360 {
361 	unsigned i;
362 	int	n;
363 
364 	for (n = 0, i = 0 ; i < length ; i += 2) {
365 		n += snprintf(&dest[n], 3, "%02x", *src++);
366 		n += snprintf(&dest[n], 10, "%02x%s", *src++, sep);
367 	}
368 	return dest;
369 }
370 
371 /* return the time as a string */
372 static char *
373 ptimestr(char *dest, size_t size, time_t t)
374 {
375 	struct tm      *tm;
376 
377 	tm = gmtime(&t);
378 	(void) snprintf(dest, size, "%04d-%02d-%02d",
379 		tm->tm_year + 1900,
380 		tm->tm_mon + 1,
381 		tm->tm_mday);
382 	return dest;
383 }
384 
385 /* print the sub key binding signature info */
386 static int
387 psubkeybinding(char *buf, size_t size, __ops_subsig_t *subsig, const __ops_pubkey_t *pubkey, char *expired)
388 {
389 	char	keyid[512];
390 	char	t[32];
391 
392 	return snprintf(buf, size, "sub %d/%s %s %s %s\n",
393 		numkeybits(pubkey),
394 		__ops_show_pka(subsig->sig.info.key_alg),
395 		strhexdump(keyid, subsig->sig.info.signer_id, OPS_KEY_ID_SIZE, ""),
396 		ptimestr(t, sizeof(t), subsig->sig.info.birthtime),
397 		expired);
398 }
399 
400 static int
401 isrevoked(const __ops_key_t *key, unsigned uid)
402 {
403 	unsigned	r;
404 
405 	for (r = 0 ; r < key->revokec ; r++) {
406 		if (key->revokes[r].uid == uid) {
407 			return r;
408 		}
409 	}
410 	return -1;
411 }
412 
413 #ifndef KB
414 #define KB(x)	((x) * 1024)
415 #endif
416 
417 /* print into a string (malloc'ed) the pubkeydata */
418 int
419 __ops_sprint_keydata(__ops_io_t *io, const __ops_keyring_t *keyring,
420 		const __ops_key_t *key, char **buf, const char *header,
421 		const __ops_pubkey_t *pubkey, const int psigs)
422 {
423 	const __ops_key_t	*trustkey;
424 	unsigned	 	 from;
425 	unsigned		 i;
426 	unsigned		 j;
427 	time_t			 now;
428 	char			 uidbuf[KB(128)];
429 	char			 keyid[OPS_KEY_ID_SIZE * 3];
430 	char			 fp[(OPS_FINGERPRINT_SIZE * 3) + 1];
431 	char			 expired[128];
432 	char			 t[32];
433 	int			 cc;
434 	int			 n;
435 	int			 r;
436 
437 	if (key->revoked) {
438 		return -1;
439 	}
440 	now = time(NULL);
441 	if (pubkey->duration > 0) {
442 		cc = snprintf(expired, sizeof(expired),
443 			(pubkey->birthtime + pubkey->duration < now) ?
444 			"[EXPIRED " : "[EXPIRES ");
445 		ptimestr(&expired[cc], sizeof(expired) - cc,
446 			pubkey->birthtime + pubkey->duration);
447 		cc += 10;
448 		cc += snprintf(&expired[cc], sizeof(expired) - cc, "]");
449 	} else {
450 		expired[0] = 0x0;
451 	}
452 	for (i = 0, n = 0; i < key->uidc; i++) {
453 		if ((r = isrevoked(key, i)) >= 0 &&
454 		    key->revokes[r].code == OPS_REVOCATION_COMPROMISED) {
455 			continue;
456 		}
457 		n += snprintf(&uidbuf[n], sizeof(uidbuf) - n, "uid%s%s%s\n",
458 				(psigs) ? "    " : "              ",
459 				key->uids[i],
460 				(isrevoked(key, i) >= 0) ? " [REVOKED]" : "");
461 		for (j = 0 ; j < key->subsigc ; j++) {
462 			if (psigs) {
463 				if (key->subsigs[j].uid != i) {
464 					continue;
465 				}
466 			} else {
467 				if (!(key->subsigs[j].sig.info.version == 4 &&
468 					key->subsigs[j].sig.info.type == OPS_SIG_SUBKEY &&
469 					i == key->uidc - 1)) {
470 						continue;
471 				}
472 			}
473 			from = 0;
474 			trustkey = __ops_getkeybyid(io, keyring, key->subsigs[j].sig.info.signer_id, &from);
475 			if (key->subsigs[j].sig.info.version == 4 &&
476 					key->subsigs[j].sig.info.type == OPS_SIG_SUBKEY) {
477 				psubkeybinding(&uidbuf[n], sizeof(uidbuf) - n, &key->subsigs[j], pubkey, expired);
478 			} else {
479 				n += snprintf(&uidbuf[n], sizeof(uidbuf) - n,
480 					"sig        %s  %s  %s\n",
481 					strhexdump(keyid, key->subsigs[j].sig.info.signer_id, OPS_KEY_ID_SIZE, ""),
482 					ptimestr(t, sizeof(t), key->subsigs[j].sig.info.birthtime),
483 					(trustkey) ? (char *)trustkey->uids[trustkey->uid0] : "[unknown]");
484 			}
485 		}
486 	}
487 	return __ops_asprintf(buf, "%s %d/%s %s %s %s\nKey fingerprint: %s\n%s",
488 		header,
489 		numkeybits(pubkey),
490 		__ops_show_pka(pubkey->alg),
491 		strhexdump(keyid, key->key_id, OPS_KEY_ID_SIZE, ""),
492 		ptimestr(t, sizeof(t), pubkey->birthtime),
493 		expired,
494 		strhexdump(fp, key->fingerprint.fingerprint, OPS_FINGERPRINT_SIZE, " "),
495 		uidbuf);
496 }
497 
498 int
499 __ops_hkp_sprint_keydata(__ops_io_t *io, const __ops_keyring_t *keyring,
500 		const __ops_key_t *key, char **buf,
501 		const __ops_pubkey_t *pubkey, const int psigs)
502 {
503 	const __ops_key_t	*trustkey;
504 	unsigned	 	 from;
505 	unsigned	 	 i;
506 	unsigned	 	 j;
507 	char			 keyid[OPS_KEY_ID_SIZE * 3];
508 	char		 	 uidbuf[KB(128)];
509 	char		 	 fp[(OPS_FINGERPRINT_SIZE * 3) + 1];
510 	int		 	 n;
511 
512 	if (key->revoked) {
513 		return -1;
514 	}
515 	for (i = 0, n = 0; i < key->uidc; i++) {
516 		n += snprintf(&uidbuf[n], sizeof(uidbuf) - n,
517 			"uid:%lld:%lld:%s\n",
518 			(long long)pubkey->birthtime,
519 			(long long)pubkey->duration,
520 			key->uids[i]);
521 		for (j = 0 ; j < key->subsigc ; j++) {
522 			if (psigs) {
523 				if (key->subsigs[j].uid != i) {
524 					continue;
525 				}
526 			} else {
527 				if (!(key->subsigs[j].sig.info.version == 4 &&
528 					key->subsigs[j].sig.info.type == OPS_SIG_SUBKEY &&
529 					i == key->uidc - 1)) {
530 						continue;
531 				}
532 			}
533 			from = 0;
534 			trustkey = __ops_getkeybyid(io, keyring, key->subsigs[j].sig.info.signer_id, &from);
535 			if (key->subsigs[j].sig.info.version == 4 &&
536 					key->subsigs[j].sig.info.type == OPS_SIG_SUBKEY) {
537 				n += snprintf(&uidbuf[n], sizeof(uidbuf) - n, "sub:%d:%d:%s:%lld:%lld\n",
538 					numkeybits(pubkey),
539 					key->subsigs[j].sig.info.key_alg,
540 					strhexdump(keyid, key->subsigs[j].sig.info.signer_id, OPS_KEY_ID_SIZE, ""),
541 					(long long)(key->subsigs[j].sig.info.birthtime),
542 					(long long)pubkey->duration);
543 			} else {
544 				n += snprintf(&uidbuf[n], sizeof(uidbuf) - n,
545 					"sig:%s:%lld:%s\n",
546 					strhexdump(keyid, key->subsigs[j].sig.info.signer_id, OPS_KEY_ID_SIZE, ""),
547 					(long long)key->subsigs[j].sig.info.birthtime,
548 					(trustkey) ? (char *)trustkey->uids[trustkey->uid0] : "");
549 			}
550 		}
551 	}
552 	return __ops_asprintf(buf, "pub:%s:%d:%d:%lld:%lld\n%s",
553 		strhexdump(fp, key->fingerprint.fingerprint, OPS_FINGERPRINT_SIZE, ""),
554 		pubkey->alg,
555 		numkeybits(pubkey),
556 		(long long)pubkey->birthtime,
557 		(long long)pubkey->duration,
558 		uidbuf);
559 }
560 
561 /* print the key data for a pub or sec key */
562 void
563 __ops_print_keydata(__ops_io_t *io, const __ops_keyring_t *keyring,
564 		const __ops_key_t *key, const char *header,
565 		const __ops_pubkey_t *pubkey, const int psigs)
566 {
567 	char	*cp;
568 
569 	if (__ops_sprint_keydata(io, keyring, key, &cp, header, pubkey, psigs) >= 0) {
570 		(void) fprintf(io->res, "%s", cp);
571 		free(cp);
572 	}
573 }
574 
575 /**
576 \ingroup Core_Print
577 \param pubkey
578 */
579 void
580 __ops_print_pubkey(const __ops_pubkey_t *pubkey)
581 {
582 	printf("------- PUBLIC KEY ------\n");
583 	print_uint(0, "Version", (unsigned)pubkey->version);
584 	print_time(0, "Creation Time", pubkey->birthtime);
585 	if (pubkey->version == OPS_V3) {
586 		print_uint(0, "Days Valid", pubkey->days_valid);
587 	}
588 	print_string_and_value(0, "Algorithm", __ops_show_pka(pubkey->alg),
589 			       pubkey->alg);
590 	switch (pubkey->alg) {
591 	case OPS_PKA_DSA:
592 		print_bn(0, "p", pubkey->key.dsa.p);
593 		print_bn(0, "q", pubkey->key.dsa.q);
594 		print_bn(0, "g", pubkey->key.dsa.g);
595 		print_bn(0, "y", pubkey->key.dsa.y);
596 		break;
597 
598 	case OPS_PKA_RSA:
599 	case OPS_PKA_RSA_ENCRYPT_ONLY:
600 	case OPS_PKA_RSA_SIGN_ONLY:
601 		print_bn(0, "n", pubkey->key.rsa.n);
602 		print_bn(0, "e", pubkey->key.rsa.e);
603 		break;
604 
605 	case OPS_PKA_ELGAMAL:
606 	case OPS_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
607 		print_bn(0, "p", pubkey->key.elgamal.p);
608 		print_bn(0, "g", pubkey->key.elgamal.g);
609 		print_bn(0, "y", pubkey->key.elgamal.y);
610 		break;
611 
612 	default:
613 		(void) fprintf(stderr,
614 			"__ops_print_pubkey: Unusual algorithm\n");
615 	}
616 
617 	printf("------- end of PUBLIC KEY ------\n");
618 }
619 
620 int
621 __ops_sprint_pubkey(const __ops_key_t *key, char *out, size_t outsize)
622 {
623 	char	fp[(OPS_FINGERPRINT_SIZE * 3) + 1];
624 	int	cc;
625 
626 	cc = snprintf(out, outsize, "key:%s:%d:%lld:%lld:%d:\n",
627 		strhexdump(fp, key->fingerprint.fingerprint, OPS_FINGERPRINT_SIZE, ""),
628 		key->key.pubkey.version,
629 		(long long)key->key.pubkey.birthtime,
630 		(long long)key->key.pubkey.days_valid,
631 		key->key.pubkey.alg);
632 	switch (key->key.pubkey.alg) {
633 	case OPS_PKA_DSA:
634 		cc += snprintf(&out[cc], outsize - cc,
635 			"pubkey:p=%s:q=%s:g=%s:y=%s\n",
636 			BN_bn2hex(key->key.pubkey.key.dsa.p),
637 			BN_bn2hex(key->key.pubkey.key.dsa.q),
638 			BN_bn2hex(key->key.pubkey.key.dsa.g),
639 			BN_bn2hex(key->key.pubkey.key.dsa.y));
640 		break;
641 	case OPS_PKA_RSA:
642 	case OPS_PKA_RSA_ENCRYPT_ONLY:
643 	case OPS_PKA_RSA_SIGN_ONLY:
644 		cc += snprintf(&out[cc], outsize - cc,
645 			"pubkey:n=%s:e=%s\n",
646 			BN_bn2hex(key->key.pubkey.key.rsa.n),
647 			BN_bn2hex(key->key.pubkey.key.rsa.e));
648 		break;
649 	case OPS_PKA_ELGAMAL:
650 	case OPS_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
651 		cc += snprintf(&out[cc], outsize - cc,
652 			"pubkey:p=%s:g=%s:y=%s\n",
653 			BN_bn2hex(key->key.pubkey.key.elgamal.p),
654 			BN_bn2hex(key->key.pubkey.key.elgamal.g),
655 			BN_bn2hex(key->key.pubkey.key.elgamal.y));
656 		break;
657 	default:
658 		(void) fprintf(stderr,
659 			"__ops_print_pubkey: Unusual algorithm\n");
660 	}
661 	return cc;
662 }
663 
664 /**
665 \ingroup Core_Print
666 \param type
667 \param seckey
668 */
669 static void
670 __ops_print_seckey_verbose(const __ops_content_enum type,
671 				const __ops_seckey_t *seckey)
672 {
673 	printf("------- SECRET KEY or ENCRYPTED SECRET KEY ------\n");
674 	print_tagname(0, (type == OPS_PTAG_CT_SECRET_KEY) ?
675 			"SECRET_KEY" :
676 			"ENCRYPTED_SECRET_KEY");
677 	/* __ops_print_pubkey(key); */
678 	printf("S2K Usage: %d\n", seckey->s2k_usage);
679 	if (seckey->s2k_usage != OPS_S2KU_NONE) {
680 		printf("S2K Specifier: %d\n", seckey->s2k_specifier);
681 		printf("Symmetric algorithm: %d (%s)\n", seckey->alg,
682 		       __ops_show_symm_alg(seckey->alg));
683 		printf("Hash algorithm: %d (%s)\n", seckey->hash_alg,
684 		       __ops_show_hash_alg((uint8_t)seckey->hash_alg));
685 		if (seckey->s2k_specifier != OPS_S2KS_SIMPLE) {
686 			print_hexdump(0, "Salt", seckey->salt,
687 					sizeof(seckey->salt));
688 		}
689 		if (seckey->s2k_specifier == OPS_S2KS_ITERATED_AND_SALTED) {
690 			printf("Octet count: %u\n", seckey->octetc);
691 		}
692 		print_hexdump(0, "IV", seckey->iv, __ops_block_size(seckey->alg));
693 	}
694 	/* no more set if encrypted */
695 	if (type == OPS_PTAG_CT_ENCRYPTED_SECRET_KEY) {
696 		return;
697 	}
698 	switch (seckey->pubkey.alg) {
699 	case OPS_PKA_RSA:
700 		print_bn(0, "d", seckey->key.rsa.d);
701 		print_bn(0, "p", seckey->key.rsa.p);
702 		print_bn(0, "q", seckey->key.rsa.q);
703 		print_bn(0, "u", seckey->key.rsa.u);
704 		break;
705 
706 	case OPS_PKA_DSA:
707 		print_bn(0, "x", seckey->key.dsa.x);
708 		break;
709 
710 	default:
711 		(void) fprintf(stderr,
712 			"__ops_print_seckey_verbose: unusual algorithm\n");
713 	}
714 	if (seckey->s2k_usage == OPS_S2KU_ENCRYPTED_AND_HASHED) {
715 		print_hexdump(0, "Checkhash", seckey->checkhash,
716 				OPS_CHECKHASH_SIZE);
717 	} else {
718 		printf("Checksum: %04x\n", seckey->checksum);
719 	}
720 	printf("------- end of SECRET KEY or ENCRYPTED SECRET KEY ------\n");
721 }
722 
723 
724 /**
725 \ingroup Core_Print
726 \param tag
727 \param key
728 */
729 static void
730 __ops_print_pk_sesskey(__ops_content_enum tag,
731 			 const __ops_pk_sesskey_t * key)
732 {
733 	print_tagname(0, (tag == OPS_PTAG_CT_PK_SESSION_KEY) ?
734 		"PUBLIC KEY SESSION KEY" :
735 		"ENCRYPTED PUBLIC KEY SESSION KEY");
736 	printf("Version: %d\n", key->version);
737 	print_hexdump(0, "Key ID", key->key_id, sizeof(key->key_id));
738 	printf("Algorithm: %d (%s)\n", key->alg,
739 	       __ops_show_pka(key->alg));
740 	switch (key->alg) {
741 	case OPS_PKA_RSA:
742 		print_bn(0, "encrypted_m", key->params.rsa.encrypted_m);
743 		break;
744 
745 	case OPS_PKA_ELGAMAL:
746 		print_bn(0, "g_to_k", key->params.elgamal.g_to_k);
747 		print_bn(0, "encrypted_m", key->params.elgamal.encrypted_m);
748 		break;
749 
750 	default:
751 		(void) fprintf(stderr,
752 			"__ops_print_pk_sesskey: unusual algorithm\n");
753 	}
754 	if (tag == OPS_PTAG_CT_PK_SESSION_KEY) {
755 		printf("Symmetric algorithm: %d (%s)\n", key->symm_alg,
756 		       __ops_show_symm_alg(key->symm_alg));
757 		print_hexdump(0, "Key", key->key, __ops_key_size(key->symm_alg));
758 		printf("Checksum: %04x\n", key->checksum);
759 	}
760 }
761 
762 static void
763 start_subpacket(int *indent, int type)
764 {
765 	*indent += 1;
766 	print_indent(*indent);
767 	printf("-- %s (type 0x%02x)\n",
768 	       __ops_show_ss_type((__ops_content_enum)type),
769 	       type - OPS_PTAG_SIG_SUBPKT_BASE);
770 }
771 
772 static void
773 end_subpacket(int *indent)
774 {
775 	*indent -= 1;
776 }
777 
778 /**
779 \ingroup Core_Print
780 \param contents
781 */
782 int
783 __ops_print_packet(__ops_printstate_t *print, const __ops_packet_t *pkt)
784 {
785 	const __ops_contents_t	*content = &pkt->u;
786 	__ops_text_t		*text;
787 	const char		*str;
788 
789 	if (print->unarmoured && pkt->tag != OPS_PTAG_CT_UNARMOURED_TEXT) {
790 		print->unarmoured = 0;
791 		puts("UNARMOURED TEXT ends");
792 	}
793 	if (pkt->tag == OPS_PARSER_PTAG) {
794 		printf("=> OPS_PARSER_PTAG: %s\n",
795 			__ops_show_packet_tag((__ops_content_enum)content->ptag.type));
796 	} else {
797 		printf("=> %s\n", __ops_show_packet_tag(pkt->tag));
798 	}
799 
800 	switch (pkt->tag) {
801 	case OPS_PARSER_ERROR:
802 		printf("parse error: %s\n", content->error);
803 		break;
804 
805 	case OPS_PARSER_ERRCODE:
806 		printf("parse error: %s\n",
807 		       __ops_errcode(content->errcode.errcode));
808 		break;
809 
810 	case OPS_PARSER_PACKET_END:
811 		print_packet_hex(&content->packet);
812 		break;
813 
814 	case OPS_PARSER_PTAG:
815 		if (content->ptag.type == OPS_PTAG_CT_PUBLIC_KEY) {
816 			print->indent = 0;
817 			printf("\n*** NEXT KEY ***\n");
818 		}
819 		printf("\n");
820 		print_indent(print->indent);
821 		printf("==== ptag new_format=%u type=%u length_type=%d"
822 		       " length=0x%x (%u) position=0x%x (%u)\n",
823 		       content->ptag.new_format,
824 		       content->ptag.type, content->ptag.length_type,
825 		       content->ptag.length, content->ptag.length,
826 		       content->ptag.position, content->ptag.position);
827 		print_tagname(print->indent, __ops_show_packet_tag((__ops_content_enum)content->ptag.type));
828 		break;
829 
830 	case OPS_PTAG_CT_SE_DATA_HEADER:
831 		print_tagname(print->indent, "SYMMETRIC ENCRYPTED DATA");
832 		break;
833 
834 	case OPS_PTAG_CT_SE_IP_DATA_HEADER:
835 		print_tagname(print->indent,
836 			"SYMMETRIC ENCRYPTED INTEGRITY PROTECTED DATA HEADER");
837 		printf("Version: %d\n", content->se_ip_data_header);
838 		break;
839 
840 	case OPS_PTAG_CT_SE_IP_DATA_BODY:
841 		print_tagname(print->indent,
842 			"SYMMETRIC ENCRYPTED INTEGRITY PROTECTED DATA BODY");
843 		printf("  data body length=%u\n",
844 		       content->se_data_body.length);
845 		printf("    data=");
846 		hexdump(stdout, content->se_data_body.data,
847 			content->se_data_body.length, "");
848 		printf("\n");
849 		break;
850 
851 	case OPS_PTAG_CT_PUBLIC_KEY:
852 	case OPS_PTAG_CT_PUBLIC_SUBKEY:
853 		print_tagname(print->indent, (pkt->tag == OPS_PTAG_CT_PUBLIC_KEY) ?
854 			"PUBLIC KEY" :
855 			"PUBLIC SUBKEY");
856 		__ops_print_pubkey(&content->pubkey);
857 		break;
858 
859 	case OPS_PTAG_CT_TRUST:
860 		print_tagname(print->indent, "TRUST");
861 		print_data(print->indent, "Trust", &content->trust);
862 		break;
863 
864 	case OPS_PTAG_CT_USER_ID:
865 		print_tagname(print->indent, "USER ID");
866 		print_utf8_string(print->indent, "userid", content->userid);
867 		break;
868 
869 	case OPS_PTAG_CT_SIGNATURE:
870 		print_tagname(print->indent, "SIGNATURE");
871 		print_indent(print->indent);
872 		print_uint(print->indent, "Signature Version",
873 				   (unsigned)content->sig.info.version);
874 		if (content->sig.info.birthtime_set) {
875 			print_time(print->indent, "Signature Creation Time",
876 				   content->sig.info.birthtime);
877 		}
878 		if (content->sig.info.duration_set) {
879 			print_uint(print->indent, "Signature Duration",
880 				   (unsigned)content->sig.info.duration);
881 		}
882 
883 		print_string_and_value(print->indent, "Signature Type",
884 			    __ops_show_sig_type(content->sig.info.type),
885 				       content->sig.info.type);
886 
887 		if (content->sig.info.signer_id_set) {
888 			hexdump_data(print->indent, "Signer ID",
889 					   content->sig.info.signer_id,
890 				  sizeof(content->sig.info.signer_id));
891 		}
892 
893 		print_string_and_value(print->indent, "Public Key Algorithm",
894 			__ops_show_pka(content->sig.info.key_alg),
895 				     content->sig.info.key_alg);
896 		print_string_and_value(print->indent, "Hash Algorithm",
897 			__ops_show_hash_alg((uint8_t)
898 				content->sig.info.hash_alg),
899 			(uint8_t)content->sig.info.hash_alg);
900 		print_uint(print->indent, "Hashed data len",
901 			content->sig.info.v4_hashlen);
902 		print_indent(print->indent);
903 		hexdump_data(print->indent, "hash2", &content->sig.hash2[0], 2);
904 		switch (content->sig.info.key_alg) {
905 		case OPS_PKA_RSA:
906 		case OPS_PKA_RSA_SIGN_ONLY:
907 			print_bn(print->indent, "sig", content->sig.info.sig.rsa.sig);
908 			break;
909 
910 		case OPS_PKA_DSA:
911 			print_bn(print->indent, "r", content->sig.info.sig.dsa.r);
912 			print_bn(print->indent, "s", content->sig.info.sig.dsa.s);
913 			break;
914 
915 		case OPS_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
916 			print_bn(print->indent, "r", content->sig.info.sig.elgamal.r);
917 			print_bn(print->indent, "s", content->sig.info.sig.elgamal.s);
918 			break;
919 
920 		default:
921 			(void) fprintf(stderr,
922 				"__ops_print_packet: Unusual algorithm\n");
923 			return 0;
924 		}
925 
926 		if (content->sig.hash)
927 			printf("data hash is set\n");
928 
929 		break;
930 
931 	case OPS_PTAG_CT_COMPRESSED:
932 		print_tagname(print->indent, "COMPRESSED");
933 		print_uint(print->indent, "Compressed Data Type",
934 			(unsigned)content->compressed);
935 		break;
936 
937 	case OPS_PTAG_CT_1_PASS_SIG:
938 		print_tagname(print->indent, "ONE PASS SIGNATURE");
939 
940 		print_uint(print->indent, "Version", (unsigned)content->one_pass_sig.version);
941 		print_string_and_value(print->indent, "Signature Type",
942 		    __ops_show_sig_type(content->one_pass_sig.sig_type),
943 				       content->one_pass_sig.sig_type);
944 		print_string_and_value(print->indent, "Hash Algorithm",
945 			__ops_show_hash_alg((uint8_t)content->one_pass_sig.hash_alg),
946 			(uint8_t)content->one_pass_sig.hash_alg);
947 		print_string_and_value(print->indent, "Public Key Algorithm",
948 			__ops_show_pka(content->one_pass_sig.key_alg),
949 			content->one_pass_sig.key_alg);
950 		hexdump_data(print->indent, "Signer ID",
951 				   content->one_pass_sig.keyid,
952 				   sizeof(content->one_pass_sig.keyid));
953 		print_uint(print->indent, "Nested", content->one_pass_sig.nested);
954 		break;
955 
956 	case OPS_PTAG_CT_USER_ATTR:
957 		print_tagname(print->indent, "USER ATTRIBUTE");
958 		print_hexdump(print->indent, "User Attribute",
959 			      content->userattr.contents,
960 			      content->userattr.len);
961 		break;
962 
963 	case OPS_PTAG_RAW_SS:
964 		if (pkt->critical) {
965 			(void) fprintf(stderr, "contents are critical\n");
966 			return 0;
967 		}
968 		start_subpacket(&print->indent, pkt->tag);
969 		print_uint(print->indent, "Raw Signature Subpacket: tag",
970 			(unsigned)(content->ss_raw.tag -
971 		   	(unsigned)OPS_PTAG_SIG_SUBPKT_BASE));
972 		print_hexdump(print->indent, "Raw Data",
973 			      content->ss_raw.raw,
974 			      content->ss_raw.length);
975 		break;
976 
977 	case OPS_PTAG_SS_CREATION_TIME:
978 		start_subpacket(&print->indent, pkt->tag);
979 		print_time(print->indent, "Signature Creation Time", content->ss_time);
980 		end_subpacket(&print->indent);
981 		break;
982 
983 	case OPS_PTAG_SS_EXPIRATION_TIME:
984 		start_subpacket(&print->indent, pkt->tag);
985 		print_duration(print->indent, "Signature Expiration Time",
986 			content->ss_time);
987 		end_subpacket(&print->indent);
988 		break;
989 
990 	case OPS_PTAG_SS_KEY_EXPIRY:
991 		start_subpacket(&print->indent, pkt->tag);
992 		print_duration(print->indent, "Key Expiration Time", content->ss_time);
993 		end_subpacket(&print->indent);
994 		break;
995 
996 	case OPS_PTAG_SS_TRUST:
997 		start_subpacket(&print->indent, pkt->tag);
998 		print_string(print->indent, "Trust Signature", "");
999 		print_uint(print->indent, "Level", (unsigned)content->ss_trust.level);
1000 		print_uint(print->indent, "Amount", (unsigned)content->ss_trust.amount);
1001 		end_subpacket(&print->indent);
1002 		break;
1003 
1004 	case OPS_PTAG_SS_REVOCABLE:
1005 		start_subpacket(&print->indent, pkt->tag);
1006 		print_boolean(print->indent, "Revocable", content->ss_revocable);
1007 		end_subpacket(&print->indent);
1008 		break;
1009 
1010 	case OPS_PTAG_SS_REVOCATION_KEY:
1011 		start_subpacket(&print->indent, pkt->tag);
1012 		/* not yet tested */
1013 		printf("  revocation key: class=0x%x",
1014 		       content->ss_revocation_key.class);
1015 		if (content->ss_revocation_key.class & 0x40) {
1016 			printf(" (sensitive)");
1017 		}
1018 		printf(", algid=0x%x", content->ss_revocation_key.algid);
1019 		printf(", fingerprint=");
1020 		hexdump(stdout, content->ss_revocation_key.fingerprint,
1021 				OPS_FINGERPRINT_SIZE, "");
1022 		printf("\n");
1023 		end_subpacket(&print->indent);
1024 		break;
1025 
1026 	case OPS_PTAG_SS_ISSUER_KEY_ID:
1027 		start_subpacket(&print->indent, pkt->tag);
1028 		print_hexdump(print->indent, "Issuer Key Id",
1029 			      content->ss_issuer, sizeof(content->ss_issuer));
1030 		end_subpacket(&print->indent);
1031 		break;
1032 
1033 	case OPS_PTAG_SS_PREFERRED_SKA:
1034 		start_subpacket(&print->indent, pkt->tag);
1035 		print_data(print->indent, "Preferred Symmetric Algorithms",
1036 			   &content->ss_skapref);
1037 		text = __ops_showall_ss_skapref(&content->ss_skapref);
1038 		print_text_breakdown(print->indent, text);
1039 		__ops_text_free(text);
1040 
1041 		end_subpacket(&print->indent);
1042 		break;
1043 
1044 	case OPS_PTAG_SS_PRIMARY_USER_ID:
1045 		start_subpacket(&print->indent, pkt->tag);
1046 		print_boolean(print->indent, "Primary User ID",
1047 			      content->ss_primary_userid);
1048 		end_subpacket(&print->indent);
1049 		break;
1050 
1051 	case OPS_PTAG_SS_PREFERRED_HASH:
1052 		start_subpacket(&print->indent, pkt->tag);
1053 		print_data(print->indent, "Preferred Hash Algorithms",
1054 			   &content->ss_hashpref);
1055 		text = __ops_showall_ss_hashpref(&content->ss_hashpref);
1056 		print_text_breakdown(print->indent, text);
1057 		__ops_text_free(text);
1058 		end_subpacket(&print->indent);
1059 		break;
1060 
1061 	case OPS_PTAG_SS_PREF_COMPRESS:
1062 		start_subpacket(&print->indent, pkt->tag);
1063 		print_data(print->indent, "Preferred Compression Algorithms",
1064 			   &content->ss_zpref);
1065 		text = __ops_showall_ss_zpref(&content->ss_zpref);
1066 		print_text_breakdown(print->indent, text);
1067 		__ops_text_free(text);
1068 		end_subpacket(&print->indent);
1069 		break;
1070 
1071 	case OPS_PTAG_SS_KEY_FLAGS:
1072 		start_subpacket(&print->indent, pkt->tag);
1073 		print_data(print->indent, "Key Flags", &content->ss_key_flags);
1074 
1075 		text = __ops_showall_ss_key_flags(&content->ss_key_flags);
1076 		print_text_breakdown(print->indent, text);
1077 		__ops_text_free(text);
1078 
1079 		end_subpacket(&print->indent);
1080 		break;
1081 
1082 	case OPS_PTAG_SS_KEYSERV_PREFS:
1083 		start_subpacket(&print->indent, pkt->tag);
1084 		print_data(print->indent, "Key Server Preferences",
1085 			   &content->ss_key_server_prefs);
1086 		text = __ops_show_keyserv_prefs(&content->ss_key_server_prefs);
1087 		print_text_breakdown(print->indent, text);
1088 		__ops_text_free(text);
1089 
1090 		end_subpacket(&print->indent);
1091 		break;
1092 
1093 	case OPS_PTAG_SS_FEATURES:
1094 		start_subpacket(&print->indent, pkt->tag);
1095 		print_data(print->indent, "Features", &content->ss_features);
1096 		text = __ops_showall_ss_features(content->ss_features);
1097 		print_text_breakdown(print->indent, text);
1098 		__ops_text_free(text);
1099 
1100 		end_subpacket(&print->indent);
1101 		break;
1102 
1103 	case OPS_PTAG_SS_NOTATION_DATA:
1104 		start_subpacket(&print->indent, pkt->tag);
1105 		print_indent(print->indent);
1106 		printf("Notation Data:\n");
1107 
1108 		print->indent++;
1109 		print_data(print->indent, "Flags", &content->ss_notation.flags);
1110 		text = __ops_showall_notation(content->ss_notation);
1111 		print_text_breakdown(print->indent, text);
1112 		__ops_text_free(text);
1113 
1114 		print_data(print->indent, "Name", &content->ss_notation.name);
1115 
1116 		print_data(print->indent, "Value", &content->ss_notation.value);
1117 
1118 		print->indent--;
1119 		end_subpacket(&print->indent);
1120 		break;
1121 
1122 	case OPS_PTAG_SS_REGEXP:
1123 		start_subpacket(&print->indent, pkt->tag);
1124 		print_hexdump(print->indent, "Regular Expression",
1125 			      (uint8_t *) content->ss_regexp,
1126 			      strlen(content->ss_regexp));
1127 		print_string(print->indent, NULL, content->ss_regexp);
1128 		end_subpacket(&print->indent);
1129 		break;
1130 
1131 	case OPS_PTAG_SS_POLICY_URI:
1132 		start_subpacket(&print->indent, pkt->tag);
1133 		print_string(print->indent, "Policy URL", content->ss_policy);
1134 		end_subpacket(&print->indent);
1135 		break;
1136 
1137 	case OPS_PTAG_SS_SIGNERS_USER_ID:
1138 		start_subpacket(&print->indent, pkt->tag);
1139 		print_utf8_string(print->indent, "Signer's User ID", content->ss_signer);
1140 		end_subpacket(&print->indent);
1141 		break;
1142 
1143 	case OPS_PTAG_SS_PREF_KEYSERV:
1144 		start_subpacket(&print->indent, pkt->tag);
1145 		print_string(print->indent, "Preferred Key Server", content->ss_keyserv);
1146 		end_subpacket(&print->indent);
1147 		break;
1148 
1149 	case OPS_PTAG_SS_EMBEDDED_SIGNATURE:
1150 		start_subpacket(&print->indent, pkt->tag);
1151 		end_subpacket(&print->indent);/* \todo print out contents? */
1152 		break;
1153 
1154 	case OPS_PTAG_SS_USERDEFINED00:
1155 	case OPS_PTAG_SS_USERDEFINED01:
1156 	case OPS_PTAG_SS_USERDEFINED02:
1157 	case OPS_PTAG_SS_USERDEFINED03:
1158 	case OPS_PTAG_SS_USERDEFINED04:
1159 	case OPS_PTAG_SS_USERDEFINED05:
1160 	case OPS_PTAG_SS_USERDEFINED06:
1161 	case OPS_PTAG_SS_USERDEFINED07:
1162 	case OPS_PTAG_SS_USERDEFINED08:
1163 	case OPS_PTAG_SS_USERDEFINED09:
1164 	case OPS_PTAG_SS_USERDEFINED10:
1165 		start_subpacket(&print->indent, pkt->tag);
1166 		print_hexdump(print->indent, "Internal or user-defined",
1167 			      content->ss_userdef.contents,
1168 			      content->ss_userdef.len);
1169 		end_subpacket(&print->indent);
1170 		break;
1171 
1172 	case OPS_PTAG_SS_RESERVED:
1173 		start_subpacket(&print->indent, pkt->tag);
1174 		print_hexdump(print->indent, "Reserved",
1175 			      content->ss_userdef.contents,
1176 			      content->ss_userdef.len);
1177 		end_subpacket(&print->indent);
1178 		break;
1179 
1180 	case OPS_PTAG_SS_REVOCATION_REASON:
1181 		start_subpacket(&print->indent, pkt->tag);
1182 		print_hexdump(print->indent, "Revocation Reason",
1183 			      &content->ss_revocation.code,
1184 			      1);
1185 		str = __ops_show_ss_rr_code(content->ss_revocation.code);
1186 		print_string(print->indent, NULL, str);
1187 		end_subpacket(&print->indent);
1188 		break;
1189 
1190 	case OPS_PTAG_CT_LITDATA_HEADER:
1191 		print_tagname(print->indent, "LITERAL DATA HEADER");
1192 		printf("  literal data header format=%c filename='%s'\n",
1193 		       content->litdata_header.format,
1194 		       content->litdata_header.filename);
1195 		showtime("    modification time",
1196 			 content->litdata_header.mtime);
1197 		printf("\n");
1198 		break;
1199 
1200 	case OPS_PTAG_CT_LITDATA_BODY:
1201 		print_tagname(print->indent, "LITERAL DATA BODY");
1202 		printf("  literal data body length=%u\n",
1203 		       content->litdata_body.length);
1204 		printf("    data=");
1205 		print_escaped(content->litdata_body.data,
1206 			      content->litdata_body.length);
1207 		printf("\n");
1208 		break;
1209 
1210 	case OPS_PTAG_CT_SIGNATURE_HEADER:
1211 		print_tagname(print->indent, "SIGNATURE");
1212 		print_indent(print->indent);
1213 		print_uint(print->indent, "Signature Version",
1214 				   (unsigned)content->sig.info.version);
1215 		if (content->sig.info.birthtime_set) {
1216 			print_time(print->indent, "Signature Creation Time",
1217 				content->sig.info.birthtime);
1218 		}
1219 		if (content->sig.info.duration_set) {
1220 			print_uint(print->indent, "Signature Duration",
1221 				   (unsigned)content->sig.info.duration);
1222 		}
1223 		print_string_and_value(print->indent, "Signature Type",
1224 			    __ops_show_sig_type(content->sig.info.type),
1225 				       content->sig.info.type);
1226 		if (content->sig.info.signer_id_set) {
1227 			hexdump_data(print->indent, "Signer ID",
1228 				content->sig.info.signer_id,
1229 				sizeof(content->sig.info.signer_id));
1230 		}
1231 		print_string_and_value(print->indent, "Public Key Algorithm",
1232 			__ops_show_pka(content->sig.info.key_alg),
1233 				     content->sig.info.key_alg);
1234 		print_string_and_value(print->indent, "Hash Algorithm",
1235 			__ops_show_hash_alg((uint8_t)content->sig.info.hash_alg),
1236 			(uint8_t)content->sig.info.hash_alg);
1237 		print_uint(print->indent, "Hashed data len",
1238 			content->sig.info.v4_hashlen);
1239 
1240 		break;
1241 
1242 	case OPS_PTAG_CT_SIGNATURE_FOOTER:
1243 		print_indent(print->indent);
1244 		hexdump_data(print->indent, "hash2", &content->sig.hash2[0], 2);
1245 
1246 		switch (content->sig.info.key_alg) {
1247 		case OPS_PKA_RSA:
1248 			print_bn(print->indent, "sig", content->sig.info.sig.rsa.sig);
1249 			break;
1250 
1251 		case OPS_PKA_DSA:
1252 			print_bn(print->indent, "r", content->sig.info.sig.dsa.r);
1253 			print_bn(print->indent, "s", content->sig.info.sig.dsa.s);
1254 			break;
1255 
1256 		case OPS_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
1257 			print_bn(print->indent, "r", content->sig.info.sig.elgamal.r);
1258 			print_bn(print->indent, "s", content->sig.info.sig.elgamal.s);
1259 			break;
1260 
1261 		case OPS_PKA_PRIVATE00:
1262 		case OPS_PKA_PRIVATE01:
1263 		case OPS_PKA_PRIVATE02:
1264 		case OPS_PKA_PRIVATE03:
1265 		case OPS_PKA_PRIVATE04:
1266 		case OPS_PKA_PRIVATE05:
1267 		case OPS_PKA_PRIVATE06:
1268 		case OPS_PKA_PRIVATE07:
1269 		case OPS_PKA_PRIVATE08:
1270 		case OPS_PKA_PRIVATE09:
1271 		case OPS_PKA_PRIVATE10:
1272 			print_data(print->indent, "Private/Experimental",
1273 			   &content->sig.info.sig.unknown);
1274 			break;
1275 
1276 		default:
1277 			(void) fprintf(stderr,
1278 				"__ops_print_packet: Unusual key algorithm\n");
1279 			return 0;
1280 		}
1281 		break;
1282 
1283 	case OPS_GET_PASSPHRASE:
1284 		print_tagname(print->indent, "OPS_GET_PASSPHRASE");
1285 		break;
1286 
1287 	case OPS_PTAG_CT_SECRET_KEY:
1288 		print_tagname(print->indent, "OPS_PTAG_CT_SECRET_KEY");
1289 		__ops_print_seckey_verbose(pkt->tag, &content->seckey);
1290 		break;
1291 
1292 	case OPS_PTAG_CT_ENCRYPTED_SECRET_KEY:
1293 		print_tagname(print->indent, "OPS_PTAG_CT_ENCRYPTED_SECRET_KEY");
1294 		__ops_print_seckey_verbose(pkt->tag, &content->seckey);
1295 		break;
1296 
1297 	case OPS_PTAG_CT_ARMOUR_HEADER:
1298 		print_tagname(print->indent, "ARMOUR HEADER");
1299 		print_string(print->indent, "type", content->armour_header.type);
1300 		break;
1301 
1302 	case OPS_PTAG_CT_SIGNED_CLEARTEXT_HEADER:
1303 		print_tagname(print->indent, "SIGNED CLEARTEXT HEADER");
1304 		print_headers(&content->cleartext_head);
1305 		break;
1306 
1307 	case OPS_PTAG_CT_SIGNED_CLEARTEXT_BODY:
1308 		print_tagname(print->indent, "SIGNED CLEARTEXT BODY");
1309 		print_block(print->indent, "signed cleartext", content->cleartext_body.data,
1310 			    content->cleartext_body.length);
1311 		break;
1312 
1313 	case OPS_PTAG_CT_SIGNED_CLEARTEXT_TRAILER:
1314 		print_tagname(print->indent, "SIGNED CLEARTEXT TRAILER");
1315 		printf("hash algorithm: %d\n",
1316 		       content->cleartext_trailer->alg);
1317 		printf("\n");
1318 		break;
1319 
1320 	case OPS_PTAG_CT_UNARMOURED_TEXT:
1321 		if (!print->unarmoured) {
1322 			print_tagname(print->indent, "UNARMOURED TEXT");
1323 			print->unarmoured = 1;
1324 		}
1325 		putchar('[');
1326 		print_escaped(content->unarmoured_text.data,
1327 			      content->unarmoured_text.length);
1328 		putchar(']');
1329 		break;
1330 
1331 	case OPS_PTAG_CT_ARMOUR_TRAILER:
1332 		print_tagname(print->indent, "ARMOUR TRAILER");
1333 		print_string(print->indent, "type", content->armour_header.type);
1334 		break;
1335 
1336 	case OPS_PTAG_CT_PK_SESSION_KEY:
1337 	case OPS_PTAG_CT_ENCRYPTED_PK_SESSION_KEY:
1338 		__ops_print_pk_sesskey(pkt->tag, &content->pk_sesskey);
1339 		break;
1340 
1341 	case OPS_GET_SECKEY:
1342 		__ops_print_pk_sesskey(OPS_PTAG_CT_ENCRYPTED_PK_SESSION_KEY,
1343 				    content->get_seckey.pk_sesskey);
1344 		break;
1345 
1346 	default:
1347 		print_tagname(print->indent, "UNKNOWN PACKET TYPE");
1348 		fprintf(stderr, "__ops_print_packet: unknown tag=%d (0x%x)\n",
1349 			pkt->tag, pkt->tag);
1350 		exit(EXIT_FAILURE);
1351 	}
1352 	return 1;
1353 }
1354 
1355 static __ops_cb_ret_t
1356 cb_list_packets(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
1357 {
1358 	__ops_print_packet(&cbinfo->printstate, pkt);
1359 	return OPS_RELEASE_MEMORY;
1360 }
1361 
1362 /**
1363 \ingroup Core_Print
1364 \param filename
1365 \param armour
1366 \param keyring
1367 \param cb_get_passphrase
1368 */
1369 int
1370 __ops_list_packets(__ops_io_t *io,
1371 			char *filename,
1372 			unsigned armour,
1373 			__ops_keyring_t *secring,
1374 			__ops_keyring_t *pubring,
1375 			void *passfp,
1376 			__ops_cbfunc_t *cb_get_passphrase)
1377 {
1378 	__ops_stream_t	*stream = NULL;
1379 	const unsigned	 accumulate = 1;
1380 	const int	 printerrors = 1;
1381 	int		 fd;
1382 
1383 	fd = __ops_setup_file_read(io, &stream, filename, NULL, cb_list_packets,
1384 				accumulate);
1385 	__ops_parse_options(stream, OPS_PTAG_SS_ALL, OPS_PARSE_PARSED);
1386 	stream->cryptinfo.secring = secring;
1387 	stream->cryptinfo.pubring = pubring;
1388 	stream->cbinfo.passfp = passfp;
1389 	stream->cryptinfo.getpassphrase = cb_get_passphrase;
1390 	if (armour) {
1391 		__ops_reader_push_dearmour(stream);
1392 	}
1393 	__ops_parse(stream, printerrors);
1394 	__ops_teardown_file_read(stream, fd);
1395 	return 1;
1396 }
1397