packet-print.c revision 1.21
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
80static int      indent = 0;
81
82/* static functions */
83
84static void
85print_indent(void)
86{
87	int             i;
88
89	for (i = 0; i < indent; i++) {
90		printf("  ");
91	}
92}
93
94static void
95print_name(const char *name)
96{
97	print_indent();
98	if (name) {
99		printf("%s: ", name);
100	}
101}
102
103static void
104print_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
113static void
114hexdump_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
123static void
124print_uint(const char *name, unsigned int val)
125{
126	print_name(name);
127	printf("%u\n", val);
128}
129
130static void
131showtime(const char *name, time_t t)
132{
133	printf("%s=%" PRItime "d (%.24s)", name, (long long) t, ctime(&t));
134}
135
136static void
137print_time(const char *name, time_t t)
138{
139	print_indent();
140	printf("%s: ", name);
141	showtime("time", t);
142	printf("\n");
143}
144
145static void
146print_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
152static void
153print_tagname(const char *str)
154{
155	print_indent();
156	printf("%s packet\n", str);
157}
158
159static void
160print_data(const char *name, const __ops_data_t *data)
161{
162	print_hexdump(name, data->contents, data->len);
163}
164
165static void
166print_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
178static void
179print_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
201static void
202print_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
215static void
216print_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
223static void
224print_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
230static void
231print_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
255static void
256print_boolean(const char *name, unsigned char boolval)
257{
258	print_name(name);
259	printf("%s\n", (boolval) ? "Yes" : "No");
260}
261
262static void
263print_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
291static void
292print_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
301static void
302print_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 */
332static int
333numkeybits(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 */
359static char *
360strhexdump(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 */
373static char *
374ptimestr(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 */
391int
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 */
417void
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*/
433void
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*/
479static 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*/
539static 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
572static void
573start_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
582static void
583end_subpacket(void)
584{
585	indent--;
586}
587
588/**
589\ingroup Core_Print
590\param contents
591*/
592int
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
1164static __ops_cb_ret_t
1165cb_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*/
1180int
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