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