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