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