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