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