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