xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/packet-show.c (revision 3816d47b2c42fcd6e549e3407f842a5b1a1d23ad)
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 /** \file
51  *
52  * Creates printable text strings from packet contents
53  *
54  */
55 #include "config.h"
56 
57 #ifdef HAVE_SYS_CDEFS_H
58 #include <sys/cdefs.h>
59 #endif
60 
61 #if defined(__NetBSD__)
62 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
63 __RCSID("$NetBSD: packet-show.c,v 1.14 2009/10/09 06:02:55 agc Exp $");
64 #endif
65 
66 #include <stdlib.h>
67 #include <string.h>
68 
69 #include "packet-show.h"
70 
71 #include "netpgpdefs.h"
72 
73 
74 /*
75  * Arrays of value->text maps
76  */
77 
78 static __ops_map_t packet_tag_map[] =
79 {
80 	{OPS_PTAG_CT_RESERVED, "Reserved"},
81 	{OPS_PTAG_CT_PK_SESSION_KEY, "Public-Key Encrypted Session Key"},
82 	{OPS_PTAG_CT_SIGNATURE, "Signature"},
83 	{OPS_PTAG_CT_SK_SESSION_KEY, "Symmetric-Key Encrypted Session Key"},
84 	{OPS_PTAG_CT_1_PASS_SIG, "One-Pass Signature"},
85 	{OPS_PTAG_CT_SECRET_KEY, "Secret Key"},
86 	{OPS_PTAG_CT_PUBLIC_KEY, "Public Key"},
87 	{OPS_PTAG_CT_SECRET_SUBKEY, "Secret Subkey"},
88 	{OPS_PTAG_CT_COMPRESSED, "Compressed Data"},
89 	{OPS_PTAG_CT_SE_DATA, "Symmetrically Encrypted Data"},
90 	{OPS_PTAG_CT_MARKER, "Marker"},
91 	{OPS_PTAG_CT_LITDATA, "Literal Data"},
92 	{OPS_PTAG_CT_TRUST, "Trust"},
93 	{OPS_PTAG_CT_USER_ID, "User ID"},
94 	{OPS_PTAG_CT_PUBLIC_SUBKEY, "Public Subkey"},
95 	{OPS_PTAG_CT_RESERVED2, "reserved2"},
96 	{OPS_PTAG_CT_RESERVED3, "reserved3"},
97 	{OPS_PTAG_CT_USER_ATTR, "User Attribute"},
98 	{OPS_PTAG_CT_SE_IP_DATA,
99 		"Symmetric Encrypted and Integrity Protected Data"},
100 	{OPS_PTAG_CT_MDC, "Modification Detection Code"},
101 	{OPS_PARSER_PTAG, "OPS_PARSER_PTAG"},
102 	{OPS_PTAG_RAW_SS, "OPS_PTAG_RAW_SS"},
103 	{OPS_PTAG_SS_ALL, "OPS_PTAG_SS_ALL"},
104 	{OPS_PARSER_PACKET_END, "OPS_PARSER_PACKET_END"},
105 	{OPS_PTAG_SIG_SUBPKT_BASE, "OPS_PTAG_SIG_SUBPKT_BASE"},
106 	{OPS_PTAG_SS_CREATION_TIME, "SS: Signature Creation Time"},
107 	{OPS_PTAG_SS_EXPIRATION_TIME, "SS: Signature Expiration Time"},
108 	{OPS_PTAG_SS_EXPORT_CERT, "SS: Exportable Certification"},
109 	{OPS_PTAG_SS_TRUST, "SS: Trust Signature"},
110 	{OPS_PTAG_SS_REGEXP, "SS: Regular Expression"},
111 	{OPS_PTAG_SS_REVOCABLE, "SS: Revocable"},
112 	{OPS_PTAG_SS_KEY_EXPIRY, "SS: Key Expiration Time"},
113 	{OPS_PTAG_SS_RESERVED, "SS: Reserved"},
114 	{OPS_PTAG_SS_PREFERRED_SKA, "SS: Preferred Secret Key Algorithm"},
115 	{OPS_PTAG_SS_REVOCATION_KEY, "SS: Revocation Key"},
116 	{OPS_PTAG_SS_ISSUER_KEY_ID, "SS: Issuer Key Id"},
117 	{OPS_PTAG_SS_NOTATION_DATA, "SS: Notation Data"},
118 	{OPS_PTAG_SS_PREFERRED_HASH, "SS: Preferred Hash Algorithm"},
119 	{OPS_PTAG_SS_PREF_COMPRESS, "SS: Preferred Compression Algorithm"},
120 	{OPS_PTAG_SS_KEYSERV_PREFS, "SS: Key Server Preferences"},
121 	{OPS_PTAG_SS_PREF_KEYSERV, "SS: Preferred Key Server"},
122 	{OPS_PTAG_SS_PRIMARY_USER_ID, "SS: Primary User ID"},
123 	{OPS_PTAG_SS_POLICY_URI, "SS: Policy URI"},
124 	{OPS_PTAG_SS_KEY_FLAGS, "SS: Key Flags"},
125 	{OPS_PTAG_SS_SIGNERS_USER_ID, "SS: Signer's User ID"},
126 	{OPS_PTAG_SS_REVOCATION_REASON, "SS: Reason for Revocation"},
127 	{OPS_PTAG_SS_FEATURES, "SS: Features"},
128 	{OPS_PTAG_SS_SIGNATURE_TARGET, "SS: Signature Target"},
129 	{OPS_PTAG_SS_EMBEDDED_SIGNATURE, "SS: Embedded Signature"},
130 
131 	{OPS_PTAG_CT_LITDATA_HEADER, "CT: Literal Data Header"},
132 	{OPS_PTAG_CT_LITDATA_BODY, "CT: Literal Data Body"},
133 	{OPS_PTAG_CT_SIGNATURE_HEADER, "CT: Signature Header"},
134 	{OPS_PTAG_CT_SIGNATURE_FOOTER, "CT: Signature Footer"},
135 	{OPS_PTAG_CT_ARMOUR_HEADER, "CT: Armour Header"},
136 	{OPS_PTAG_CT_ARMOUR_TRAILER, "CT: Armour Trailer"},
137 	{OPS_PTAG_CT_SIGNED_CLEARTEXT_HEADER, "CT: Signed Cleartext Header"},
138 	{OPS_PTAG_CT_SIGNED_CLEARTEXT_BODY, "CT: Signed Cleartext Body"},
139 	{OPS_PTAG_CT_SIGNED_CLEARTEXT_TRAILER, "CT: Signed Cleartext Trailer"},
140 	{OPS_PTAG_CT_UNARMOURED_TEXT, "CT: Unarmoured Text"},
141 	{OPS_PTAG_CT_ENCRYPTED_SECRET_KEY, "CT: Encrypted Secret Key"},
142 	{OPS_PTAG_CT_SE_DATA_HEADER, "CT: Sym Encrypted Data Header"},
143 	{OPS_PTAG_CT_SE_DATA_BODY, "CT: Sym Encrypted Data Body"},
144 	{OPS_PTAG_CT_SE_IP_DATA_HEADER, "CT: Sym Encrypted IP Data Header"},
145 	{OPS_PTAG_CT_SE_IP_DATA_BODY, "CT: Sym Encrypted IP Data Body"},
146 	{OPS_PTAG_CT_ENCRYPTED_PK_SESSION_KEY, "CT: Encrypted PK Session Key"},
147 	{OPS_GET_PASSPHRASE, "CMD: Get Secret Key Passphrase"},
148 	{OPS_GET_SECKEY, "CMD: Get Secret Key"},
149 	{OPS_PARSER_ERROR, "OPS_PARSER_ERROR"},
150 	{OPS_PARSER_ERRCODE, "OPS_PARSER_ERRCODE"},
151 
152 	{0x00, NULL},		/* this is the end-of-array marker */
153 };
154 
155 static __ops_map_t ss_type_map[] =
156 {
157 	{OPS_PTAG_SS_CREATION_TIME, "Signature Creation Time"},
158 	{OPS_PTAG_SS_EXPIRATION_TIME, "Signature Expiration Time"},
159 	{OPS_PTAG_SS_TRUST, "Trust Signature"},
160 	{OPS_PTAG_SS_REGEXP, "Regular Expression"},
161 	{OPS_PTAG_SS_REVOCABLE, "Revocable"},
162 	{OPS_PTAG_SS_KEY_EXPIRY, "Key Expiration Time"},
163 	{OPS_PTAG_SS_PREFERRED_SKA, "Preferred Symmetric Algorithms"},
164 	{OPS_PTAG_SS_REVOCATION_KEY, "Revocation Key"},
165 	{OPS_PTAG_SS_ISSUER_KEY_ID, "Issuer key ID"},
166 	{OPS_PTAG_SS_NOTATION_DATA, "Notation Data"},
167 	{OPS_PTAG_SS_PREFERRED_HASH, "Preferred Hash Algorithms"},
168 	{OPS_PTAG_SS_PREF_COMPRESS, "Preferred Compression Algorithms"},
169 	{OPS_PTAG_SS_KEYSERV_PREFS, "Key Server Preferences"},
170 	{OPS_PTAG_SS_PREF_KEYSERV, "Preferred Key Server"},
171 	{OPS_PTAG_SS_PRIMARY_USER_ID, "Primary User ID"},
172 	{OPS_PTAG_SS_POLICY_URI, "Policy URI"},
173 	{OPS_PTAG_SS_KEY_FLAGS, "Key Flags"},
174 	{OPS_PTAG_SS_REVOCATION_REASON, "Reason for Revocation"},
175 	{OPS_PTAG_SS_FEATURES, "Features"},
176 	{0x00, NULL},		/* this is the end-of-array marker */
177 };
178 
179 
180 static __ops_map_t ss_rr_code_map[] =
181 {
182 	{0x00, "No reason specified"},
183 	{0x01, "Key is superseded"},
184 	{0x02, "Key material has been compromised"},
185 	{0x03, "Key is retired and no longer used"},
186 	{0x20, "User ID information is no longer valid"},
187 	{0x00, NULL},		/* this is the end-of-array marker */
188 };
189 
190 static __ops_map_t sig_type_map[] =
191 {
192 	{OPS_SIG_BINARY, "Signature of a binary document"},
193 	{OPS_SIG_TEXT, "Signature of a canonical text document"},
194 	{OPS_SIG_STANDALONE, "Standalone signature"},
195 	{OPS_CERT_GENERIC, "Generic certification of a User ID and Public Key packet"},
196 	{OPS_CERT_PERSONA, "Personal certification of a User ID and Public Key packet"},
197 	{OPS_CERT_CASUAL, "Casual certification of a User ID and Public Key packet"},
198 	{OPS_CERT_POSITIVE, "Positive certification of a User ID and Public Key packet"},
199 	{OPS_SIG_SUBKEY, "Subkey Binding Signature"},
200 	{OPS_SIG_PRIMARY, "Primary Key Binding Signature"},
201 	{OPS_SIG_DIRECT, "Signature directly on a key"},
202 	{OPS_SIG_REV_KEY, "Key revocation signature"},
203 	{OPS_SIG_REV_SUBKEY, "Subkey revocation signature"},
204 	{OPS_SIG_REV_CERT, "Certification revocation signature"},
205 	{OPS_SIG_TIMESTAMP, "Timestamp signature"},
206 	{OPS_SIG_3RD_PARTY, "Third-Party Confirmation signature"},
207 	{0x00, NULL},		/* this is the end-of-array marker */
208 };
209 
210 static __ops_map_t pubkey_alg_map[] =
211 {
212 	{OPS_PKA_RSA, "RSA (Encrypt or Sign)"},
213 	{OPS_PKA_RSA_ENCRYPT_ONLY, "RSA Encrypt-Only"},
214 	{OPS_PKA_RSA_SIGN_ONLY, "RSA Sign-Only"},
215 	{OPS_PKA_ELGAMAL, "Elgamal (Encrypt-Only)"},
216 	{OPS_PKA_DSA, "DSA"},
217 	{OPS_PKA_RESERVED_ELLIPTIC_CURVE, "Reserved for Elliptic Curve"},
218 	{OPS_PKA_RESERVED_ECDSA, "Reserved for ECDSA"},
219 	{OPS_PKA_ELGAMAL_ENCRYPT_OR_SIGN, "Reserved (formerly Elgamal Encrypt or Sign"},
220 	{OPS_PKA_RESERVED_DH, "Reserved for Diffie-Hellman (X9.42)"},
221 	{OPS_PKA_PRIVATE00, "Private/Experimental"},
222 	{OPS_PKA_PRIVATE01, "Private/Experimental"},
223 	{OPS_PKA_PRIVATE02, "Private/Experimental"},
224 	{OPS_PKA_PRIVATE03, "Private/Experimental"},
225 	{OPS_PKA_PRIVATE04, "Private/Experimental"},
226 	{OPS_PKA_PRIVATE05, "Private/Experimental"},
227 	{OPS_PKA_PRIVATE06, "Private/Experimental"},
228 	{OPS_PKA_PRIVATE07, "Private/Experimental"},
229 	{OPS_PKA_PRIVATE08, "Private/Experimental"},
230 	{OPS_PKA_PRIVATE09, "Private/Experimental"},
231 	{OPS_PKA_PRIVATE10, "Private/Experimental"},
232 	{0x00, NULL},		/* this is the end-of-array marker */
233 };
234 
235 static __ops_map_t symm_alg_map[] =
236 {
237 	{OPS_SA_PLAINTEXT, "Plaintext or unencrypted data"},
238 	{OPS_SA_IDEA, "IDEA"},
239 	{OPS_SA_TRIPLEDES, "TripleDES"},
240 	{OPS_SA_CAST5, "CAST5"},
241 	{OPS_SA_BLOWFISH, "Blowfish"},
242 	{OPS_SA_AES_128, "AES (128-bit key)"},
243 	{OPS_SA_AES_192, "AES (192-bit key)"},
244 	{OPS_SA_AES_256, "AES (256-bit key)"},
245 	{OPS_SA_TWOFISH, "Twofish(256-bit key)"},
246 	{0x00, NULL},		/* this is the end-of-array marker */
247 };
248 
249 static __ops_map_t hash_alg_map[] =
250 {
251 	{OPS_HASH_MD5, "MD5"},
252 	{OPS_HASH_SHA1, "SHA1"},
253 	{OPS_HASH_RIPEMD, "RIPEMD160"},
254 	{OPS_HASH_SHA256, "SHA256"},
255 	{OPS_HASH_SHA384, "SHA384"},
256 	{OPS_HASH_SHA512, "SHA512"},
257 	{OPS_HASH_SHA224, "SHA224"},
258 	{0x00, NULL},		/* this is the end-of-array marker */
259 };
260 
261 static __ops_map_t compression_alg_map[] =
262 {
263 	{OPS_C_NONE, "Uncompressed"},
264 	{OPS_C_ZIP, "ZIP(RFC1951)"},
265 	{OPS_C_ZLIB, "ZLIB(RFC1950)"},
266 	{OPS_C_BZIP2, "Bzip2(BZ2)"},
267 	{0x00, NULL},		/* this is the end-of-array marker */
268 };
269 
270 static __ops_bit_map_t ss_notation_map_byte0[] =
271 {
272 	{0x80, "Human-readable"},
273 	{0x00, NULL},
274 };
275 
276 static __ops_bit_map_t *ss_notation_map[] =
277 {
278 	ss_notation_map_byte0,
279 };
280 
281 static __ops_bit_map_t ss_feature_map_byte0[] =
282 {
283 	{0x01, "Modification Detection"},
284 	{0x00, NULL},
285 };
286 
287 static __ops_bit_map_t *ss_feature_map[] =
288 {
289 	ss_feature_map_byte0,
290 };
291 
292 static __ops_bit_map_t ss_key_flags_map[] =
293 {
294 	{0x01, "May be used to certify other keys"},
295 	{0x02, "May be used to sign data"},
296 	{0x04, "May be used to encrypt communications"},
297 	{0x08, "May be used to encrypt storage"},
298 	{0x10, "Private component may have been split by a secret-sharing mechanism"},
299 	{0x80, "Private component may be in possession of more than one person"},
300 	{0x00, NULL},
301 };
302 
303 static __ops_bit_map_t ss_key_server_prefs_map[] =
304 {
305 	{0x80, "Key holder requests that this key only be modified or updated by the key holder or an administrator of the key server"},
306 	{0x00, NULL},
307 };
308 
309 /*
310  * Private functions
311  */
312 
313 static void
314 list_init(__ops_list_t *list)
315 {
316 	list->size = 0;
317 	list->used = 0;
318 	list->strings = NULL;
319 }
320 
321 static void
322 list_free_strings(__ops_list_t *list)
323 {
324 	unsigned        i;
325 
326 	for (i = 0; i < list->used; i++) {
327 		free(list->strings[i]);
328 		list->strings[i] = NULL;
329 	}
330 }
331 
332 static void
333 list_free(__ops_list_t *list)
334 {
335 	if (list->strings)
336 		free(list->strings);
337 	list_init(list);
338 }
339 
340 static unsigned int
341 list_resize(__ops_list_t *list)
342 {
343 	/*
344 	 * We only resize in one direction - upwards. Algorithm used : double
345 	 * the current size then add 1
346 	 */
347 	char	**newstrings;
348 	int	  newsize;
349 
350 	newsize = (list->size * 2) + 1;
351 	newstrings = realloc(list->strings, newsize * sizeof(char *));
352 	if (newstrings) {
353 		list->strings = newstrings;
354 		list->size = newsize;
355 		return 1;
356 	}
357 	(void) fprintf(stderr, "list_resize - bad alloc\n");
358 	return 0;
359 }
360 
361 static unsigned int
362 add_str(__ops_list_t *list, const char *str)
363 {
364 	if (list->size == list->used && !list_resize(list)) {
365 		return 0;
366 	}
367 	list->strings[list->used++] = __UNCONST(str);
368 	return 1;
369 }
370 
371 /* find a bitfield in a map - serial search */
372 static const char *
373 find_bitfield(__ops_bit_map_t *map, unsigned char octet)
374 {
375 	__ops_bit_map_t  *row;
376 
377 	for (row = map; row->string != NULL && row->mask != octet ; row++) {
378 	}
379 	return (row->string) ? row->string : "Unknown";
380 }
381 
382 /* ! generic function to initialise __ops_text_t structure */
383 void
384 __ops_text_init(__ops_text_t *text)
385 {
386 	list_init(&text->known);
387 	list_init(&text->unknown);
388 }
389 
390 /**
391  * \ingroup Core_Print
392  *
393  * __ops_text_free() frees the memory used by an __ops_text_t structure
394  *
395  * \param text Pointer to a previously allocated structure. This structure and its contents will be freed.
396  */
397 void
398 __ops_text_free(__ops_text_t *text)
399 {
400 	/* Strings in "known" array will be constants, so don't free them */
401 	list_free(&text->known);
402 
403 	/*
404 	 * Strings in "unknown" array will be dynamically allocated, so do
405 	 * free them
406 	 */
407 	list_free_strings(&text->unknown);
408 	list_free(&text->unknown);
409 
410 	free(text);
411 }
412 
413 /* XXX: should this (and many others) be unsigned? */
414 /* ! generic function which adds text derived from single octet map to text */
415 static unsigned
416 add_str_from_octet_map(__ops_text_t *map, char *str, unsigned char octet)
417 {
418 	if (str && !add_str(&map->known, str)) {
419 		/*
420 		 * value recognised, but there was a problem adding it to the
421 		 * list
422 		 */
423 		/* XXX - should print out error msg here, Ben? - rachel */
424 		return 0;
425 	} else if (!str) {
426 		/*
427 		 * value not recognised and there was a problem adding it to
428 		 * the unknown list
429 		 */
430 		unsigned        len = 2 + 2 + 1;	/* 2 for "0x", 2 for
431 							 * single octet in hex
432 							 * format, 1 for NUL */
433 		if ((str = calloc(1, len)) == NULL) {
434 			(void) fprintf(stderr, "add_str_from_octet_map: bad alloc\n");
435 			return 0;
436 		}
437 		(void) snprintf(str, len, "0x%x", octet);
438 		if (!add_str(&map->unknown, str)) {
439 			return 0;
440 		}
441 		free(str);
442 	}
443 	return 1;
444 }
445 
446 /* ! generic function which adds text derived from single bit map to text */
447 static unsigned int
448 add_bitmap_entry(__ops_text_t *map, const char *str, unsigned char bit)
449 {
450 	const char     *fmt_unknown = "Unknown bit(0x%x)";
451 
452 	if (str && !add_str(&map->known, str)) {
453 		/*
454 		 * value recognised, but there was a problem adding it to the
455 		 * list
456 		 */
457 		/* XXX - should print out error msg here, Ben? - rachel */
458 		return 0;
459 	} else if (!str) {
460 		/*
461 		 * value not recognised and there was a problem adding it to
462 		 * the unknown list
463 		 * 2 chars of the string are the format definition, this will
464 		 * be replaced in the output by 2 chars of hex, so the length
465 		 * will be correct
466 		 */
467 		unsigned         len = strlen(fmt_unknown) + 1;
468 		char		*newstr;
469 
470 		if ((newstr = calloc(1, len)) == NULL) {
471 			(void) fprintf(stderr, "add_bitmap_entry: bad alloc\n");
472 			return 0;
473 		}
474 		(void) snprintf(newstr, len, fmt_unknown, bit);
475 		if (!add_str(&map->unknown, newstr)) {
476 			return 0;
477 		}
478 		free(newstr);
479 	}
480 	return 1;
481 }
482 
483 /**
484  * Produce a structure containing human-readable textstrings
485  * representing the recognised and unrecognised contents
486  * of this byte array. text_fn() will be called on each octet in turn.
487  * Each octet will generate one string representing the whole byte.
488  *
489  */
490 
491 static __ops_text_t *
492 text_from_bytemapped_octets(__ops_data_t *data,
493 			    const char *(*text_fn)(unsigned char octet))
494 {
495 	__ops_text_t	*text;
496 	const char	*str;
497 	unsigned	 i;
498 
499 	/*
500 	 * ! allocate and initialise __ops_text_t structure to store derived
501 	 * strings
502 	 */
503 	if ((text = calloc(1, sizeof(*text))) == NULL) {
504 		return NULL;
505 	}
506 
507 	__ops_text_init(text);
508 
509 	/* ! for each octet in field ... */
510 	for (i = 0; i < data->len; i++) {
511 		/* ! derive string from octet */
512 		str = (*text_fn) (data->contents[i]);
513 
514 		/* ! and add to text */
515 		if (!add_str_from_octet_map(text, strdup(str),
516 						data->contents[i])) {
517 			__ops_text_free(text);
518 			return NULL;
519 		}
520 	}
521 	/*
522 	 * ! All values have been added to either the known or the unknown
523 	 * list
524 	 */
525 	return text;
526 }
527 
528 /**
529  * Produce a structure containing human-readable textstrings
530  * representing the recognised and unrecognised contents
531  * of this byte array, derived from each bit of each octet.
532  *
533  */
534 static __ops_text_t *
535 showall_octets_bits(__ops_data_t *data, __ops_bit_map_t **map,
536 		    size_t nmap)
537 {
538 	unsigned char	 mask, bit;
539 	__ops_text_t	*text;
540 	const char	*str;
541 	unsigned         i;
542 	int              j = 0;
543 
544 	/*
545 	 * ! allocate and initialise __ops_text_t structure to store derived
546 	 * strings
547 	 */
548 	if ((text = calloc(1, sizeof(__ops_text_t))) == NULL) {
549 		return NULL;
550 	}
551 
552 	__ops_text_init(text);
553 
554 	/* ! for each octet in field ... */
555 	for (i = 0; i < data->len; i++) {
556 		/* ! for each bit in octet ... */
557 		mask = 0x80;
558 		for (j = 0; j < 8; j++, mask = (unsigned)mask >> 1) {
559 			bit = data->contents[i] & mask;
560 			if (bit) {
561 				str = (i >= nmap) ? "Unknown" :
562 					find_bitfield(map[i], bit);
563 				if (!add_bitmap_entry(text, str, bit)) {
564 					__ops_text_free(text);
565 					return NULL;
566 				}
567 			}
568 		}
569 	}
570 	return text;
571 }
572 
573 /*
574  * Public Functions
575  */
576 
577 /**
578  * \ingroup Core_Print
579  * returns description of the Packet Tag
580  * \param packet_tag
581  * \return string or "Unknown"
582 */
583 const char     *
584 __ops_show_packet_tag(__ops_packet_tag_t packet_tag)
585 {
586 	const char     *ret;
587 
588 	ret = __ops_str_from_map(packet_tag, packet_tag_map);
589 	if (!ret) {
590 		ret = "Unknown Tag";
591 	}
592 	return ret;
593 }
594 
595 /**
596  * \ingroup Core_Print
597  *
598  * returns description of the Signature Sub-Packet type
599  * \param ss_type Signature Sub-Packet type
600  * \return string or "Unknown"
601  */
602 const char     *
603 __ops_show_ss_type(__ops_ss_type_t ss_type)
604 {
605 	return __ops_str_from_map(ss_type, ss_type_map);
606 }
607 
608 /**
609  * \ingroup Core_Print
610  *
611  * returns description of the Revocation Reason code
612  * \param ss_rr_code Revocation Reason code
613  * \return string or "Unknown"
614  */
615 const char     *
616 __ops_show_ss_rr_code(__ops_ss_rr_code_t ss_rr_code)
617 {
618 	return __ops_str_from_map(ss_rr_code, ss_rr_code_map);
619 }
620 
621 /**
622  * \ingroup Core_Print
623  *
624  * returns description of the given Signature type
625  * \param sig_type Signature type
626  * \return string or "Unknown"
627  */
628 const char     *
629 __ops_show_sig_type(__ops_sig_type_t sig_type)
630 {
631 	return __ops_str_from_map(sig_type, sig_type_map);
632 }
633 
634 /**
635  * \ingroup Core_Print
636  *
637  * returns description of the given Public Key Algorithm
638  * \param pka Public Key Algorithm type
639  * \return string or "Unknown"
640  */
641 const char     *
642 __ops_show_pka(__ops_pubkey_alg_t pka)
643 {
644 	return __ops_str_from_map(pka, pubkey_alg_map);
645 }
646 
647 /**
648  * \ingroup Core_Print
649  * returns description of the Preferred Compression
650  * \param octet Preferred Compression
651  * \return string or "Unknown"
652 */
653 const char     *
654 __ops_show_ss_zpref(unsigned char octet)
655 {
656 	return __ops_str_from_map(octet, compression_alg_map);
657 }
658 
659 /**
660  * \ingroup Core_Print
661  *
662  * returns set of descriptions of the given Preferred Compression Algorithms
663  * \param ss_zpref Array of Preferred Compression Algorithms
664  * \return NULL if cannot allocate memory or other error
665  * \return pointer to structure, if no error
666  */
667 __ops_text_t     *
668 __ops_showall_ss_zpref(__ops_ss_zpref_t ss_zpref)
669 {
670 	return text_from_bytemapped_octets(&ss_zpref.data,
671 					&__ops_show_ss_zpref);
672 }
673 
674 
675 /**
676  * \ingroup Core_Print
677  *
678  * returns description of the Hash Algorithm type
679  * \param hash Hash Algorithm type
680  * \return string or "Unknown"
681  */
682 const char     *
683 __ops_show_hash_alg(unsigned char hash)
684 {
685 	return __ops_str_from_map(hash, hash_alg_map);
686 }
687 
688 /**
689  * \ingroup Core_Print
690  *
691  * returns set of descriptions of the given Preferred Hash Algorithms
692  * \param ss_hashpref Array of Preferred Hash Algorithms
693  * \return NULL if cannot allocate memory or other error
694  * \return pointer to structure, if no error
695  */
696 __ops_text_t     *
697 __ops_showall_ss_hashpref(__ops_ss_hashpref_t ss_hashpref)
698 {
699 	return text_from_bytemapped_octets(&ss_hashpref.data,
700 					   &__ops_show_hash_alg);
701 }
702 
703 const char     *
704 __ops_show_symm_alg(unsigned char hash)
705 {
706 	return __ops_str_from_map(hash, symm_alg_map);
707 }
708 
709 /**
710  * \ingroup Core_Print
711  * returns description of the given Preferred Symmetric Key Algorithm
712  * \param octet
713  * \return string or "Unknown"
714 */
715 const char     *
716 __ops_show_ss_skapref(unsigned char octet)
717 {
718 	return __ops_str_from_map(octet, symm_alg_map);
719 }
720 
721 /**
722  * \ingroup Core_Print
723  *
724  * returns set of descriptions of the given Preferred Symmetric Key Algorithms
725  * \param ss_skapref Array of Preferred Symmetric Key Algorithms
726  * \return NULL if cannot allocate memory or other error
727  * \return pointer to structure, if no error
728  */
729 __ops_text_t     *
730 __ops_showall_ss_skapref(__ops_ss_skapref_t ss_skapref)
731 {
732 	return text_from_bytemapped_octets(&ss_skapref.data,
733 					   &__ops_show_ss_skapref);
734 }
735 
736 /**
737  * \ingroup Core_Print
738  * returns description of one SS Feature
739  * \param octet
740  * \return string or "Unknown"
741 */
742 static const char *
743 __ops_show_ss_feature(unsigned char octet, unsigned offset)
744 {
745 	if (offset >= OPS_ARRAY_SIZE(ss_feature_map)) {
746 		return "Unknown";
747 	}
748 	return find_bitfield(ss_feature_map[offset], octet);
749 }
750 
751 /**
752  * \ingroup Core_Print
753  *
754  * returns set of descriptions of the given SS Features
755  * \param ss_features Signature Sub-Packet Features
756  * \return NULL if cannot allocate memory or other error
757  * \return pointer to structure, if no error
758  */
759 /* XXX: shouldn't this use show_all_octets_bits? */
760 __ops_text_t     *
761 __ops_showall_ss_features(__ops_ss_features_t ss_features)
762 {
763 	unsigned char	 mask, bit;
764 	__ops_text_t	*text;
765 	const char	*str;
766 	unsigned	 i;
767 	int		 j;
768 
769 	if ((text = calloc(1, sizeof(*text))) == NULL) {
770 		return NULL;
771 	}
772 
773 	__ops_text_init(text);
774 
775 	for (i = 0; i < ss_features.data.len; i++) {
776 		mask = 0x80;
777 		for (j = 0; j < 8; j++, mask = (unsigned)mask >> 1) {
778 			bit = ss_features.data.contents[i] & mask;
779 			if (bit) {
780 				str = __ops_show_ss_feature(bit, i);
781 				if (!add_bitmap_entry(text, str, bit)) {
782 					__ops_text_free(text);
783 					return NULL;
784 				}
785 			}
786 		}
787 	}
788 	return text;
789 }
790 
791 /**
792  * \ingroup Core_Print
793  * returns description of SS Key Flag
794  * \param octet
795  * \param map
796  * \return
797 */
798 const char     *
799 __ops_show_ss_key_flag(unsigned char octet, __ops_bit_map_t *map)
800 {
801 	return find_bitfield(map, octet);
802 }
803 
804 /**
805  * \ingroup Core_Print
806  *
807  * returns set of descriptions of the given Preferred Key Flags
808  * \param ss_key_flags Array of Key Flags
809  * \return NULL if cannot allocate memory or other error
810  * \return pointer to structure, if no error
811  */
812 __ops_text_t     *
813 __ops_showall_ss_key_flags(__ops_ss_key_flags_t ss_key_flags)
814 {
815 	unsigned char    mask, bit;
816 	__ops_text_t	*text;
817 	const char	*str;
818 	int              i;
819 
820 	if ((text = calloc(1, sizeof(*text))) == NULL) {
821 		return NULL;
822 	}
823 
824 	__ops_text_init(text);
825 
826 	/* xxx - TBD: extend to handle multiple octets of bits - rachel */
827 	for (i = 0, mask = 0x80; i < 8; i++, mask = (unsigned)mask >> 1) {
828 		bit = ss_key_flags.data.contents[0] & mask;
829 		if (bit) {
830 			str = __ops_show_ss_key_flag(bit, &ss_key_flags_map[0]);
831 			if (!add_bitmap_entry(text, strdup(str), bit)) {
832 				__ops_text_free(text);
833 				return NULL;
834 			}
835 		}
836 	}
837 	/*
838 	 * xxx - must add error text if more than one octet. Only one
839 	 * currently specified -- rachel
840 	 */
841 	return text;
842 }
843 
844 /**
845  * \ingroup Core_Print
846  *
847  * returns description of one given Key Server Preference
848  *
849  * \param prefs Byte containing bitfield of preferences
850  * \param map
851  * \return string or "Unknown"
852  */
853 const char     *
854 __ops_show_keyserv_pref(unsigned char prefs, __ops_bit_map_t *map)
855 {
856 	return find_bitfield(map, prefs);
857 }
858 
859 /**
860  * \ingroup Core_Print
861  * returns set of descriptions of given Key Server Preferences
862  * \param ss_key_server_prefs
863  * \return NULL if cannot allocate memory or other error
864  * \return pointer to structure, if no error
865  *
866 */
867 __ops_text_t     *
868 __ops_show_keyserv_prefs(__ops_ss_key_server_prefs_t prefs)
869 {
870 	unsigned char	 mask, bit;
871 	__ops_text_t	*text;
872 	const char	*str;
873 	int              i = 0;
874 
875 	if ((text = calloc(1, sizeof(*text))) == NULL) {
876 		return NULL;
877 	}
878 
879 	__ops_text_init(text);
880 
881 	/* xxx - TBD: extend to handle multiple octets of bits - rachel */
882 
883 	for (i = 0, mask = 0x80; i < 8; i++, mask = (unsigned)mask >> 1) {
884 		bit = prefs.data.contents[0] & mask;
885 		if (bit) {
886 			str = __ops_show_keyserv_pref(bit,
887 						ss_key_server_prefs_map);
888 			if (!add_bitmap_entry(text, strdup(str), bit)) {
889 				__ops_text_free(text);
890 				return NULL;
891 			}
892 		}
893 	}
894 	/*
895 	 * xxx - must add error text if more than one octet. Only one
896 	 * currently specified -- rachel
897 	 */
898 	return text;
899 }
900 
901 /**
902  * \ingroup Core_Print
903  *
904  * returns set of descriptions of the given SS Notation Data Flags
905  * \param ss_notation Signature Sub-Packet Notation Data
906  * \return NULL if cannot allocate memory or other error
907  * \return pointer to structure, if no error
908  */
909 __ops_text_t     *
910 __ops_showall_notation(__ops_ss_notation_t ss_notation)
911 {
912 	return showall_octets_bits(&ss_notation.flags,
913 				ss_notation_map,
914 				OPS_ARRAY_SIZE(ss_notation_map));
915 }
916