xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/packet-print.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
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.37 2010/08/15 07:52: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 #include "mj.h"
81 
82 /* static functions */
83 
84 static void
85 print_indent(int indent)
86 {
87 	int             i;
88 
89 	for (i = 0; i < indent; i++) {
90 		printf("  ");
91 	}
92 }
93 
94 static void
95 print_name(int indent, const char *name)
96 {
97 	print_indent(indent);
98 	if (name) {
99 		printf("%s: ", name);
100 	}
101 }
102 
103 static void
104 print_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 
110 static void
111 hexdump_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 
117 static void
118 print_uint(int indent, const char *name, unsigned val)
119 {
120 	print_name(indent, name);
121 	printf("%u\n", val);
122 }
123 
124 static void
125 showtime(const char *name, time_t t)
126 {
127 	printf("%s=%" PRItime "d (%.24s)", name, (long long) t, ctime(&t));
128 }
129 
130 static void
131 print_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 
139 static void
140 print_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 
146 static void
147 print_tagname(int indent, const char *str)
148 {
149 	print_indent(indent);
150 	printf("%s packet\n", str);
151 }
152 
153 static void
154 print_data(int indent, const char *name, const __ops_data_t *data)
155 {
156 	print_hexdump(indent, name, data->contents, (unsigned)data->len);
157 }
158 
159 static void
160 print_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 
172 static void
173 print_packet_hex(const __ops_subpacket_t *pkt)
174 {
175 	hexdump(stdout, "packet contents:", pkt->raw, pkt->length);
176 }
177 
178 static void
179 print_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 
192 static void
193 print_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 
200 static void
201 print_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 
207 static void
208 print_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 
232 static void
233 print_boolean(int indent, const char *name, uint8_t boolval)
234 {
235 	print_name(indent, name);
236 	printf("%s\n", (boolval) ? "Yes" : "No");
237 }
238 
239 static void
240 print_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 
268 static void
269 print_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 
278 static void
279 print_block(int indent, const char *name, const uint8_t *str, size_t length)
280 {
281 	int             o = (int)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 */
309 static int
310 numkeybits(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 */
336 static char *
337 strhexdump(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 */
350 static char *
351 ptimestr(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 */
364 static int
365 psubkeybinding(char *buf, size_t size, const __ops_key_t *key, const char *expired)
366 {
367 	char	keyid[512];
368 	char	t[32];
369 
370 	return snprintf(buf, size, "encryption %d/%s %s %s %s\n",
371 		numkeybits(&key->enckey),
372 		__ops_show_pka(key->enckey.alg),
373 		strhexdump(keyid, key->encid, OPS_KEY_ID_SIZE, ""),
374 		ptimestr(t, sizeof(t), key->enckey.birthtime),
375 		expired);
376 }
377 
378 static int
379 isrevoked(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 */
396 int
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, NULL);
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, 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->sigid, OPS_KEY_ID_SIZE, ""),
470 		ptimestr(t, sizeof(t), pubkey->birthtime),
471 		expired,
472 		strhexdump(fp, key->sigfingerprint.fingerprint, key->sigfingerprint.length, " "),
473 		uidbuf);
474 }
475 
476 /* return the key info as a JSON encoded string */
477 int
478 __ops_sprint_mj(__ops_io_t *io, const __ops_keyring_t *keyring,
479 		const __ops_key_t *key, mj_t *keyjson, const char *header,
480 		const __ops_pubkey_t *pubkey, const int psigs)
481 {
482 	const __ops_key_t	*trustkey;
483 	unsigned	 	 from;
484 	unsigned		 i;
485 	unsigned		 j;
486 	mj_t			 sub_obj;
487 	char			 keyid[OPS_KEY_ID_SIZE * 3];
488 	char			 fp[(OPS_FINGERPRINT_SIZE * 3) + 1];
489 	int			 r;
490 
491 	if (key == NULL || key->revoked) {
492 		return -1;
493 	}
494 	(void) memset(keyjson, 0x0, sizeof(*keyjson));
495 	mj_create(keyjson, "object");
496 	mj_append_field(keyjson, "header", "string", header);
497 	mj_append_field(keyjson, "key bits", "integer", (int64_t) numkeybits(pubkey));
498 	mj_append_field(keyjson, "pka", "string", __ops_show_pka(pubkey->alg));
499 	mj_append_field(keyjson, "key id", "string", strhexdump(keyid, key->sigid, OPS_KEY_ID_SIZE, ""));
500 	mj_append_field(keyjson, "fingerprint", "string",
501 		strhexdump(fp, key->sigfingerprint.fingerprint, key->sigfingerprint.length, " "));
502 	mj_append_field(keyjson, "birthtime", "integer", pubkey->birthtime);
503 	mj_append_field(keyjson, "duration", "integer", pubkey->duration);
504 	for (i = 0; i < key->uidc; i++) {
505 		if ((r = isrevoked(key, i)) >= 0 &&
506 		    key->revokes[r].code == OPS_REVOCATION_COMPROMISED) {
507 			continue;
508 		}
509 		(void) memset(&sub_obj, 0x0, sizeof(sub_obj));
510 		mj_create(&sub_obj, "array");
511 		mj_append(&sub_obj, "string", key->uids[i]);
512 		mj_append(&sub_obj, "string", (r >= 0) ? "[REVOKED]" : "");
513 		mj_append_field(keyjson, "uid", "array", &sub_obj);
514 		mj_delete(&sub_obj);
515 		for (j = 0 ; j < key->subsigc ; j++) {
516 			if (psigs) {
517 				if (key->subsigs[j].uid != i) {
518 					continue;
519 				}
520 			} else {
521 				if (!(key->subsigs[j].sig.info.version == 4 &&
522 					key->subsigs[j].sig.info.type == OPS_SIG_SUBKEY &&
523 					i == key->uidc - 1)) {
524 						continue;
525 				}
526 			}
527 			(void) memset(&sub_obj, 0x0, sizeof(sub_obj));
528 			mj_create(&sub_obj, "array");
529 			if (key->subsigs[j].sig.info.version == 4 &&
530 					key->subsigs[j].sig.info.type == OPS_SIG_SUBKEY) {
531 				mj_append(&sub_obj, "integer", (int64_t)numkeybits(&key->enckey));
532 				mj_append(&sub_obj, "string",
533 					(const char *)__ops_show_pka(key->enckey.alg));
534 				mj_append(&sub_obj, "string",
535 					strhexdump(keyid, key->encid, OPS_KEY_ID_SIZE, ""));
536 				mj_append(&sub_obj, "integer", (int64_t)key->enckey.birthtime);
537 				mj_append_field(keyjson, "encryption", "array", &sub_obj);
538 				mj_delete(&sub_obj);
539 			} else {
540 				mj_append(&sub_obj, "string",
541 					strhexdump(keyid, key->subsigs[j].sig.info.signer_id, OPS_KEY_ID_SIZE, ""));
542 				mj_append(&sub_obj, "integer",
543 					(int64_t)(key->subsigs[j].sig.info.birthtime));
544 				from = 0;
545 				trustkey = __ops_getkeybyid(io, keyring, key->subsigs[j].sig.info.signer_id, &from, NULL);
546 				mj_append(&sub_obj, "string",
547 					(trustkey) ? (char *)trustkey->uids[trustkey->uid0] : "[unknown]");
548 				mj_append_field(keyjson, "sig", "array", &sub_obj);
549 				mj_delete(&sub_obj);
550 			}
551 		}
552 	}
553 	if (__ops_get_debug_level(__FILE__)) {
554 		char	*buf;
555 
556 		mj_asprint(&buf, keyjson);
557 		(void) fprintf(stderr, "__ops_sprint_mj: '%s'\n", buf);
558 		free(buf);
559 	}
560 	return 1;
561 }
562 
563 int
564 __ops_hkp_sprint_keydata(__ops_io_t *io, const __ops_keyring_t *keyring,
565 		const __ops_key_t *key, char **buf,
566 		const __ops_pubkey_t *pubkey, const int psigs)
567 {
568 	const __ops_key_t	*trustkey;
569 	unsigned	 	 from;
570 	unsigned	 	 i;
571 	unsigned	 	 j;
572 	char			 keyid[OPS_KEY_ID_SIZE * 3];
573 	char		 	 uidbuf[KB(128)];
574 	char		 	 fp[(OPS_FINGERPRINT_SIZE * 3) + 1];
575 	int		 	 n;
576 
577 	if (key->revoked) {
578 		return -1;
579 	}
580 	for (i = 0, n = 0; i < key->uidc; i++) {
581 		n += snprintf(&uidbuf[n], sizeof(uidbuf) - n,
582 			"uid:%lld:%lld:%s\n",
583 			(long long)pubkey->birthtime,
584 			(long long)pubkey->duration,
585 			key->uids[i]);
586 		for (j = 0 ; j < key->subsigc ; j++) {
587 			if (psigs) {
588 				if (key->subsigs[j].uid != i) {
589 					continue;
590 				}
591 			} else {
592 				if (!(key->subsigs[j].sig.info.version == 4 &&
593 					key->subsigs[j].sig.info.type == OPS_SIG_SUBKEY &&
594 					i == key->uidc - 1)) {
595 						continue;
596 				}
597 			}
598 			from = 0;
599 			trustkey = __ops_getkeybyid(io, keyring, key->subsigs[j].sig.info.signer_id, &from, NULL);
600 			if (key->subsigs[j].sig.info.version == 4 &&
601 					key->subsigs[j].sig.info.type == OPS_SIG_SUBKEY) {
602 				n += snprintf(&uidbuf[n], sizeof(uidbuf) - n, "sub:%d:%d:%s:%lld:%lld\n",
603 					numkeybits(pubkey),
604 					key->subsigs[j].sig.info.key_alg,
605 					strhexdump(keyid, key->subsigs[j].sig.info.signer_id, OPS_KEY_ID_SIZE, ""),
606 					(long long)(key->subsigs[j].sig.info.birthtime),
607 					(long long)pubkey->duration);
608 			} else {
609 				n += snprintf(&uidbuf[n], sizeof(uidbuf) - n,
610 					"sig:%s:%lld:%s\n",
611 					strhexdump(keyid, key->subsigs[j].sig.info.signer_id, OPS_KEY_ID_SIZE, ""),
612 					(long long)key->subsigs[j].sig.info.birthtime,
613 					(trustkey) ? (char *)trustkey->uids[trustkey->uid0] : "");
614 			}
615 		}
616 	}
617 	return __ops_asprintf(buf, "pub:%s:%d:%d:%lld:%lld\n%s",
618 		strhexdump(fp, key->sigfingerprint.fingerprint, OPS_FINGERPRINT_SIZE, ""),
619 		pubkey->alg,
620 		numkeybits(pubkey),
621 		(long long)pubkey->birthtime,
622 		(long long)pubkey->duration,
623 		uidbuf);
624 }
625 
626 /* print the key data for a pub or sec key */
627 void
628 __ops_print_keydata(__ops_io_t *io, const __ops_keyring_t *keyring,
629 		const __ops_key_t *key, const char *header,
630 		const __ops_pubkey_t *pubkey, const int psigs)
631 {
632 	char	*cp;
633 
634 	if (__ops_sprint_keydata(io, keyring, key, &cp, header, pubkey, psigs) >= 0) {
635 		(void) fprintf(io->res, "%s", cp);
636 		free(cp);
637 	}
638 }
639 
640 /**
641 \ingroup Core_Print
642 \param pubkey
643 */
644 void
645 __ops_print_pubkey(const __ops_pubkey_t *pubkey)
646 {
647 	printf("------- PUBLIC KEY ------\n");
648 	print_uint(0, "Version", (unsigned)pubkey->version);
649 	print_time(0, "Creation Time", pubkey->birthtime);
650 	if (pubkey->version == OPS_V3) {
651 		print_uint(0, "Days Valid", pubkey->days_valid);
652 	}
653 	print_string_and_value(0, "Algorithm", __ops_show_pka(pubkey->alg),
654 			       pubkey->alg);
655 	switch (pubkey->alg) {
656 	case OPS_PKA_DSA:
657 		print_bn(0, "p", pubkey->key.dsa.p);
658 		print_bn(0, "q", pubkey->key.dsa.q);
659 		print_bn(0, "g", pubkey->key.dsa.g);
660 		print_bn(0, "y", pubkey->key.dsa.y);
661 		break;
662 
663 	case OPS_PKA_RSA:
664 	case OPS_PKA_RSA_ENCRYPT_ONLY:
665 	case OPS_PKA_RSA_SIGN_ONLY:
666 		print_bn(0, "n", pubkey->key.rsa.n);
667 		print_bn(0, "e", pubkey->key.rsa.e);
668 		break;
669 
670 	case OPS_PKA_ELGAMAL:
671 	case OPS_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
672 		print_bn(0, "p", pubkey->key.elgamal.p);
673 		print_bn(0, "g", pubkey->key.elgamal.g);
674 		print_bn(0, "y", pubkey->key.elgamal.y);
675 		break;
676 
677 	default:
678 		(void) fprintf(stderr,
679 			"__ops_print_pubkey: Unusual algorithm\n");
680 	}
681 
682 	printf("------- end of PUBLIC KEY ------\n");
683 }
684 
685 int
686 __ops_sprint_pubkey(const __ops_key_t *key, char *out, size_t outsize)
687 {
688 	char	fp[(OPS_FINGERPRINT_SIZE * 3) + 1];
689 	int	cc;
690 
691 	cc = snprintf(out, outsize, "key:%s:%d:%lld:%lld:%d:\n",
692 		strhexdump(fp, key->sigfingerprint.fingerprint, OPS_FINGERPRINT_SIZE, ""),
693 		key->key.pubkey.version,
694 		(long long)key->key.pubkey.birthtime,
695 		(long long)key->key.pubkey.days_valid,
696 		key->key.pubkey.alg);
697 	switch (key->key.pubkey.alg) {
698 	case OPS_PKA_DSA:
699 		cc += snprintf(&out[cc], outsize - cc,
700 			"pubkey:p=%s:q=%s:g=%s:y=%s\n",
701 			BN_bn2hex(key->key.pubkey.key.dsa.p),
702 			BN_bn2hex(key->key.pubkey.key.dsa.q),
703 			BN_bn2hex(key->key.pubkey.key.dsa.g),
704 			BN_bn2hex(key->key.pubkey.key.dsa.y));
705 		break;
706 	case OPS_PKA_RSA:
707 	case OPS_PKA_RSA_ENCRYPT_ONLY:
708 	case OPS_PKA_RSA_SIGN_ONLY:
709 		cc += snprintf(&out[cc], outsize - cc,
710 			"pubkey:n=%s:e=%s\n",
711 			BN_bn2hex(key->key.pubkey.key.rsa.n),
712 			BN_bn2hex(key->key.pubkey.key.rsa.e));
713 		break;
714 	case OPS_PKA_ELGAMAL:
715 	case OPS_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
716 		cc += snprintf(&out[cc], outsize - cc,
717 			"pubkey:p=%s:g=%s:y=%s\n",
718 			BN_bn2hex(key->key.pubkey.key.elgamal.p),
719 			BN_bn2hex(key->key.pubkey.key.elgamal.g),
720 			BN_bn2hex(key->key.pubkey.key.elgamal.y));
721 		break;
722 	default:
723 		(void) fprintf(stderr,
724 			"__ops_print_pubkey: Unusual algorithm\n");
725 	}
726 	return cc;
727 }
728 
729 /**
730 \ingroup Core_Print
731 \param type
732 \param seckey
733 */
734 static void
735 __ops_print_seckey_verbose(const __ops_content_enum type,
736 				const __ops_seckey_t *seckey)
737 {
738 	printf("------- SECRET KEY or ENCRYPTED SECRET KEY ------\n");
739 	print_tagname(0, (type == OPS_PTAG_CT_SECRET_KEY) ?
740 			"SECRET_KEY" :
741 			"ENCRYPTED_SECRET_KEY");
742 	/* __ops_print_pubkey(key); */
743 	printf("S2K Usage: %d\n", seckey->s2k_usage);
744 	if (seckey->s2k_usage != OPS_S2KU_NONE) {
745 		printf("S2K Specifier: %d\n", seckey->s2k_specifier);
746 		printf("Symmetric algorithm: %d (%s)\n", seckey->alg,
747 		       __ops_show_symm_alg(seckey->alg));
748 		printf("Hash algorithm: %d (%s)\n", seckey->hash_alg,
749 		       __ops_show_hash_alg((uint8_t)seckey->hash_alg));
750 		if (seckey->s2k_specifier != OPS_S2KS_SIMPLE) {
751 			print_hexdump(0, "Salt", seckey->salt,
752 					(unsigned)sizeof(seckey->salt));
753 		}
754 		if (seckey->s2k_specifier == OPS_S2KS_ITERATED_AND_SALTED) {
755 			printf("Octet count: %u\n", seckey->octetc);
756 		}
757 		print_hexdump(0, "IV", seckey->iv, __ops_block_size(seckey->alg));
758 	}
759 	/* no more set if encrypted */
760 	if (type == OPS_PTAG_CT_ENCRYPTED_SECRET_KEY) {
761 		return;
762 	}
763 	switch (seckey->pubkey.alg) {
764 	case OPS_PKA_RSA:
765 		print_bn(0, "d", seckey->key.rsa.d);
766 		print_bn(0, "p", seckey->key.rsa.p);
767 		print_bn(0, "q", seckey->key.rsa.q);
768 		print_bn(0, "u", seckey->key.rsa.u);
769 		break;
770 
771 	case OPS_PKA_DSA:
772 		print_bn(0, "x", seckey->key.dsa.x);
773 		break;
774 
775 	default:
776 		(void) fprintf(stderr,
777 			"__ops_print_seckey_verbose: unusual algorithm\n");
778 	}
779 	if (seckey->s2k_usage == OPS_S2KU_ENCRYPTED_AND_HASHED) {
780 		print_hexdump(0, "Checkhash", seckey->checkhash,
781 				OPS_CHECKHASH_SIZE);
782 	} else {
783 		printf("Checksum: %04x\n", seckey->checksum);
784 	}
785 	printf("------- end of SECRET KEY or ENCRYPTED SECRET KEY ------\n");
786 }
787 
788 
789 /**
790 \ingroup Core_Print
791 \param tag
792 \param key
793 */
794 static void
795 __ops_print_pk_sesskey(__ops_content_enum tag,
796 			 const __ops_pk_sesskey_t * key)
797 {
798 	print_tagname(0, (tag == OPS_PTAG_CT_PK_SESSION_KEY) ?
799 		"PUBLIC KEY SESSION KEY" :
800 		"ENCRYPTED PUBLIC KEY SESSION KEY");
801 	printf("Version: %d\n", key->version);
802 	print_hexdump(0, "Key ID", key->key_id, (unsigned)sizeof(key->key_id));
803 	printf("Algorithm: %d (%s)\n", key->alg,
804 	       __ops_show_pka(key->alg));
805 	switch (key->alg) {
806 	case OPS_PKA_RSA:
807 		print_bn(0, "encrypted_m", key->params.rsa.encrypted_m);
808 		break;
809 
810 	case OPS_PKA_ELGAMAL:
811 		print_bn(0, "g_to_k", key->params.elgamal.g_to_k);
812 		print_bn(0, "encrypted_m", key->params.elgamal.encrypted_m);
813 		break;
814 
815 	default:
816 		(void) fprintf(stderr,
817 			"__ops_print_pk_sesskey: unusual algorithm\n");
818 	}
819 	if (tag == OPS_PTAG_CT_PK_SESSION_KEY) {
820 		printf("Symmetric algorithm: %d (%s)\n", key->symm_alg,
821 		       __ops_show_symm_alg(key->symm_alg));
822 		print_hexdump(0, "Key", key->key, __ops_key_size(key->symm_alg));
823 		printf("Checksum: %04x\n", key->checksum);
824 	}
825 }
826 
827 static void
828 start_subpacket(int *indent, int type)
829 {
830 	*indent += 1;
831 	print_indent(*indent);
832 	printf("-- %s (type 0x%02x)\n",
833 	       __ops_show_ss_type((__ops_content_enum)type),
834 	       type - OPS_PTAG_SIG_SUBPKT_BASE);
835 }
836 
837 static void
838 end_subpacket(int *indent)
839 {
840 	*indent -= 1;
841 }
842 
843 /**
844 \ingroup Core_Print
845 \param contents
846 */
847 int
848 __ops_print_packet(__ops_printstate_t *print, const __ops_packet_t *pkt)
849 {
850 	const __ops_contents_t	*content = &pkt->u;
851 	__ops_text_t		*text;
852 	const char		*str;
853 
854 	if (print->unarmoured && pkt->tag != OPS_PTAG_CT_UNARMOURED_TEXT) {
855 		print->unarmoured = 0;
856 		puts("UNARMOURED TEXT ends");
857 	}
858 	if (pkt->tag == OPS_PARSER_PTAG) {
859 		printf("=> OPS_PARSER_PTAG: %s\n",
860 			__ops_show_packet_tag((__ops_content_enum)content->ptag.type));
861 	} else {
862 		printf("=> %s\n", __ops_show_packet_tag(pkt->tag));
863 	}
864 
865 	switch (pkt->tag) {
866 	case OPS_PARSER_ERROR:
867 		printf("parse error: %s\n", content->error);
868 		break;
869 
870 	case OPS_PARSER_ERRCODE:
871 		printf("parse error: %s\n",
872 		       __ops_errcode(content->errcode.errcode));
873 		break;
874 
875 	case OPS_PARSER_PACKET_END:
876 		print_packet_hex(&content->packet);
877 		break;
878 
879 	case OPS_PARSER_PTAG:
880 		if (content->ptag.type == OPS_PTAG_CT_PUBLIC_KEY) {
881 			print->indent = 0;
882 			printf("\n*** NEXT KEY ***\n");
883 		}
884 		printf("\n");
885 		print_indent(print->indent);
886 		printf("==== ptag new_format=%u type=%u length_type=%d"
887 		       " length=0x%x (%u) position=0x%x (%u)\n",
888 		       content->ptag.new_format,
889 		       content->ptag.type, content->ptag.length_type,
890 		       content->ptag.length, content->ptag.length,
891 		       content->ptag.position, content->ptag.position);
892 		print_tagname(print->indent, __ops_show_packet_tag((__ops_content_enum)content->ptag.type));
893 		break;
894 
895 	case OPS_PTAG_CT_SE_DATA_HEADER:
896 		print_tagname(print->indent, "SYMMETRIC ENCRYPTED DATA");
897 		break;
898 
899 	case OPS_PTAG_CT_SE_IP_DATA_HEADER:
900 		print_tagname(print->indent,
901 			"SYMMETRIC ENCRYPTED INTEGRITY PROTECTED DATA HEADER");
902 		printf("Version: %d\n", content->se_ip_data_header);
903 		break;
904 
905 	case OPS_PTAG_CT_SE_IP_DATA_BODY:
906 		print_tagname(print->indent,
907 			"SYMMETRIC ENCRYPTED INTEGRITY PROTECTED DATA BODY");
908 		hexdump(stdout, "data", content->se_data_body.data,
909 			content->se_data_body.length);
910 		break;
911 
912 	case OPS_PTAG_CT_PUBLIC_KEY:
913 	case OPS_PTAG_CT_PUBLIC_SUBKEY:
914 		print_tagname(print->indent, (pkt->tag == OPS_PTAG_CT_PUBLIC_KEY) ?
915 			"PUBLIC KEY" :
916 			"PUBLIC SUBKEY");
917 		__ops_print_pubkey(&content->pubkey);
918 		break;
919 
920 	case OPS_PTAG_CT_TRUST:
921 		print_tagname(print->indent, "TRUST");
922 		print_data(print->indent, "Trust", &content->trust);
923 		break;
924 
925 	case OPS_PTAG_CT_USER_ID:
926 		print_tagname(print->indent, "USER ID");
927 		print_utf8_string(print->indent, "userid", content->userid);
928 		break;
929 
930 	case OPS_PTAG_CT_SIGNATURE:
931 		print_tagname(print->indent, "SIGNATURE");
932 		print_indent(print->indent);
933 		print_uint(print->indent, "Signature Version",
934 				   (unsigned)content->sig.info.version);
935 		if (content->sig.info.birthtime_set) {
936 			print_time(print->indent, "Signature Creation Time",
937 				   content->sig.info.birthtime);
938 		}
939 		if (content->sig.info.duration_set) {
940 			print_uint(print->indent, "Signature Duration",
941 				   (unsigned)content->sig.info.duration);
942 		}
943 
944 		print_string_and_value(print->indent, "Signature Type",
945 			    __ops_show_sig_type(content->sig.info.type),
946 				       content->sig.info.type);
947 
948 		if (content->sig.info.signer_id_set) {
949 			hexdump_data(print->indent, "Signer ID",
950 					   content->sig.info.signer_id,
951 				  (unsigned)sizeof(content->sig.info.signer_id));
952 		}
953 
954 		print_string_and_value(print->indent, "Public Key Algorithm",
955 			__ops_show_pka(content->sig.info.key_alg),
956 				     content->sig.info.key_alg);
957 		print_string_and_value(print->indent, "Hash Algorithm",
958 			__ops_show_hash_alg((uint8_t)
959 				content->sig.info.hash_alg),
960 			(uint8_t)content->sig.info.hash_alg);
961 		print_uint(print->indent, "Hashed data len",
962 			(unsigned)content->sig.info.v4_hashlen);
963 		print_indent(print->indent);
964 		hexdump_data(print->indent, "hash2", &content->sig.hash2[0], 2);
965 		switch (content->sig.info.key_alg) {
966 		case OPS_PKA_RSA:
967 		case OPS_PKA_RSA_SIGN_ONLY:
968 			print_bn(print->indent, "sig", content->sig.info.sig.rsa.sig);
969 			break;
970 
971 		case OPS_PKA_DSA:
972 			print_bn(print->indent, "r", content->sig.info.sig.dsa.r);
973 			print_bn(print->indent, "s", content->sig.info.sig.dsa.s);
974 			break;
975 
976 		case OPS_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
977 			print_bn(print->indent, "r", content->sig.info.sig.elgamal.r);
978 			print_bn(print->indent, "s", content->sig.info.sig.elgamal.s);
979 			break;
980 
981 		default:
982 			(void) fprintf(stderr,
983 				"__ops_print_packet: Unusual algorithm\n");
984 			return 0;
985 		}
986 
987 		if (content->sig.hash)
988 			printf("data hash is set\n");
989 
990 		break;
991 
992 	case OPS_PTAG_CT_COMPRESSED:
993 		print_tagname(print->indent, "COMPRESSED");
994 		print_uint(print->indent, "Compressed Data Type",
995 			(unsigned)content->compressed);
996 		break;
997 
998 	case OPS_PTAG_CT_1_PASS_SIG:
999 		print_tagname(print->indent, "ONE PASS SIGNATURE");
1000 
1001 		print_uint(print->indent, "Version", (unsigned)content->one_pass_sig.version);
1002 		print_string_and_value(print->indent, "Signature Type",
1003 		    __ops_show_sig_type(content->one_pass_sig.sig_type),
1004 				       content->one_pass_sig.sig_type);
1005 		print_string_and_value(print->indent, "Hash Algorithm",
1006 			__ops_show_hash_alg((uint8_t)content->one_pass_sig.hash_alg),
1007 			(uint8_t)content->one_pass_sig.hash_alg);
1008 		print_string_and_value(print->indent, "Public Key Algorithm",
1009 			__ops_show_pka(content->one_pass_sig.key_alg),
1010 			content->one_pass_sig.key_alg);
1011 		hexdump_data(print->indent, "Signer ID",
1012 				   content->one_pass_sig.keyid,
1013 				   (unsigned)sizeof(content->one_pass_sig.keyid));
1014 		print_uint(print->indent, "Nested", content->one_pass_sig.nested);
1015 		break;
1016 
1017 	case OPS_PTAG_CT_USER_ATTR:
1018 		print_tagname(print->indent, "USER ATTRIBUTE");
1019 		print_hexdump(print->indent, "User Attribute",
1020 			      content->userattr.contents,
1021 			      (unsigned)content->userattr.len);
1022 		break;
1023 
1024 	case OPS_PTAG_RAW_SS:
1025 		if (pkt->critical) {
1026 			(void) fprintf(stderr, "contents are critical\n");
1027 			return 0;
1028 		}
1029 		start_subpacket(&print->indent, pkt->tag);
1030 		print_uint(print->indent, "Raw Signature Subpacket: tag",
1031 			(unsigned)(content->ss_raw.tag -
1032 		   	(unsigned)OPS_PTAG_SIG_SUBPKT_BASE));
1033 		print_hexdump(print->indent, "Raw Data",
1034 			      content->ss_raw.raw,
1035 			      (unsigned)content->ss_raw.length);
1036 		break;
1037 
1038 	case OPS_PTAG_SS_CREATION_TIME:
1039 		start_subpacket(&print->indent, pkt->tag);
1040 		print_time(print->indent, "Signature Creation Time", content->ss_time);
1041 		end_subpacket(&print->indent);
1042 		break;
1043 
1044 	case OPS_PTAG_SS_EXPIRATION_TIME:
1045 		start_subpacket(&print->indent, pkt->tag);
1046 		print_duration(print->indent, "Signature Expiration Time",
1047 			content->ss_time);
1048 		end_subpacket(&print->indent);
1049 		break;
1050 
1051 	case OPS_PTAG_SS_KEY_EXPIRY:
1052 		start_subpacket(&print->indent, pkt->tag);
1053 		print_duration(print->indent, "Key Expiration Time", content->ss_time);
1054 		end_subpacket(&print->indent);
1055 		break;
1056 
1057 	case OPS_PTAG_SS_TRUST:
1058 		start_subpacket(&print->indent, pkt->tag);
1059 		print_string(print->indent, "Trust Signature", "");
1060 		print_uint(print->indent, "Level", (unsigned)content->ss_trust.level);
1061 		print_uint(print->indent, "Amount", (unsigned)content->ss_trust.amount);
1062 		end_subpacket(&print->indent);
1063 		break;
1064 
1065 	case OPS_PTAG_SS_REVOCABLE:
1066 		start_subpacket(&print->indent, pkt->tag);
1067 		print_boolean(print->indent, "Revocable", content->ss_revocable);
1068 		end_subpacket(&print->indent);
1069 		break;
1070 
1071 	case OPS_PTAG_SS_REVOCATION_KEY:
1072 		start_subpacket(&print->indent, pkt->tag);
1073 		/* not yet tested */
1074 		printf("  revocation key: class=0x%x",
1075 		       content->ss_revocation_key.class);
1076 		if (content->ss_revocation_key.class & 0x40) {
1077 			printf(" (sensitive)");
1078 		}
1079 		printf(", algid=0x%x", content->ss_revocation_key.algid);
1080 		hexdump(stdout, "fingerprint", content->ss_revocation_key.fingerprint,
1081 				OPS_FINGERPRINT_SIZE);
1082 		end_subpacket(&print->indent);
1083 		break;
1084 
1085 	case OPS_PTAG_SS_ISSUER_KEY_ID:
1086 		start_subpacket(&print->indent, pkt->tag);
1087 		print_hexdump(print->indent, "Issuer Key Id",
1088 			      content->ss_issuer, (unsigned)sizeof(content->ss_issuer));
1089 		end_subpacket(&print->indent);
1090 		break;
1091 
1092 	case OPS_PTAG_SS_PREFERRED_SKA:
1093 		start_subpacket(&print->indent, pkt->tag);
1094 		print_data(print->indent, "Preferred Symmetric Algorithms",
1095 			   &content->ss_skapref);
1096 		text = __ops_showall_ss_skapref(&content->ss_skapref);
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_PRIMARY_USER_ID:
1104 		start_subpacket(&print->indent, pkt->tag);
1105 		print_boolean(print->indent, "Primary User ID",
1106 			      content->ss_primary_userid);
1107 		end_subpacket(&print->indent);
1108 		break;
1109 
1110 	case OPS_PTAG_SS_PREFERRED_HASH:
1111 		start_subpacket(&print->indent, pkt->tag);
1112 		print_data(print->indent, "Preferred Hash Algorithms",
1113 			   &content->ss_hashpref);
1114 		text = __ops_showall_ss_hashpref(&content->ss_hashpref);
1115 		print_text_breakdown(print->indent, text);
1116 		__ops_text_free(text);
1117 		end_subpacket(&print->indent);
1118 		break;
1119 
1120 	case OPS_PTAG_SS_PREF_COMPRESS:
1121 		start_subpacket(&print->indent, pkt->tag);
1122 		print_data(print->indent, "Preferred Compression Algorithms",
1123 			   &content->ss_zpref);
1124 		text = __ops_showall_ss_zpref(&content->ss_zpref);
1125 		print_text_breakdown(print->indent, text);
1126 		__ops_text_free(text);
1127 		end_subpacket(&print->indent);
1128 		break;
1129 
1130 	case OPS_PTAG_SS_KEY_FLAGS:
1131 		start_subpacket(&print->indent, pkt->tag);
1132 		print_data(print->indent, "Key Flags", &content->ss_key_flags);
1133 
1134 		text = __ops_showall_ss_key_flags(&content->ss_key_flags);
1135 		print_text_breakdown(print->indent, text);
1136 		__ops_text_free(text);
1137 
1138 		end_subpacket(&print->indent);
1139 		break;
1140 
1141 	case OPS_PTAG_SS_KEYSERV_PREFS:
1142 		start_subpacket(&print->indent, pkt->tag);
1143 		print_data(print->indent, "Key Server Preferences",
1144 			   &content->ss_key_server_prefs);
1145 		text = __ops_show_keyserv_prefs(&content->ss_key_server_prefs);
1146 		print_text_breakdown(print->indent, text);
1147 		__ops_text_free(text);
1148 
1149 		end_subpacket(&print->indent);
1150 		break;
1151 
1152 	case OPS_PTAG_SS_FEATURES:
1153 		start_subpacket(&print->indent, pkt->tag);
1154 		print_data(print->indent, "Features", &content->ss_features);
1155 		text = __ops_showall_ss_features(content->ss_features);
1156 		print_text_breakdown(print->indent, text);
1157 		__ops_text_free(text);
1158 
1159 		end_subpacket(&print->indent);
1160 		break;
1161 
1162 	case OPS_PTAG_SS_NOTATION_DATA:
1163 		start_subpacket(&print->indent, pkt->tag);
1164 		print_indent(print->indent);
1165 		printf("Notation Data:\n");
1166 
1167 		print->indent++;
1168 		print_data(print->indent, "Flags", &content->ss_notation.flags);
1169 		text = __ops_showall_notation(content->ss_notation);
1170 		print_text_breakdown(print->indent, text);
1171 		__ops_text_free(text);
1172 
1173 		print_data(print->indent, "Name", &content->ss_notation.name);
1174 
1175 		print_data(print->indent, "Value", &content->ss_notation.value);
1176 
1177 		print->indent--;
1178 		end_subpacket(&print->indent);
1179 		break;
1180 
1181 	case OPS_PTAG_SS_REGEXP:
1182 		start_subpacket(&print->indent, pkt->tag);
1183 		print_hexdump(print->indent, "Regular Expression",
1184 			      (uint8_t *) content->ss_regexp,
1185 			      (unsigned)strlen(content->ss_regexp));
1186 		print_string(print->indent, NULL, content->ss_regexp);
1187 		end_subpacket(&print->indent);
1188 		break;
1189 
1190 	case OPS_PTAG_SS_POLICY_URI:
1191 		start_subpacket(&print->indent, pkt->tag);
1192 		print_string(print->indent, "Policy URL", content->ss_policy);
1193 		end_subpacket(&print->indent);
1194 		break;
1195 
1196 	case OPS_PTAG_SS_SIGNERS_USER_ID:
1197 		start_subpacket(&print->indent, pkt->tag);
1198 		print_utf8_string(print->indent, "Signer's User ID", content->ss_signer);
1199 		end_subpacket(&print->indent);
1200 		break;
1201 
1202 	case OPS_PTAG_SS_PREF_KEYSERV:
1203 		start_subpacket(&print->indent, pkt->tag);
1204 		print_string(print->indent, "Preferred Key Server", content->ss_keyserv);
1205 		end_subpacket(&print->indent);
1206 		break;
1207 
1208 	case OPS_PTAG_SS_EMBEDDED_SIGNATURE:
1209 		start_subpacket(&print->indent, pkt->tag);
1210 		end_subpacket(&print->indent);/* \todo print out contents? */
1211 		break;
1212 
1213 	case OPS_PTAG_SS_USERDEFINED00:
1214 	case OPS_PTAG_SS_USERDEFINED01:
1215 	case OPS_PTAG_SS_USERDEFINED02:
1216 	case OPS_PTAG_SS_USERDEFINED03:
1217 	case OPS_PTAG_SS_USERDEFINED04:
1218 	case OPS_PTAG_SS_USERDEFINED05:
1219 	case OPS_PTAG_SS_USERDEFINED06:
1220 	case OPS_PTAG_SS_USERDEFINED07:
1221 	case OPS_PTAG_SS_USERDEFINED08:
1222 	case OPS_PTAG_SS_USERDEFINED09:
1223 	case OPS_PTAG_SS_USERDEFINED10:
1224 		start_subpacket(&print->indent, pkt->tag);
1225 		print_hexdump(print->indent, "Internal or user-defined",
1226 			      content->ss_userdef.contents,
1227 			      (unsigned)content->ss_userdef.len);
1228 		end_subpacket(&print->indent);
1229 		break;
1230 
1231 	case OPS_PTAG_SS_RESERVED:
1232 		start_subpacket(&print->indent, pkt->tag);
1233 		print_hexdump(print->indent, "Reserved",
1234 			      content->ss_userdef.contents,
1235 			      (unsigned)content->ss_userdef.len);
1236 		end_subpacket(&print->indent);
1237 		break;
1238 
1239 	case OPS_PTAG_SS_REVOCATION_REASON:
1240 		start_subpacket(&print->indent, pkt->tag);
1241 		print_hexdump(print->indent, "Revocation Reason",
1242 			      &content->ss_revocation.code,
1243 			      1);
1244 		str = __ops_show_ss_rr_code(content->ss_revocation.code);
1245 		print_string(print->indent, NULL, str);
1246 		end_subpacket(&print->indent);
1247 		break;
1248 
1249 	case OPS_PTAG_CT_LITDATA_HEADER:
1250 		print_tagname(print->indent, "LITERAL DATA HEADER");
1251 		printf("  literal data header format=%c filename='%s'\n",
1252 		       content->litdata_header.format,
1253 		       content->litdata_header.filename);
1254 		showtime("    modification time",
1255 			 content->litdata_header.mtime);
1256 		printf("\n");
1257 		break;
1258 
1259 	case OPS_PTAG_CT_LITDATA_BODY:
1260 		print_tagname(print->indent, "LITERAL DATA BODY");
1261 		printf("  literal data body length=%u\n",
1262 		       content->litdata_body.length);
1263 		printf("    data=");
1264 		print_escaped(content->litdata_body.data,
1265 			      content->litdata_body.length);
1266 		printf("\n");
1267 		break;
1268 
1269 	case OPS_PTAG_CT_SIGNATURE_HEADER:
1270 		print_tagname(print->indent, "SIGNATURE");
1271 		print_indent(print->indent);
1272 		print_uint(print->indent, "Signature Version",
1273 				   (unsigned)content->sig.info.version);
1274 		if (content->sig.info.birthtime_set) {
1275 			print_time(print->indent, "Signature Creation Time",
1276 				content->sig.info.birthtime);
1277 		}
1278 		if (content->sig.info.duration_set) {
1279 			print_uint(print->indent, "Signature Duration",
1280 				   (unsigned)content->sig.info.duration);
1281 		}
1282 		print_string_and_value(print->indent, "Signature Type",
1283 			    __ops_show_sig_type(content->sig.info.type),
1284 				       content->sig.info.type);
1285 		if (content->sig.info.signer_id_set) {
1286 			hexdump_data(print->indent, "Signer ID",
1287 				content->sig.info.signer_id,
1288 				(unsigned)sizeof(content->sig.info.signer_id));
1289 		}
1290 		print_string_and_value(print->indent, "Public Key Algorithm",
1291 			__ops_show_pka(content->sig.info.key_alg),
1292 				     content->sig.info.key_alg);
1293 		print_string_and_value(print->indent, "Hash Algorithm",
1294 			__ops_show_hash_alg((uint8_t)content->sig.info.hash_alg),
1295 			(uint8_t)content->sig.info.hash_alg);
1296 		print_uint(print->indent, "Hashed data len",
1297 			(unsigned)content->sig.info.v4_hashlen);
1298 
1299 		break;
1300 
1301 	case OPS_PTAG_CT_SIGNATURE_FOOTER:
1302 		print_indent(print->indent);
1303 		hexdump_data(print->indent, "hash2", &content->sig.hash2[0], 2);
1304 
1305 		switch (content->sig.info.key_alg) {
1306 		case OPS_PKA_RSA:
1307 			print_bn(print->indent, "sig", content->sig.info.sig.rsa.sig);
1308 			break;
1309 
1310 		case OPS_PKA_DSA:
1311 			print_bn(print->indent, "r", content->sig.info.sig.dsa.r);
1312 			print_bn(print->indent, "s", content->sig.info.sig.dsa.s);
1313 			break;
1314 
1315 		case OPS_PKA_ELGAMAL_ENCRYPT_OR_SIGN:
1316 			print_bn(print->indent, "r", content->sig.info.sig.elgamal.r);
1317 			print_bn(print->indent, "s", content->sig.info.sig.elgamal.s);
1318 			break;
1319 
1320 		case OPS_PKA_PRIVATE00:
1321 		case OPS_PKA_PRIVATE01:
1322 		case OPS_PKA_PRIVATE02:
1323 		case OPS_PKA_PRIVATE03:
1324 		case OPS_PKA_PRIVATE04:
1325 		case OPS_PKA_PRIVATE05:
1326 		case OPS_PKA_PRIVATE06:
1327 		case OPS_PKA_PRIVATE07:
1328 		case OPS_PKA_PRIVATE08:
1329 		case OPS_PKA_PRIVATE09:
1330 		case OPS_PKA_PRIVATE10:
1331 			print_data(print->indent, "Private/Experimental",
1332 			   &content->sig.info.sig.unknown);
1333 			break;
1334 
1335 		default:
1336 			(void) fprintf(stderr,
1337 				"__ops_print_packet: Unusual key algorithm\n");
1338 			return 0;
1339 		}
1340 		break;
1341 
1342 	case OPS_GET_PASSPHRASE:
1343 		print_tagname(print->indent, "OPS_GET_PASSPHRASE");
1344 		break;
1345 
1346 	case OPS_PTAG_CT_SECRET_KEY:
1347 		print_tagname(print->indent, "OPS_PTAG_CT_SECRET_KEY");
1348 		__ops_print_seckey_verbose(pkt->tag, &content->seckey);
1349 		break;
1350 
1351 	case OPS_PTAG_CT_ENCRYPTED_SECRET_KEY:
1352 		print_tagname(print->indent, "OPS_PTAG_CT_ENCRYPTED_SECRET_KEY");
1353 		__ops_print_seckey_verbose(pkt->tag, &content->seckey);
1354 		break;
1355 
1356 	case OPS_PTAG_CT_ARMOUR_HEADER:
1357 		print_tagname(print->indent, "ARMOUR HEADER");
1358 		print_string(print->indent, "type", content->armour_header.type);
1359 		break;
1360 
1361 	case OPS_PTAG_CT_SIGNED_CLEARTEXT_HEADER:
1362 		print_tagname(print->indent, "SIGNED CLEARTEXT HEADER");
1363 		print_headers(&content->cleartext_head);
1364 		break;
1365 
1366 	case OPS_PTAG_CT_SIGNED_CLEARTEXT_BODY:
1367 		print_tagname(print->indent, "SIGNED CLEARTEXT BODY");
1368 		print_block(print->indent, "signed cleartext", content->cleartext_body.data,
1369 			    content->cleartext_body.length);
1370 		break;
1371 
1372 	case OPS_PTAG_CT_SIGNED_CLEARTEXT_TRAILER:
1373 		print_tagname(print->indent, "SIGNED CLEARTEXT TRAILER");
1374 		printf("hash algorithm: %d\n",
1375 		       content->cleartext_trailer->alg);
1376 		printf("\n");
1377 		break;
1378 
1379 	case OPS_PTAG_CT_UNARMOURED_TEXT:
1380 		if (!print->unarmoured) {
1381 			print_tagname(print->indent, "UNARMOURED TEXT");
1382 			print->unarmoured = 1;
1383 		}
1384 		putchar('[');
1385 		print_escaped(content->unarmoured_text.data,
1386 			      content->unarmoured_text.length);
1387 		putchar(']');
1388 		break;
1389 
1390 	case OPS_PTAG_CT_ARMOUR_TRAILER:
1391 		print_tagname(print->indent, "ARMOUR TRAILER");
1392 		print_string(print->indent, "type", content->armour_header.type);
1393 		break;
1394 
1395 	case OPS_PTAG_CT_PK_SESSION_KEY:
1396 	case OPS_PTAG_CT_ENCRYPTED_PK_SESSION_KEY:
1397 		__ops_print_pk_sesskey(pkt->tag, &content->pk_sesskey);
1398 		break;
1399 
1400 	case OPS_GET_SECKEY:
1401 		__ops_print_pk_sesskey(OPS_PTAG_CT_ENCRYPTED_PK_SESSION_KEY,
1402 				    content->get_seckey.pk_sesskey);
1403 		break;
1404 
1405 	default:
1406 		print_tagname(print->indent, "UNKNOWN PACKET TYPE");
1407 		fprintf(stderr, "__ops_print_packet: unknown tag=%d (0x%x)\n",
1408 			pkt->tag, pkt->tag);
1409 		exit(EXIT_FAILURE);
1410 	}
1411 	return 1;
1412 }
1413 
1414 static __ops_cb_ret_t
1415 cb_list_packets(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
1416 {
1417 	__ops_print_packet(&cbinfo->printstate, pkt);
1418 	return OPS_RELEASE_MEMORY;
1419 }
1420 
1421 /**
1422 \ingroup Core_Print
1423 \param filename
1424 \param armour
1425 \param keyring
1426 \param cb_get_passphrase
1427 */
1428 int
1429 __ops_list_packets(__ops_io_t *io,
1430 			char *filename,
1431 			unsigned armour,
1432 			__ops_keyring_t *secring,
1433 			__ops_keyring_t *pubring,
1434 			void *passfp,
1435 			__ops_cbfunc_t *cb_get_passphrase)
1436 {
1437 	__ops_stream_t	*stream = NULL;
1438 	const unsigned	 accumulate = 1;
1439 	const int	 printerrors = 1;
1440 	int		 fd;
1441 
1442 	fd = __ops_setup_file_read(io, &stream, filename, NULL, cb_list_packets,
1443 				accumulate);
1444 	__ops_parse_options(stream, OPS_PTAG_SS_ALL, OPS_PARSE_PARSED);
1445 	stream->cryptinfo.secring = secring;
1446 	stream->cryptinfo.pubring = pubring;
1447 	stream->cbinfo.passfp = passfp;
1448 	stream->cryptinfo.getpassphrase = cb_get_passphrase;
1449 	if (armour) {
1450 		__ops_reader_push_dearmour(stream);
1451 	}
1452 	__ops_parse(stream, printerrors);
1453 	__ops_teardown_file_read(stream, fd);
1454 	return 1;
1455 }
1456