xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/misc.c (revision 7affbacab9bd5b509bcf92dddc4a53cd447fef4c)
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 #include "config.h"
53 
54 #ifdef HAVE_SYS_CDEFS_H
55 #include <sys/cdefs.h>
56 #endif
57 
58 #if defined(__NetBSD__)
59 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
60 __RCSID("$NetBSD: misc.c,v 1.22 2009/10/07 16:19:51 agc Exp $");
61 #endif
62 
63 #include <sys/types.h>
64 #include <sys/stat.h>
65 #include <sys/mman.h>
66 
67 #include <stdarg.h>
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <string.h>
71 
72 #ifdef HAVE_UNISTD_H
73 #include <unistd.h>
74 #endif
75 
76 #ifdef HAVE_OPENSSL_RAND_H
77 #include <openssl/rand.h>
78 #endif
79 
80 #include "errors.h"
81 #include "packet.h"
82 #include "crypto.h"
83 #include "create.h"
84 #include "packet-parse.h"
85 #include "packet-show.h"
86 #include "signature.h"
87 #include "netpgpsdk.h"
88 #include "netpgpdefs.h"
89 #include "memory.h"
90 #include "readerwriter.h"
91 #include "version.h"
92 #include "netpgpdigest.h"
93 
94 #ifdef WIN32
95 #define vsnprintf _vsnprintf
96 #endif
97 
98 
99 typedef struct {
100 	__ops_keyring_t  *keyring;
101 } accumulate_t;
102 
103 /**
104  * \ingroup Core_Callbacks
105  */
106 static __ops_cb_ret_t
107 accumulate_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
108 {
109 	const __ops_contents_t	*content = &pkt->u;
110 	const __ops_pubkey_t	*pubkey;
111 	__ops_keyring_t		*keyring;
112 	__ops_key_t		*key;
113 	accumulate_t		*accumulate;
114 
115 	accumulate = __ops_callback_arg(cbinfo);
116 	keyring = accumulate->keyring;
117 	switch (pkt->tag) {
118 	case OPS_PTAG_CT_PUBLIC_KEY:
119 	case OPS_PTAG_CT_SECRET_KEY:
120 	case OPS_PTAG_CT_ENCRYPTED_SECRET_KEY:
121 		if (__ops_get_debug_level(__FILE__)) {
122 			(void) fprintf(stderr, "Creating key %u - tag %u\n",
123 				keyring->keyc, pkt->tag);
124 		}
125 		EXPAND_ARRAY(keyring, key);
126 		pubkey = (pkt->tag == OPS_PTAG_CT_PUBLIC_KEY) ?
127 					&content->pubkey :
128 					&content->seckey.pubkey;
129 		key = &keyring->keys[keyring->keyc++];
130 		(void) memset(key, 0x0, sizeof(*key));
131 		__ops_keyid(key->key_id, OPS_KEY_ID_SIZE, pubkey);
132 		__ops_fingerprint(&key->fingerprint, pubkey);
133 		key->type = pkt->tag;
134 		if (pkt->tag == OPS_PTAG_CT_PUBLIC_KEY) {
135 			key->key.pubkey = *pubkey;
136 		} else {
137 			key->key.seckey = content->seckey;
138 		}
139 		return OPS_KEEP_MEMORY;
140 	case OPS_PTAG_CT_USER_ID:
141 		if (__ops_get_debug_level(__FILE__)) {
142 			(void) fprintf(stderr, "User ID: %s for key %d\n",
143 					content->userid.userid,
144 					keyring->keyc - 1);
145 		}
146 		if (keyring->keyc > 0) {
147 			__ops_add_userid(&keyring->keys[keyring->keyc - 1],
148 						&content->userid);
149 			return OPS_KEEP_MEMORY;
150 		}
151 		OPS_ERROR(cbinfo->errors, OPS_E_P_NO_USERID, "No userid found");
152 		return OPS_KEEP_MEMORY;
153 
154 	case OPS_PARSER_PACKET_END:
155 		if (keyring->keyc > 0) {
156 			__ops_add_subpacket(&keyring->keys[keyring->keyc - 1],
157 						&content->packet);
158 			return OPS_KEEP_MEMORY;
159 		}
160 		return OPS_RELEASE_MEMORY;
161 
162 	case OPS_PARSER_ERROR:
163 		(void) fprintf(stderr, "Error: %s\n", content->error.error);
164 		return OPS_FINISHED;
165 
166 	case OPS_PARSER_ERRCODE:
167 		(void) fprintf(stderr, "parse error: %s\n",
168 				__ops_errcode(content->errcode.errcode));
169 		break;
170 
171 	default:
172 		break;
173 	}
174 
175 	/* XXX: we now exclude so many things, we should either drop this or */
176 	/* do something to pass on copies of the stuff we keep */
177 	return __ops_stacked_callback(pkt, cbinfo);
178 }
179 
180 /**
181  * \ingroup Core_Parse
182  *
183  * Parse packets from an input stream until EOF or error.
184  *
185  * Key data found in the parsed data is added to #keyring.
186  *
187  * \param keyring Pointer to an existing keyring
188  * \param parse Options to use when parsing
189 */
190 int
191 __ops_parse_and_accumulate(__ops_keyring_t *keyring, __ops_stream_t *parse)
192 {
193 	accumulate_t	accumulate;
194 	const int	printerrors = 1;
195 	int             ret;
196 
197 	if (parse->readinfo.accumulate) {
198 		(void) fprintf(stderr,
199 			"__ops_parse_and_accumulate: already init\n");
200 		return 0;
201 	}
202 
203 	(void) memset(&accumulate, 0x0, sizeof(accumulate));
204 
205 	accumulate.keyring = keyring;
206 
207 	__ops_callback_push(parse, accumulate_cb, &accumulate);
208 	parse->readinfo.accumulate = 1;
209 	ret = __ops_parse(parse, !printerrors);
210 
211 	return ret;
212 }
213 
214 
215 /** \file
216  * \brief Error Handling
217  */
218 #define ERRNAME(code)	{ code, #code }
219 
220 static __ops_errcode_name_map_t errcode_name_map[] = {
221 	ERRNAME(OPS_E_OK),
222 	ERRNAME(OPS_E_FAIL),
223 	ERRNAME(OPS_E_SYSTEM_ERROR),
224 	ERRNAME(OPS_E_UNIMPLEMENTED),
225 
226 	ERRNAME(OPS_E_R),
227 	ERRNAME(OPS_E_R_READ_FAILED),
228 	ERRNAME(OPS_E_R_EARLY_EOF),
229 	ERRNAME(OPS_E_R_BAD_FORMAT),
230 	ERRNAME(OPS_E_R_UNCONSUMED_DATA),
231 
232 	ERRNAME(OPS_E_W),
233 	ERRNAME(OPS_E_W_WRITE_FAILED),
234 	ERRNAME(OPS_E_W_WRITE_TOO_SHORT),
235 
236 	ERRNAME(OPS_E_P),
237 	ERRNAME(OPS_E_P_NOT_ENOUGH_DATA),
238 	ERRNAME(OPS_E_P_UNKNOWN_TAG),
239 	ERRNAME(OPS_E_P_PACKET_CONSUMED),
240 	ERRNAME(OPS_E_P_MPI_FORMAT_ERROR),
241 
242 	ERRNAME(OPS_E_C),
243 
244 	ERRNAME(OPS_E_V),
245 	ERRNAME(OPS_E_V_BAD_SIGNATURE),
246 	ERRNAME(OPS_E_V_NO_SIGNATURE),
247 	ERRNAME(OPS_E_V_UNKNOWN_SIGNER),
248 
249 	ERRNAME(OPS_E_ALG),
250 	ERRNAME(OPS_E_ALG_UNSUPPORTED_SYMMETRIC_ALG),
251 	ERRNAME(OPS_E_ALG_UNSUPPORTED_PUBLIC_KEY_ALG),
252 	ERRNAME(OPS_E_ALG_UNSUPPORTED_SIGNATURE_ALG),
253 	ERRNAME(OPS_E_ALG_UNSUPPORTED_HASH_ALG),
254 
255 	ERRNAME(OPS_E_PROTO),
256 	ERRNAME(OPS_E_PROTO_BAD_SYMMETRIC_DECRYPT),
257 	ERRNAME(OPS_E_PROTO_UNKNOWN_SS),
258 	ERRNAME(OPS_E_PROTO_CRITICAL_SS_IGNORED),
259 	ERRNAME(OPS_E_PROTO_BAD_PUBLIC_KEY_VRSN),
260 	ERRNAME(OPS_E_PROTO_BAD_SIGNATURE_VRSN),
261 	ERRNAME(OPS_E_PROTO_BAD_ONE_PASS_SIG_VRSN),
262 	ERRNAME(OPS_E_PROTO_BAD_PKSK_VRSN),
263 	ERRNAME(OPS_E_PROTO_DECRYPTED_MSG_WRONG_LEN),
264 	ERRNAME(OPS_E_PROTO_BAD_SK_CHECKSUM),
265 
266 	{0x00, NULL},		/* this is the end-of-array marker */
267 };
268 
269 /**
270  * \ingroup Core_Errors
271  * \brief returns error code name
272  * \param errcode
273  * \return error code name or "Unknown"
274  */
275 const char     *
276 __ops_errcode(const __ops_errcode_t errcode)
277 {
278 	return (__ops_str_from_map((int) errcode,
279 			(__ops_map_t *) errcode_name_map));
280 }
281 
282 /* generic grab new storage function */
283 void *
284 __ops_new(size_t size)
285 {
286 	void	*vp;
287 
288 	if ((vp = calloc(1, size)) == NULL) {
289 		(void) fprintf(stderr,
290 			"allocation failure for %" PRIsize "u bytes", size);
291 	}
292 	return vp;
293 }
294 
295 /**
296  * \ingroup Core_Errors
297  * \brief Pushes the given error on the given errorstack
298  * \param errstack Error stack to use
299  * \param errcode Code of error to push
300  * \param sys_errno System errno (used if errcode=OPS_E_SYSTEM_ERROR)
301  * \param file Source filename where error occurred
302  * \param line Line in source file where error occurred
303  * \param fmt Comment
304  *
305  */
306 
307 void
308 __ops_push_error(__ops_error_t **errstack, __ops_errcode_t errcode,
309 		int sys_errno, const char *file, int line, const char *fmt,...)
310 {
311 	/* first get the varargs and generate the comment */
312 	__ops_error_t  *err;
313 	unsigned	maxbuf = 128;
314 	va_list		args;
315 	char           *comment;
316 
317 	if ((comment = calloc(1, maxbuf + 1)) == NULL) {
318 		(void) fprintf(stderr, "calloc comment failure\n");
319 		return;
320 	}
321 
322 	va_start(args, fmt);
323 	vsnprintf(comment, maxbuf + 1, fmt, args);
324 	va_end(args);
325 
326 	/* alloc a new error and add it to the top of the stack */
327 
328 	if ((err = calloc(1, sizeof(*err))) == NULL) {
329 		(void) fprintf(stderr, "calloc comment failure\n");
330 		return;
331 	}
332 
333 	err->next = *errstack;
334 	*errstack = err;
335 
336 	/* fill in the details */
337 	err->errcode = errcode;
338 	err->sys_errno = sys_errno;
339 	err->file = file;
340 	err->line = line;
341 
342 	err->comment = comment;
343 }
344 
345 /**
346 \ingroup Core_Errors
347 \brief print this error
348 \param err Error to print
349 */
350 void
351 __ops_print_error(__ops_error_t *err)
352 {
353 	printf("%s:%d: ", err->file, err->line);
354 	if (err->errcode == OPS_E_SYSTEM_ERROR) {
355 		printf("system error %d returned from %s()\n", err->sys_errno,
356 		       err->comment);
357 	} else {
358 		printf("%s, %s\n", __ops_errcode(err->errcode), err->comment);
359 	}
360 }
361 
362 /**
363 \ingroup Core_Errors
364 \brief Print all errors on stack
365 \param errstack Error stack to print
366 */
367 void
368 __ops_print_errors(__ops_error_t *errstack)
369 {
370 	__ops_error_t    *err;
371 
372 	for (err = errstack; err != NULL; err = err->next) {
373 		__ops_print_error(err);
374 	}
375 }
376 
377 /**
378 \ingroup Core_Errors
379 \brief Return 1 if given error is present anywhere on stack
380 \param errstack Error stack to check
381 \param errcode Error code to look for
382 \return 1 if found; else 0
383 */
384 int
385 __ops_has_error(__ops_error_t *errstack, __ops_errcode_t errcode)
386 {
387 	__ops_error_t    *err;
388 
389 	for (err = errstack; err != NULL; err = err->next) {
390 		if (err->errcode == errcode) {
391 			return 1;
392 		}
393 	}
394 	return 0;
395 }
396 
397 /**
398 \ingroup Core_Errors
399 \brief Frees all errors on stack
400 \param errstack Error stack to free
401 */
402 void
403 __ops_free_errors(__ops_error_t *errstack)
404 {
405 	__ops_error_t    *next;
406 
407 	while (errstack != NULL) {
408 		next = errstack->next;
409 		free(errstack->comment);
410 		free(errstack);
411 		errstack = next;
412 	}
413 }
414 
415 /** \file
416  */
417 
418 /**
419  * \ingroup Core_Keys
420  * \brief Calculate a public key fingerprint.
421  * \param fp Where to put the calculated fingerprint
422  * \param key The key for which the fingerprint is calculated
423  */
424 
425 void
426 __ops_fingerprint(__ops_fingerprint_t *fp, const __ops_pubkey_t *key)
427 {
428 	if (key->version == 2 || key->version == 3) {
429 		unsigned char  *bn;
430 		size_t		n;
431 		__ops_hash_t	md5;
432 
433 		if (key->alg != OPS_PKA_RSA &&
434 		    key->alg != OPS_PKA_RSA_ENCRYPT_ONLY &&
435 		    key->alg != OPS_PKA_RSA_SIGN_ONLY) {
436 			(void) fprintf(stderr,
437 				"__ops_fingerprint: bad algorithm\n");
438 			return;
439 		}
440 
441 		__ops_hash_md5(&md5);
442 		if (!md5.init(&md5)) {
443 			(void) fprintf(stderr,
444 				"__ops_fingerprint: bad md5 alloc\n");
445 				return;
446 		}
447 
448 		n = (size_t) BN_num_bytes(key->key.rsa.n);
449 		if ((bn = calloc(1, n)) == NULL) {
450 			(void) fprintf(stderr,
451 				"__ops_fingerprint: bad bn alloc\n");
452 			return;
453 		}
454 		BN_bn2bin(key->key.rsa.n, bn);
455 		md5.add(&md5, bn, n);
456 		free(bn);
457 
458 		n = (size_t) BN_num_bytes(key->key.rsa.e);
459 		if ((bn = calloc(1, n)) == NULL) {
460 			(void) fprintf(stderr,
461 				"__ops_fingerprint: bad bn alloc 2\n");
462 			return;
463 		}
464 		BN_bn2bin(key->key.rsa.e, bn);
465 		md5.add(&md5, bn, n);
466 		free(bn);
467 
468 		md5.finish(&md5, fp->fingerprint);
469 		fp->length = 16;
470 	} else {
471 		__ops_memory_t	*mem = __ops_memory_new();
472 		__ops_hash_t	 sha1;
473 		size_t		 len;
474 
475 		__ops_build_pubkey(mem, key, 0);
476 
477 		if (__ops_get_debug_level(__FILE__)) {
478 			fprintf(stderr, "-> creating key fingerprint\n");
479 		}
480 		__ops_hash_sha1(&sha1);
481 		if (!sha1.init(&sha1)) {
482 			(void) fprintf(stderr,
483 				"__ops_fingerprint: bad sha1 alloc\n");
484 			return;
485 		}
486 
487 		len = __ops_mem_len(mem);
488 
489 		__ops_hash_add_int(&sha1, 0x99, 1);
490 		__ops_hash_add_int(&sha1, len, 2);
491 		sha1.add(&sha1, __ops_mem_data(mem), len);
492 		sha1.finish(&sha1, fp->fingerprint);
493 
494 		if (__ops_get_debug_level(__FILE__)) {
495 			fprintf(stderr, "<- finished making key fingerprint\n");
496 		}
497 		fp->length = OPS_FINGERPRINT_SIZE;
498 
499 		__ops_memory_free(mem);
500 	}
501 }
502 
503 /**
504  * \ingroup Core_Keys
505  * \brief Calculate the Key ID from the public key.
506  * \param keyid Space for the calculated ID to be stored
507  * \param key The key for which the ID is calculated
508  */
509 
510 void
511 __ops_keyid(unsigned char *keyid, const size_t idlen, const __ops_pubkey_t *key)
512 {
513 	if (key->version == 2 || key->version == 3) {
514 		unsigned char   bn[NETPGP_BUFSIZ];
515 		unsigned        n;
516 
517 		n = (unsigned) BN_num_bytes(key->key.rsa.n);
518 		if (n > sizeof(bn)) {
519 			(void) fprintf(stderr, "__ops_keyid: bad num bytes\n");
520 			return;
521 		}
522 		if (key->alg != OPS_PKA_RSA &&
523 		    key->alg != OPS_PKA_RSA_ENCRYPT_ONLY &&
524 		    key->alg != OPS_PKA_RSA_SIGN_ONLY) {
525 			(void) fprintf(stderr, "__ops_keyid: bad algorithm\n");
526 			return;
527 		}
528 		BN_bn2bin(key->key.rsa.n, bn);
529 		(void) memcpy(keyid, bn + n - idlen, idlen);
530 	} else {
531 		__ops_fingerprint_t finger;
532 
533 		__ops_fingerprint(&finger, key);
534 		(void) memcpy(keyid,
535 				finger.fingerprint + finger.length - idlen,
536 				idlen);
537 	}
538 }
539 
540 /**
541 \ingroup Core_Hashes
542 \brief Add to the hash
543 \param hash Hash to add to
544 \param n Int to add
545 \param length Length of int in bytes
546 */
547 void
548 __ops_hash_add_int(__ops_hash_t *hash, unsigned n, unsigned length)
549 {
550 	while (length--) {
551 		unsigned char   c;
552 
553 		c = n >> (length * 8);
554 		hash->add(hash, &c, 1);
555 	}
556 }
557 
558 /**
559 \ingroup Core_Hashes
560 \brief Setup hash for given hash algorithm
561 \param hash Hash to set up
562 \param alg Hash algorithm to use
563 */
564 void
565 __ops_hash_any(__ops_hash_t *hash, __ops_hash_alg_t alg)
566 {
567 	switch (alg) {
568 	case OPS_HASH_MD5:
569 		__ops_hash_md5(hash);
570 		break;
571 
572 	case OPS_HASH_SHA1:
573 		__ops_hash_sha1(hash);
574 		break;
575 
576 	case OPS_HASH_SHA256:
577 		__ops_hash_sha256(hash);
578 		break;
579 
580 	case OPS_HASH_SHA384:
581 		__ops_hash_sha384(hash);
582 		break;
583 
584 	case OPS_HASH_SHA512:
585 		__ops_hash_sha512(hash);
586 		break;
587 
588 	case OPS_HASH_SHA224:
589 		__ops_hash_sha224(hash);
590 		break;
591 
592 	default:
593 		(void) fprintf(stderr, "__ops_hash_any: bad algorithm\n");
594 	}
595 }
596 
597 /**
598 \ingroup Core_Hashes
599 \brief Returns size of hash for given hash algorithm
600 \param alg Hash algorithm to use
601 \return Size of hash algorithm in bytes
602 */
603 unsigned
604 __ops_hash_size(__ops_hash_alg_t alg)
605 {
606 	switch (alg) {
607 	case OPS_HASH_MD5:
608 		return 16;
609 
610 	case OPS_HASH_SHA1:
611 		return 20;
612 
613 	case OPS_HASH_SHA256:
614 		return 32;
615 
616 	case OPS_HASH_SHA224:
617 		return 28;
618 
619 	case OPS_HASH_SHA512:
620 		return 64;
621 
622 	case OPS_HASH_SHA384:
623 		return 48;
624 
625 	default:
626 		(void) fprintf(stderr, "__ops_hash_size: bad algorithm\n");
627 	}
628 
629 	return 0;
630 }
631 
632 /**
633 \ingroup Core_Hashes
634 \brief Returns hash enum corresponding to given string
635 \param hash Text name of hash algorithm i.e. "SHA1"
636 \returns Corresponding enum i.e. OPS_HASH_SHA1
637 */
638 __ops_hash_alg_t
639 __ops_str_to_hash_alg(const char *hash)
640 {
641 	if (strcmp(hash, "SHA1") == 0) {
642 		return OPS_HASH_SHA1;
643 	}
644 	if (strcmp(hash, "MD5") == 0) {
645 		return OPS_HASH_MD5;
646 	}
647 	if (strcmp(hash, "SHA256") == 0) {
648 		return OPS_HASH_SHA256;
649 	}
650 	/*
651         if (strcmp(hash,"SHA224") == 0) {
652 		return OPS_HASH_SHA224;
653 	}
654         */
655 	if (strcmp(hash, "SHA512") == 0) {
656 		return OPS_HASH_SHA512;
657 	}
658 	if (strcmp(hash, "SHA384") == 0) {
659 		return OPS_HASH_SHA384;
660 	}
661 	return OPS_HASH_UNKNOWN;
662 }
663 
664 /**
665 \ingroup Core_Hashes
666 \brief Hash given data
667 \param out Where to write the hash
668 \param alg Hash algorithm to use
669 \param in Data to hash
670 \param length Length of data
671 \return Size of hash created
672 */
673 unsigned
674 __ops_hash(unsigned char *out, __ops_hash_alg_t alg, const void *in,
675 	 size_t length)
676 {
677 	__ops_hash_t      hash;
678 
679 	__ops_hash_any(&hash, alg);
680 	if (!hash.init(&hash)) {
681 		(void) fprintf(stderr, "__ops_hash: bad alloc\n");
682 		/* we'll just continue here - don't want to return a 0 hash */
683 		/* XXX - agc - no way to return failure */
684 	}
685 	hash.add(&hash, in, length);
686 	return hash.finish(&hash, out);
687 }
688 
689 /**
690 \ingroup Core_Hashes
691 \brief Calculate hash for MDC packet
692 \param preamble Preamble to hash
693 \param sz_preamble Size of preamble
694 \param plaintext Plaintext to hash
695 \param sz_plaintext Size of plaintext
696 \param hashed Resulting hash
697 */
698 void
699 __ops_calc_mdc_hash(const unsigned char *preamble,
700 			const size_t sz_preamble,
701 			const unsigned char *plaintext,
702 			const unsigned sz_plaintext,
703 			unsigned char *hashed)
704 {
705 	unsigned char	c;
706 	__ops_hash_t	hash;
707 
708 	if (__ops_get_debug_level(__FILE__)) {
709 		unsigned	i;
710 
711 		(void) fprintf(stderr, "__ops_calc_mdc_hash():\n");
712 		(void) fprintf(stderr, "\npreamble: ");
713 		for (i = 0; i < sz_preamble; i++)
714 			(void) fprintf(stderr, " 0x%02x", preamble[i]);
715 		(void) fprintf(stderr, "\n");
716 		(void) fprintf(stderr, "\nplaintext (len=%u): ", sz_plaintext);
717 		for (i = 0; i < sz_plaintext; i++)
718 			(void) fprintf(stderr, " 0x%02x", plaintext[i]);
719 		(void) fprintf(stderr, "\n");
720 	}
721 	/* init */
722 	__ops_hash_any(&hash, OPS_HASH_SHA1);
723 	if (!hash.init(&hash)) {
724 		(void) fprintf(stderr, "__ops_calc_mdc_hash: bad alloc\n");
725 		/* we'll just continue here - it will die anyway */
726 		/* agc - XXX - no way to return failure */
727 	}
728 
729 	/* preamble */
730 	hash.add(&hash, preamble, sz_preamble);
731 	/* plaintext */
732 	hash.add(&hash, plaintext, sz_plaintext);
733 	/* MDC packet tag */
734 	c = MDC_PKT_TAG;
735 	hash.add(&hash, &c, 1);
736 	/* MDC packet len */
737 	c = OPS_SHA1_HASH_SIZE;
738 	hash.add(&hash, &c, 1);
739 
740 	/* finish */
741 	hash.finish(&hash, hashed);
742 
743 	if (__ops_get_debug_level(__FILE__)) {
744 		unsigned	i;
745 
746 		(void) fprintf(stderr, "\nhashed (len=%d): ",
747 				OPS_SHA1_HASH_SIZE);
748 		for (i = 0; i < OPS_SHA1_HASH_SIZE; i++) {
749 			(void) fprintf(stderr, " 0x%02x", hashed[i]);
750 		}
751 		(void) fprintf(stderr, "\n");
752 	}
753 }
754 
755 /**
756 \ingroup HighLevel_Supported
757 \brief Is this Hash Algorithm supported?
758 \param hash_alg Hash Algorithm to check
759 \return 1 if supported; else 0
760 */
761 unsigned
762 __ops_is_hash_alg_supported(const __ops_hash_alg_t *hash_alg)
763 {
764 	switch (*hash_alg) {
765 	case OPS_HASH_MD5:
766 	case OPS_HASH_SHA1:
767 	case OPS_HASH_SHA256:
768 		return 1;
769 
770 	default:
771 		return 0;
772 	}
773 }
774 
775 void
776 __ops_random(void *dest, size_t length)
777 {
778 	RAND_bytes(dest, (int)length);
779 }
780 
781 /**
782 \ingroup HighLevel_Memory
783 \brief Memory to initialise
784 \param mem memory to initialise
785 \param needed Size to initialise to
786 */
787 void
788 __ops_memory_init(__ops_memory_t *mem, size_t needed)
789 {
790 	unsigned char	*temp;
791 
792 	mem->length = 0;
793 	if (mem->buf) {
794 		if (mem->allocated < needed) {
795 			if ((temp = realloc(mem->buf, needed)) == NULL) {
796 				(void) fprintf(stderr, "__ops_memory_init: bad alloc\n");
797 			} else {
798 				mem->buf = temp;
799 				mem->allocated = needed;
800 			}
801 		}
802 	} else {
803 		if ((mem->buf = calloc(1, needed)) == NULL) {
804 			(void) fprintf(stderr, "__ops_memory_init: bad alloc\n");
805 		} else {
806 			mem->allocated = needed;
807 		}
808 	}
809 }
810 
811 /**
812 \ingroup HighLevel_Memory
813 \brief Pad memory to required length
814 \param mem Memory to use
815 \param length New size
816 */
817 void
818 __ops_memory_pad(__ops_memory_t *mem, size_t length)
819 {
820 	if (mem->allocated < mem->length) {
821 		(void) fprintf(stderr, "__ops_memory_pad: bad alloc in\n");
822 		return;
823 	}
824 	if (mem->allocated < mem->length + length) {
825 		mem->allocated = mem->allocated * 2 + length;
826 		mem->buf = realloc(mem->buf, mem->allocated);
827 	}
828 	if (mem->allocated < mem->length + length) {
829 		(void) fprintf(stderr, "__ops_memory_pad: bad alloc out\n");
830 	}
831 }
832 
833 /**
834 \ingroup HighLevel_Memory
835 \brief Add data to memory
836 \param mem Memory to which to add
837 \param src Data to add
838 \param length Length of data to add
839 */
840 void
841 __ops_memory_add(__ops_memory_t *mem, const unsigned char *src, size_t length)
842 {
843 	__ops_memory_pad(mem, length);
844 	(void) memcpy(mem->buf + mem->length, src, length);
845 	mem->length += length;
846 }
847 
848 /* XXX: this could be refactored via the writer, but an awful lot of */
849 /* hoops to jump through for 2 lines of code! */
850 void
851 __ops_memory_place_int(__ops_memory_t *mem, unsigned offset, unsigned n,
852 		     size_t length)
853 {
854 	if (mem->allocated < offset + length) {
855 		(void) fprintf(stderr,
856 			"__ops_memory_place_int: bad alloc\n");
857 	} else {
858 		while (length-- > 0) {
859 			mem->buf[offset++] = n >> (length * 8);
860 		}
861 	}
862 }
863 
864 /**
865  * \ingroup HighLevel_Memory
866  * \brief Retains allocated memory and set length of stored data to zero.
867  * \param mem Memory to clear
868  * \sa __ops_memory_release()
869  * \sa __ops_memory_free()
870  */
871 void
872 __ops_memory_clear(__ops_memory_t *mem)
873 {
874 	mem->length = 0;
875 }
876 
877 /**
878 \ingroup HighLevel_Memory
879 \brief Free memory and associated data
880 \param mem Memory to free
881 \note This does not free mem itself
882 \sa __ops_memory_clear()
883 \sa __ops_memory_free()
884 */
885 void
886 __ops_memory_release(__ops_memory_t *mem)
887 {
888 	if (mem->mmapped) {
889 		(void) munmap(mem->buf, mem->length);
890 	} else {
891 		free(mem->buf);
892 	}
893 	mem->buf = NULL;
894 	mem->length = 0;
895 }
896 
897 void
898 __ops_memory_make_packet(__ops_memory_t *out, __ops_content_tag_t tag)
899 {
900 	size_t          extra;
901 
902 	extra = (out->length < 192) ? 1 : (out->length < 8192 + 192) ? 2 : 5;
903 	__ops_memory_pad(out, extra + 1);
904 	memmove(out->buf + extra + 1, out->buf, out->length);
905 
906 	out->buf[0] = OPS_PTAG_ALWAYS_SET | OPS_PTAG_NEW_FORMAT | tag;
907 
908 	if (out->length < 192) {
909 		out->buf[1] = out->length;
910 	} else if (out->length < 8192 + 192) {
911 		out->buf[1] = ((out->length - 192) >> 8) + 192;
912 		out->buf[2] = out->length - 192;
913 	} else {
914 		out->buf[1] = 0xff;
915 		out->buf[2] = out->length >> 24;
916 		out->buf[3] = out->length >> 16;
917 		out->buf[4] = out->length >> 8;
918 		out->buf[5] = out->length;
919 	}
920 
921 	out->length += extra + 1;
922 }
923 
924 /**
925    \ingroup HighLevel_Memory
926    \brief Create a new zeroed __ops_memory_t
927    \return Pointer to new __ops_memory_t
928    \note Free using __ops_memory_free() after use.
929    \sa __ops_memory_free()
930 */
931 
932 __ops_memory_t   *
933 __ops_memory_new(void)
934 {
935 	return calloc(1, sizeof(__ops_memory_t));
936 }
937 
938 /**
939    \ingroup HighLevel_Memory
940    \brief Free memory ptr and associated memory
941    \param mem Memory to be freed
942    \sa __ops_memory_release()
943    \sa __ops_memory_clear()
944 */
945 
946 void
947 __ops_memory_free(__ops_memory_t *mem)
948 {
949 	__ops_memory_release(mem);
950 	free(mem);
951 }
952 
953 /**
954    \ingroup HighLevel_Memory
955    \brief Get length of data stored in __ops_memory_t struct
956    \return Number of bytes in data
957 */
958 size_t
959 __ops_mem_len(const __ops_memory_t *mem)
960 {
961 	return mem->length;
962 }
963 
964 /**
965    \ingroup HighLevel_Memory
966    \brief Get data stored in __ops_memory_t struct
967    \return Pointer to data
968 */
969 void *
970 __ops_mem_data(__ops_memory_t *mem)
971 {
972 	return mem->buf;
973 }
974 
975 /* read a gile into an __ops_memory_t */
976 int
977 __ops_mem_readfile(__ops_memory_t *mem, const char *f)
978 {
979 	struct stat	 st;
980 	FILE		*fp;
981 	int		 cc;
982 
983 	if ((fp = fopen(f, "rb")) == NULL) {
984 		(void) fprintf(stderr,
985 				"__ops_mem_readfile: can't open \"%s\"\n", f);
986 		return 0;
987 	}
988 	(void) fstat(fileno(fp), &st);
989 	mem->allocated = (size_t)st.st_size;
990 	mem->buf = mmap(NULL, mem->allocated, PROT_READ,
991 				MAP_PRIVATE | MAP_FILE, fileno(fp), 0);
992 	if (mem->buf == MAP_FAILED) {
993 		/* mmap failed for some reason - try to allocate memory */
994 		if ((mem->buf = calloc(1, mem->allocated)) == NULL) {
995 			(void) fprintf(stderr, "__ops_mem_readfile: calloc\n");
996 			(void) fclose(fp);
997 			return 0;
998 		}
999 		/* read into contents of mem */
1000 		for (mem->length = 0 ;
1001 		     (cc = read(fileno(fp), &mem->buf[mem->length],
1002 					mem->allocated - mem->length)) > 0 ;
1003 		     mem->length += (size_t)cc) {
1004 		}
1005 	} else {
1006 		mem->length = mem->allocated;
1007 		mem->mmapped = 1;
1008 	}
1009 	(void) fclose(fp);
1010 	return (mem->allocated == mem->length);
1011 }
1012 
1013 typedef struct {
1014 	unsigned short  sum;
1015 } sum16_t;
1016 
1017 
1018 /**
1019  * Searches the given map for the given type.
1020  * Returns a human-readable descriptive string if found,
1021  * returns NULL if not found
1022  *
1023  * It is the responsibility of the calling function to handle the
1024  * error case sensibly (i.e. don't just print out the return string.
1025  *
1026  */
1027 static const char *
1028 str_from_map_or_null(int type, __ops_map_t *map)
1029 {
1030 	__ops_map_t      *row;
1031 
1032 	for (row = map; row->string != NULL; row++) {
1033 		if (row->type == type) {
1034 			return row->string;
1035 		}
1036 	}
1037 	return NULL;
1038 }
1039 
1040 /**
1041  * \ingroup Core_Print
1042  *
1043  * Searches the given map for the given type.
1044  * Returns a readable string if found, "Unknown" if not.
1045  */
1046 
1047 const char     *
1048 __ops_str_from_map(int type, __ops_map_t *map)
1049 {
1050 	const char     *str;
1051 
1052 	str = str_from_map_or_null(type, map);
1053 	return (str) ? str : "Unknown";
1054 }
1055 
1056 void
1057 hexdump(FILE *fp, const unsigned char *src, size_t length, const char *sep)
1058 {
1059 	unsigned i;
1060 
1061 	for (i = 0 ; i < length ; i += 2) {
1062 		(void) fprintf(fp, "%02x", *src++);
1063 		(void) fprintf(fp, "%02x%s", *src++, sep);
1064 	}
1065 }
1066 
1067 /**
1068  * \ingroup HighLevel_Functions
1069  * \brief Initialises OpenPGP::SDK. To be called before any other OPS function.
1070  *
1071  * Initialises OpenPGP::SDK and the underlying openssl library.
1072  */
1073 
1074 void
1075 __ops_init(void)
1076 {
1077 	__ops_crypto_init();
1078 }
1079 
1080 /**
1081  * \ingroup HighLevel_Functions
1082  * \brief Closes down OpenPGP::SDK.
1083  *
1084  * Close down OpenPGP:SDK, release any resources under the control of
1085  * the library. No OpenPGP:SDK function other than __ops_init() should
1086  * be called after this function.
1087  */
1088 
1089 void
1090 __ops_finish(void)
1091 {
1092 	__ops_crypto_finish();
1093 }
1094 
1095 static int
1096 sum16_reader(void *dest_, size_t length, __ops_error_t **errors,
1097 	     __ops_reader_t *readinfo, __ops_cbdata_t *cbinfo)
1098 {
1099 	const unsigned char	*dest = dest_;
1100 	sum16_t			*arg = __ops_reader_get_arg(readinfo);
1101 	int			 r;
1102 	int			 n;
1103 
1104 	r = __ops_stacked_read(dest_, length, errors, readinfo, cbinfo);
1105 	if (r < 0) {
1106 		return r;
1107 	}
1108 	for (n = 0; n < r; ++n) {
1109 		arg->sum = (arg->sum + dest[n]) & 0xffff;
1110 	}
1111 	return r;
1112 }
1113 
1114 static void
1115 sum16_destroyer(__ops_reader_t *readinfo)
1116 {
1117 	free(__ops_reader_get_arg(readinfo));
1118 }
1119 
1120 /**
1121    \ingroup Internal_Readers_Sum16
1122    \param stream Parse settings
1123 */
1124 
1125 void
1126 __ops_reader_push_sum16(__ops_stream_t *stream)
1127 {
1128 	sum16_t    *arg;
1129 
1130 	if ((arg = calloc(1, sizeof(*arg))) == NULL) {
1131 		(void) fprintf(stderr, "__ops_reader_push_sum16: bad alloc\n");
1132 	} else {
1133 		__ops_reader_push(stream, sum16_reader, sum16_destroyer, arg);
1134 	}
1135 }
1136 
1137 /**
1138    \ingroup Internal_Readers_Sum16
1139    \param stream Parse settings
1140    \return sum
1141 */
1142 unsigned short
1143 __ops_reader_pop_sum16(__ops_stream_t *stream)
1144 {
1145 	unsigned short	 sum;
1146 	sum16_t		*arg;
1147 
1148 	arg = __ops_reader_get_arg(__ops_readinfo(stream));
1149 	sum = arg->sum;
1150 	__ops_reader_pop(stream);
1151 	free(arg);
1152 	return sum;
1153 }
1154 
1155 /* small useful functions for setting the file-level debugging levels */
1156 /* if the debugv list contains the filename in question, we're debugging it */
1157 
1158 enum {
1159 	MAX_DEBUG_NAMES = 32
1160 };
1161 
1162 static int      debugc;
1163 static char    *debugv[MAX_DEBUG_NAMES];
1164 
1165 /* set the debugging level per filename */
1166 int
1167 __ops_set_debug_level(const char *f)
1168 {
1169 	const char     *name;
1170 	int             i;
1171 
1172 	if (f == NULL) {
1173 		f = "all";
1174 	}
1175 	if ((name = strrchr(f, '/')) == NULL) {
1176 		name = f;
1177 	} else {
1178 		name += 1;
1179 	}
1180 	for (i = 0; i < debugc && i < MAX_DEBUG_NAMES; i++) {
1181 		if (strcmp(debugv[i], name) == 0) {
1182 			return 1;
1183 		}
1184 	}
1185 	if (i == MAX_DEBUG_NAMES) {
1186 		return 0;
1187 	}
1188 	debugv[debugc++] = strdup(name);
1189 	return 1;
1190 }
1191 
1192 /* get the debugging level per filename */
1193 int
1194 __ops_get_debug_level(const char *f)
1195 {
1196 	const char     *name;
1197 	int             i;
1198 
1199 	if ((name = strrchr(f, '/')) == NULL) {
1200 		name = f;
1201 	} else {
1202 		name += 1;
1203 	}
1204 	for (i = 0; i < debugc; i++) {
1205 		if (strcmp(debugv[i], "all") == 0 ||
1206 		    strcmp(debugv[i], name) == 0) {
1207 			return 1;
1208 		}
1209 	}
1210 	return 0;
1211 }
1212 
1213 /* return the version for the library */
1214 const char *
1215 __ops_get_info(const char *type)
1216 {
1217 	if (strcmp(type, "version") == 0) {
1218 		return NETPGP_VERSION_STRING;
1219 	}
1220 	if (strcmp(type, "maintainer") == 0) {
1221 		return NETPGP_MAINTAINER;
1222 	}
1223 	return "[unknown]";
1224 }
1225 
1226 void
1227 netpgp_log(const char *fmt, ...)
1228 {
1229 	va_list	 vp;
1230 	time_t	 t;
1231 	char	 buf[BUFSIZ * 2];
1232 	char	*cp;
1233 	int	 cc;
1234 
1235 	(void) time(&t);
1236 	cp = ctime(&t);
1237 	cc = snprintf(buf, sizeof(buf), "%.24s: netpgp: ", cp);
1238 	va_start(vp, fmt);
1239 	(void) vsnprintf(&buf[cc], sizeof(buf) - (size_t)cc, fmt, vp);
1240 	va_end(vp);
1241 	/* do something with message */
1242 	/* put into log buffer? */
1243 }
1244