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