xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/misc.c (revision 0aa9bcca65387f0ce436e8422fdbf22bb409bc89)
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.23 2009/10/09 06:02:55 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 	unsigned char	*temp;
821 
822 	if (mem->allocated < mem->length) {
823 		(void) fprintf(stderr, "__ops_memory_pad: bad alloc in\n");
824 		return;
825 	}
826 	if (mem->allocated < mem->length + length) {
827 		mem->allocated = mem->allocated * 2 + length;
828 		temp = realloc(mem->buf, mem->allocated);
829 		if (temp == NULL) {
830 			(void) fprintf(stderr, "__ops_memory_pad: bad alloc\n");
831 		} else {
832 			mem->buf = temp;
833 		}
834 	}
835 	if (mem->allocated < mem->length + length) {
836 		(void) fprintf(stderr, "__ops_memory_pad: bad alloc out\n");
837 	}
838 }
839 
840 /**
841 \ingroup HighLevel_Memory
842 \brief Add data to memory
843 \param mem Memory to which to add
844 \param src Data to add
845 \param length Length of data to add
846 */
847 void
848 __ops_memory_add(__ops_memory_t *mem, const unsigned char *src, size_t length)
849 {
850 	__ops_memory_pad(mem, length);
851 	(void) memcpy(mem->buf + mem->length, src, length);
852 	mem->length += length;
853 }
854 
855 /* XXX: this could be refactored via the writer, but an awful lot of */
856 /* hoops to jump through for 2 lines of code! */
857 void
858 __ops_memory_place_int(__ops_memory_t *mem, unsigned offset, unsigned n,
859 		     size_t length)
860 {
861 	if (mem->allocated < offset + length) {
862 		(void) fprintf(stderr,
863 			"__ops_memory_place_int: bad alloc\n");
864 	} else {
865 		while (length-- > 0) {
866 			mem->buf[offset++] = n >> (length * 8);
867 		}
868 	}
869 }
870 
871 /**
872  * \ingroup HighLevel_Memory
873  * \brief Retains allocated memory and set length of stored data to zero.
874  * \param mem Memory to clear
875  * \sa __ops_memory_release()
876  * \sa __ops_memory_free()
877  */
878 void
879 __ops_memory_clear(__ops_memory_t *mem)
880 {
881 	mem->length = 0;
882 }
883 
884 /**
885 \ingroup HighLevel_Memory
886 \brief Free memory and associated data
887 \param mem Memory to free
888 \note This does not free mem itself
889 \sa __ops_memory_clear()
890 \sa __ops_memory_free()
891 */
892 void
893 __ops_memory_release(__ops_memory_t *mem)
894 {
895 	if (mem->mmapped) {
896 		(void) munmap(mem->buf, mem->length);
897 	} else {
898 		free(mem->buf);
899 	}
900 	mem->buf = NULL;
901 	mem->length = 0;
902 }
903 
904 void
905 __ops_memory_make_packet(__ops_memory_t *out, __ops_content_tag_t tag)
906 {
907 	size_t          extra;
908 
909 	extra = (out->length < 192) ? 1 : (out->length < 8192 + 192) ? 2 : 5;
910 	__ops_memory_pad(out, extra + 1);
911 	memmove(out->buf + extra + 1, out->buf, out->length);
912 
913 	out->buf[0] = OPS_PTAG_ALWAYS_SET | OPS_PTAG_NEW_FORMAT | tag;
914 
915 	if (out->length < 192) {
916 		out->buf[1] = out->length;
917 	} else if (out->length < 8192 + 192) {
918 		out->buf[1] = ((out->length - 192) >> 8) + 192;
919 		out->buf[2] = out->length - 192;
920 	} else {
921 		out->buf[1] = 0xff;
922 		out->buf[2] = out->length >> 24;
923 		out->buf[3] = out->length >> 16;
924 		out->buf[4] = out->length >> 8;
925 		out->buf[5] = out->length;
926 	}
927 
928 	out->length += extra + 1;
929 }
930 
931 /**
932    \ingroup HighLevel_Memory
933    \brief Create a new zeroed __ops_memory_t
934    \return Pointer to new __ops_memory_t
935    \note Free using __ops_memory_free() after use.
936    \sa __ops_memory_free()
937 */
938 
939 __ops_memory_t   *
940 __ops_memory_new(void)
941 {
942 	return calloc(1, sizeof(__ops_memory_t));
943 }
944 
945 /**
946    \ingroup HighLevel_Memory
947    \brief Free memory ptr and associated memory
948    \param mem Memory to be freed
949    \sa __ops_memory_release()
950    \sa __ops_memory_clear()
951 */
952 
953 void
954 __ops_memory_free(__ops_memory_t *mem)
955 {
956 	__ops_memory_release(mem);
957 	free(mem);
958 }
959 
960 /**
961    \ingroup HighLevel_Memory
962    \brief Get length of data stored in __ops_memory_t struct
963    \return Number of bytes in data
964 */
965 size_t
966 __ops_mem_len(const __ops_memory_t *mem)
967 {
968 	return mem->length;
969 }
970 
971 /**
972    \ingroup HighLevel_Memory
973    \brief Get data stored in __ops_memory_t struct
974    \return Pointer to data
975 */
976 void *
977 __ops_mem_data(__ops_memory_t *mem)
978 {
979 	return mem->buf;
980 }
981 
982 /* read a gile into an __ops_memory_t */
983 int
984 __ops_mem_readfile(__ops_memory_t *mem, const char *f)
985 {
986 	struct stat	 st;
987 	FILE		*fp;
988 	int		 cc;
989 
990 	if ((fp = fopen(f, "rb")) == NULL) {
991 		(void) fprintf(stderr,
992 				"__ops_mem_readfile: can't open \"%s\"\n", f);
993 		return 0;
994 	}
995 	(void) fstat(fileno(fp), &st);
996 	mem->allocated = (size_t)st.st_size;
997 	mem->buf = mmap(NULL, mem->allocated, PROT_READ,
998 				MAP_PRIVATE | MAP_FILE, fileno(fp), 0);
999 	if (mem->buf == MAP_FAILED) {
1000 		/* mmap failed for some reason - try to allocate memory */
1001 		if ((mem->buf = calloc(1, mem->allocated)) == NULL) {
1002 			(void) fprintf(stderr, "__ops_mem_readfile: calloc\n");
1003 			(void) fclose(fp);
1004 			return 0;
1005 		}
1006 		/* read into contents of mem */
1007 		for (mem->length = 0 ;
1008 		     (cc = read(fileno(fp), &mem->buf[mem->length],
1009 					mem->allocated - mem->length)) > 0 ;
1010 		     mem->length += (size_t)cc) {
1011 		}
1012 	} else {
1013 		mem->length = mem->allocated;
1014 		mem->mmapped = 1;
1015 	}
1016 	(void) fclose(fp);
1017 	return (mem->allocated == mem->length);
1018 }
1019 
1020 typedef struct {
1021 	unsigned short  sum;
1022 } sum16_t;
1023 
1024 
1025 /**
1026  * Searches the given map for the given type.
1027  * Returns a human-readable descriptive string if found,
1028  * returns NULL if not found
1029  *
1030  * It is the responsibility of the calling function to handle the
1031  * error case sensibly (i.e. don't just print out the return string.
1032  *
1033  */
1034 static const char *
1035 str_from_map_or_null(int type, __ops_map_t *map)
1036 {
1037 	__ops_map_t      *row;
1038 
1039 	for (row = map; row->string != NULL; row++) {
1040 		if (row->type == type) {
1041 			return row->string;
1042 		}
1043 	}
1044 	return NULL;
1045 }
1046 
1047 /**
1048  * \ingroup Core_Print
1049  *
1050  * Searches the given map for the given type.
1051  * Returns a readable string if found, "Unknown" if not.
1052  */
1053 
1054 const char     *
1055 __ops_str_from_map(int type, __ops_map_t *map)
1056 {
1057 	const char     *str;
1058 
1059 	str = str_from_map_or_null(type, map);
1060 	return (str) ? str : "Unknown";
1061 }
1062 
1063 void
1064 hexdump(FILE *fp, const unsigned char *src, size_t length, const char *sep)
1065 {
1066 	unsigned i;
1067 
1068 	for (i = 0 ; i < length ; i += 2) {
1069 		(void) fprintf(fp, "%02x", *src++);
1070 		(void) fprintf(fp, "%02x%s", *src++, sep);
1071 	}
1072 }
1073 
1074 /**
1075  * \ingroup HighLevel_Functions
1076  * \brief Initialises OpenPGP::SDK. To be called before any other OPS function.
1077  *
1078  * Initialises OpenPGP::SDK and the underlying openssl library.
1079  */
1080 
1081 void
1082 __ops_init(void)
1083 {
1084 	__ops_crypto_init();
1085 }
1086 
1087 /**
1088  * \ingroup HighLevel_Functions
1089  * \brief Closes down OpenPGP::SDK.
1090  *
1091  * Close down OpenPGP:SDK, release any resources under the control of
1092  * the library. No OpenPGP:SDK function other than __ops_init() should
1093  * be called after this function.
1094  */
1095 
1096 void
1097 __ops_finish(void)
1098 {
1099 	__ops_crypto_finish();
1100 }
1101 
1102 static int
1103 sum16_reader(void *dest_, size_t length, __ops_error_t **errors,
1104 	     __ops_reader_t *readinfo, __ops_cbdata_t *cbinfo)
1105 {
1106 	const unsigned char	*dest = dest_;
1107 	sum16_t			*arg = __ops_reader_get_arg(readinfo);
1108 	int			 r;
1109 	int			 n;
1110 
1111 	r = __ops_stacked_read(dest_, length, errors, readinfo, cbinfo);
1112 	if (r < 0) {
1113 		return r;
1114 	}
1115 	for (n = 0; n < r; ++n) {
1116 		arg->sum = (arg->sum + dest[n]) & 0xffff;
1117 	}
1118 	return r;
1119 }
1120 
1121 static void
1122 sum16_destroyer(__ops_reader_t *readinfo)
1123 {
1124 	free(__ops_reader_get_arg(readinfo));
1125 }
1126 
1127 /**
1128    \ingroup Internal_Readers_Sum16
1129    \param stream Parse settings
1130 */
1131 
1132 void
1133 __ops_reader_push_sum16(__ops_stream_t *stream)
1134 {
1135 	sum16_t    *arg;
1136 
1137 	if ((arg = calloc(1, sizeof(*arg))) == NULL) {
1138 		(void) fprintf(stderr, "__ops_reader_push_sum16: bad alloc\n");
1139 	} else {
1140 		__ops_reader_push(stream, sum16_reader, sum16_destroyer, arg);
1141 	}
1142 }
1143 
1144 /**
1145    \ingroup Internal_Readers_Sum16
1146    \param stream Parse settings
1147    \return sum
1148 */
1149 unsigned short
1150 __ops_reader_pop_sum16(__ops_stream_t *stream)
1151 {
1152 	unsigned short	 sum;
1153 	sum16_t		*arg;
1154 
1155 	arg = __ops_reader_get_arg(__ops_readinfo(stream));
1156 	sum = arg->sum;
1157 	__ops_reader_pop(stream);
1158 	free(arg);
1159 	return sum;
1160 }
1161 
1162 /* small useful functions for setting the file-level debugging levels */
1163 /* if the debugv list contains the filename in question, we're debugging it */
1164 
1165 enum {
1166 	MAX_DEBUG_NAMES = 32
1167 };
1168 
1169 static int      debugc;
1170 static char    *debugv[MAX_DEBUG_NAMES];
1171 
1172 /* set the debugging level per filename */
1173 int
1174 __ops_set_debug_level(const char *f)
1175 {
1176 	const char     *name;
1177 	int             i;
1178 
1179 	if (f == NULL) {
1180 		f = "all";
1181 	}
1182 	if ((name = strrchr(f, '/')) == NULL) {
1183 		name = f;
1184 	} else {
1185 		name += 1;
1186 	}
1187 	for (i = 0; i < debugc && i < MAX_DEBUG_NAMES; i++) {
1188 		if (strcmp(debugv[i], name) == 0) {
1189 			return 1;
1190 		}
1191 	}
1192 	if (i == MAX_DEBUG_NAMES) {
1193 		return 0;
1194 	}
1195 	debugv[debugc++] = strdup(name);
1196 	return 1;
1197 }
1198 
1199 /* get the debugging level per filename */
1200 int
1201 __ops_get_debug_level(const char *f)
1202 {
1203 	const char     *name;
1204 	int             i;
1205 
1206 	if ((name = strrchr(f, '/')) == NULL) {
1207 		name = f;
1208 	} else {
1209 		name += 1;
1210 	}
1211 	for (i = 0; i < debugc; i++) {
1212 		if (strcmp(debugv[i], "all") == 0 ||
1213 		    strcmp(debugv[i], name) == 0) {
1214 			return 1;
1215 		}
1216 	}
1217 	return 0;
1218 }
1219 
1220 /* return the version for the library */
1221 const char *
1222 __ops_get_info(const char *type)
1223 {
1224 	if (strcmp(type, "version") == 0) {
1225 		return NETPGP_VERSION_STRING;
1226 	}
1227 	if (strcmp(type, "maintainer") == 0) {
1228 		return NETPGP_MAINTAINER;
1229 	}
1230 	return "[unknown]";
1231 }
1232 
1233 void
1234 netpgp_log(const char *fmt, ...)
1235 {
1236 	va_list	 vp;
1237 	time_t	 t;
1238 	char	 buf[BUFSIZ * 2];
1239 	char	*cp;
1240 	int	 cc;
1241 
1242 	(void) time(&t);
1243 	cp = ctime(&t);
1244 	cc = snprintf(buf, sizeof(buf), "%.24s: netpgp: ", cp);
1245 	va_start(vp, fmt);
1246 	(void) vsnprintf(&buf[cc], sizeof(buf) - (size_t)cc, fmt, vp);
1247 	va_end(vp);
1248 	/* do something with message */
1249 	/* put into log buffer? */
1250 }
1251