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