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