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