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