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