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