xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/misc.c (revision da9817918ec7e88db2912a2882967c7570a83f47)
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.20 2009/06/11 01:12:42 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 %d - tag %d\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(__ops_error_t))) == 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 		(void) free(errstack->comment);
410 		(void) 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 		md5.init(&md5);
443 
444 		n = BN_num_bytes(key->key.rsa.n);
445 		bn = calloc(1, n);
446 		BN_bn2bin(key->key.rsa.n, bn);
447 		md5.add(&md5, bn, n);
448 		(void) free(bn);
449 
450 		n = BN_num_bytes(key->key.rsa.e);
451 		bn = calloc(1, n);
452 		BN_bn2bin(key->key.rsa.e, bn);
453 		md5.add(&md5, bn, n);
454 		(void) free(bn);
455 
456 		md5.finish(&md5, fp->fingerprint);
457 		fp->length = 16;
458 	} else {
459 		__ops_memory_t	*mem = __ops_memory_new();
460 		__ops_hash_t	 sha1;
461 		size_t		 len;
462 
463 		__ops_build_pubkey(mem, key, 0);
464 
465 		if (__ops_get_debug_level(__FILE__)) {
466 			fprintf(stderr, "-> creating key fingerprint\n");
467 		}
468 		__ops_hash_sha1(&sha1);
469 		sha1.init(&sha1);
470 
471 		len = __ops_mem_len(mem);
472 
473 		__ops_hash_add_int(&sha1, 0x99, 1);
474 		__ops_hash_add_int(&sha1, len, 2);
475 		sha1.add(&sha1, __ops_mem_data(mem), len);
476 		sha1.finish(&sha1, fp->fingerprint);
477 
478 		if (__ops_get_debug_level(__FILE__)) {
479 			fprintf(stderr, "<- finished making key fingerprint\n");
480 		}
481 		fp->length = OPS_FINGERPRINT_SIZE;
482 
483 		__ops_memory_free(mem);
484 	}
485 }
486 
487 /**
488  * \ingroup Core_Keys
489  * \brief Calculate the Key ID from the public key.
490  * \param keyid Space for the calculated ID to be stored
491  * \param key The key for which the ID is calculated
492  */
493 
494 void
495 __ops_keyid(unsigned char *keyid, const size_t idlen, const __ops_pubkey_t *key)
496 {
497 	if (key->version == 2 || key->version == 3) {
498 		unsigned char   bn[NETPGP_BUFSIZ];
499 		unsigned        n = BN_num_bytes(key->key.rsa.n);
500 
501 		if (n > sizeof(bn)) {
502 			(void) fprintf(stderr, "__ops_keyid: bad num bytes\n");
503 			return;
504 		}
505 		if (key->alg != OPS_PKA_RSA &&
506 		    key->alg != OPS_PKA_RSA_ENCRYPT_ONLY &&
507 		    key->alg != OPS_PKA_RSA_SIGN_ONLY) {
508 			(void) fprintf(stderr, "__ops_keyid: bad algorithm\n");
509 			return;
510 		}
511 		BN_bn2bin(key->key.rsa.n, bn);
512 		(void) memcpy(keyid, bn + n - idlen, idlen);
513 	} else {
514 		__ops_fingerprint_t finger;
515 
516 		__ops_fingerprint(&finger, key);
517 		(void) memcpy(keyid,
518 				finger.fingerprint + finger.length - idlen,
519 				idlen);
520 	}
521 }
522 
523 /**
524 \ingroup Core_Hashes
525 \brief Add to the hash
526 \param hash Hash to add to
527 \param n Int to add
528 \param length Length of int in bytes
529 */
530 void
531 __ops_hash_add_int(__ops_hash_t *hash, unsigned n, unsigned length)
532 {
533 	while (length--) {
534 		unsigned char   c;
535 
536 		c = n >> (length * 8);
537 		hash->add(hash, &c, 1);
538 	}
539 }
540 
541 /**
542 \ingroup Core_Hashes
543 \brief Setup hash for given hash algorithm
544 \param hash Hash to set up
545 \param alg Hash algorithm to use
546 */
547 void
548 __ops_hash_any(__ops_hash_t *hash, __ops_hash_alg_t alg)
549 {
550 	switch (alg) {
551 	case OPS_HASH_MD5:
552 		__ops_hash_md5(hash);
553 		break;
554 
555 	case OPS_HASH_SHA1:
556 		__ops_hash_sha1(hash);
557 		break;
558 
559 	case OPS_HASH_SHA256:
560 		__ops_hash_sha256(hash);
561 		break;
562 
563 	case OPS_HASH_SHA384:
564 		__ops_hash_sha384(hash);
565 		break;
566 
567 	case OPS_HASH_SHA512:
568 		__ops_hash_sha512(hash);
569 		break;
570 
571 	case OPS_HASH_SHA224:
572 		__ops_hash_sha224(hash);
573 		break;
574 
575 	default:
576 		(void) fprintf(stderr, "__ops_hash_any: bad algorithm\n");
577 	}
578 }
579 
580 /**
581 \ingroup Core_Hashes
582 \brief Returns size of hash for given hash algorithm
583 \param alg Hash algorithm to use
584 \return Size of hash algorithm in bytes
585 */
586 unsigned
587 __ops_hash_size(__ops_hash_alg_t alg)
588 {
589 	switch (alg) {
590 	case OPS_HASH_MD5:
591 		return 16;
592 
593 	case OPS_HASH_SHA1:
594 		return 20;
595 
596 	case OPS_HASH_SHA256:
597 		return 32;
598 
599 	case OPS_HASH_SHA224:
600 		return 28;
601 
602 	case OPS_HASH_SHA512:
603 		return 64;
604 
605 	case OPS_HASH_SHA384:
606 		return 48;
607 
608 	default:
609 		(void) fprintf(stderr, "__ops_hash_size: bad algorithm\n");
610 	}
611 
612 	return 0;
613 }
614 
615 /**
616 \ingroup Core_Hashes
617 \brief Returns hash enum corresponding to given string
618 \param hash Text name of hash algorithm i.e. "SHA1"
619 \returns Corresponding enum i.e. OPS_HASH_SHA1
620 */
621 __ops_hash_alg_t
622 __ops_str_to_hash_alg(const char *hash)
623 {
624 	if (strcmp(hash, "SHA1") == 0) {
625 		return OPS_HASH_SHA1;
626 	}
627 	if (strcmp(hash, "MD5") == 0) {
628 		return OPS_HASH_MD5;
629 	}
630 	if (strcmp(hash, "SHA256") == 0) {
631 		return OPS_HASH_SHA256;
632 	}
633 	/*
634         if (strcmp(hash,"SHA224") == 0) {
635 		return OPS_HASH_SHA224;
636 	}
637         */
638 	if (strcmp(hash, "SHA512") == 0) {
639 		return OPS_HASH_SHA512;
640 	}
641 	if (strcmp(hash, "SHA384") == 0) {
642 		return OPS_HASH_SHA384;
643 	}
644 	return OPS_HASH_UNKNOWN;
645 }
646 
647 /**
648 \ingroup Core_Hashes
649 \brief Hash given data
650 \param out Where to write the hash
651 \param alg Hash algorithm to use
652 \param in Data to hash
653 \param length Length of data
654 \return Size of hash created
655 */
656 unsigned
657 __ops_hash(unsigned char *out, __ops_hash_alg_t alg, const void *in,
658 	 size_t length)
659 {
660 	__ops_hash_t      hash;
661 
662 	__ops_hash_any(&hash, alg);
663 	hash.init(&hash);
664 	hash.add(&hash, in, length);
665 	return hash.finish(&hash, out);
666 }
667 
668 /**
669 \ingroup Core_Hashes
670 \brief Calculate hash for MDC packet
671 \param preamble Preamble to hash
672 \param sz_preamble Size of preamble
673 \param plaintext Plaintext to hash
674 \param sz_plaintext Size of plaintext
675 \param hashed Resulting hash
676 */
677 void
678 __ops_calc_mdc_hash(const unsigned char *preamble,
679 			const size_t sz_preamble,
680 			const unsigned char *plaintext,
681 			const unsigned int sz_plaintext,
682 			unsigned char *hashed)
683 {
684 	unsigned char	c;
685 	__ops_hash_t	hash;
686 
687 	if (__ops_get_debug_level(__FILE__)) {
688 		unsigned int    i = 0;
689 
690 		(void) fprintf(stderr, "__ops_calc_mdc_hash():\n");
691 		(void) fprintf(stderr, "\npreamble: ");
692 		for (i = 0; i < sz_preamble; i++)
693 			(void) fprintf(stderr, " 0x%02x", preamble[i]);
694 		(void) fprintf(stderr, "\n");
695 		(void) fprintf(stderr, "\nplaintext (len=%d): ", sz_plaintext);
696 		for (i = 0; i < sz_plaintext; i++)
697 			(void) fprintf(stderr, " 0x%02x", plaintext[i]);
698 		(void) fprintf(stderr, "\n");
699 	}
700 	/* init */
701 	__ops_hash_any(&hash, OPS_HASH_SHA1);
702 	hash.init(&hash);
703 
704 	/* preamble */
705 	hash.add(&hash, preamble, sz_preamble);
706 	/* plaintext */
707 	hash.add(&hash, plaintext, sz_plaintext);
708 	/* MDC packet tag */
709 	c = MDC_PKT_TAG;
710 	hash.add(&hash, &c, 1);
711 	/* MDC packet len */
712 	c = OPS_SHA1_HASH_SIZE;
713 	hash.add(&hash, &c, 1);
714 
715 	/* finish */
716 	hash.finish(&hash, hashed);
717 
718 	if (__ops_get_debug_level(__FILE__)) {
719 		unsigned int    i = 0;
720 
721 		(void) fprintf(stderr, "\nhashed (len=%d): ",
722 				OPS_SHA1_HASH_SIZE);
723 		for (i = 0; i < OPS_SHA1_HASH_SIZE; i++) {
724 			(void) fprintf(stderr, " 0x%02x", hashed[i]);
725 		}
726 		(void) fprintf(stderr, "\n");
727 	}
728 }
729 
730 /**
731 \ingroup HighLevel_Supported
732 \brief Is this Hash Algorithm supported?
733 \param hash_alg Hash Algorithm to check
734 \return 1 if supported; else 0
735 */
736 unsigned
737 __ops_is_hash_alg_supported(const __ops_hash_alg_t *hash_alg)
738 {
739 	switch (*hash_alg) {
740 	case OPS_HASH_MD5:
741 	case OPS_HASH_SHA1:
742 	case OPS_HASH_SHA256:
743 		return 1;
744 
745 	default:
746 		return 0;
747 	}
748 }
749 
750 void
751 __ops_random(void *dest, size_t length)
752 {
753 	RAND_bytes(dest, (int)length);
754 }
755 
756 /**
757 \ingroup HighLevel_Memory
758 \brief Memory to initialise
759 \param mem memory to initialise
760 \param needed Size to initialise to
761 */
762 void
763 __ops_memory_init(__ops_memory_t *mem, size_t needed)
764 {
765 	mem->length = 0;
766 	if (mem->buf) {
767 		if (mem->allocated < needed) {
768 			mem->buf = realloc(mem->buf, needed);
769 			mem->allocated = needed;
770 		}
771 		return;
772 	}
773 	mem->buf = calloc(1, needed);
774 	mem->allocated = needed;
775 }
776 
777 /**
778 \ingroup HighLevel_Memory
779 \brief Pad memory to required length
780 \param mem Memory to use
781 \param length New size
782 */
783 void
784 __ops_memory_pad(__ops_memory_t *mem, size_t length)
785 {
786 	if (mem->allocated < mem->length) {
787 		(void) fprintf(stderr, "__ops_memory_pad: bad alloc in\n");
788 		return;
789 	}
790 	if (mem->allocated < mem->length + length) {
791 		mem->allocated = mem->allocated * 2 + length;
792 		mem->buf = realloc(mem->buf, mem->allocated);
793 	}
794 	if (mem->allocated < mem->length + length) {
795 		(void) fprintf(stderr, "__ops_memory_pad: bad alloc out\n");
796 	}
797 }
798 
799 /**
800 \ingroup HighLevel_Memory
801 \brief Add data to memory
802 \param mem Memory to which to add
803 \param src Data to add
804 \param length Length of data to add
805 */
806 void
807 __ops_memory_add(__ops_memory_t *mem, const unsigned char *src, size_t length)
808 {
809 	__ops_memory_pad(mem, length);
810 	(void) memcpy(mem->buf + mem->length, src, length);
811 	mem->length += length;
812 }
813 
814 /* XXX: this could be refactored via the writer, but an awful lot of */
815 /* hoops to jump through for 2 lines of code! */
816 void
817 __ops_memory_place_int(__ops_memory_t *mem, unsigned offset, unsigned n,
818 		     size_t length)
819 {
820 	if (mem->allocated < offset + length) {
821 		(void) fprintf(stderr,
822 			"__ops_memory_place_int: bad alloc\n");
823 	} else {
824 		while (length-- > 0) {
825 			mem->buf[offset++] = n >> (length * 8);
826 		}
827 	}
828 }
829 
830 /**
831  * \ingroup HighLevel_Memory
832  * \brief Retains allocated memory and set length of stored data to zero.
833  * \param mem Memory to clear
834  * \sa __ops_memory_release()
835  * \sa __ops_memory_free()
836  */
837 void
838 __ops_memory_clear(__ops_memory_t *mem)
839 {
840 	mem->length = 0;
841 }
842 
843 /**
844 \ingroup HighLevel_Memory
845 \brief Free memory and associated data
846 \param mem Memory to free
847 \note This does not free mem itself
848 \sa __ops_memory_clear()
849 \sa __ops_memory_free()
850 */
851 void
852 __ops_memory_release(__ops_memory_t *mem)
853 {
854 	if (mem->mmapped) {
855 		(void) munmap(mem->buf, mem->length);
856 	} else {
857 		(void) free(mem->buf);
858 	}
859 	mem->buf = NULL;
860 	mem->length = 0;
861 }
862 
863 void
864 __ops_memory_make_packet(__ops_memory_t *out, __ops_content_tag_t tag)
865 {
866 	size_t          extra;
867 
868 	extra = (out->length < 192) ? 1 : (out->length < 8192 + 192) ? 2 : 5;
869 	__ops_memory_pad(out, extra + 1);
870 	memmove(out->buf + extra + 1, out->buf, out->length);
871 
872 	out->buf[0] = OPS_PTAG_ALWAYS_SET | OPS_PTAG_NEW_FORMAT | tag;
873 
874 	if (out->length < 192) {
875 		out->buf[1] = out->length;
876 	} else if (out->length < 8192 + 192) {
877 		out->buf[1] = ((out->length - 192) >> 8) + 192;
878 		out->buf[2] = out->length - 192;
879 	} else {
880 		out->buf[1] = 0xff;
881 		out->buf[2] = out->length >> 24;
882 		out->buf[3] = out->length >> 16;
883 		out->buf[4] = out->length >> 8;
884 		out->buf[5] = out->length;
885 	}
886 
887 	out->length += extra + 1;
888 }
889 
890 /**
891    \ingroup HighLevel_Memory
892    \brief Create a new zeroed __ops_memory_t
893    \return Pointer to new __ops_memory_t
894    \note Free using __ops_memory_free() after use.
895    \sa __ops_memory_free()
896 */
897 
898 __ops_memory_t   *
899 __ops_memory_new(void)
900 {
901 	return calloc(1, sizeof(__ops_memory_t));
902 }
903 
904 /**
905    \ingroup HighLevel_Memory
906    \brief Free memory ptr and associated memory
907    \param mem Memory to be freed
908    \sa __ops_memory_release()
909    \sa __ops_memory_clear()
910 */
911 
912 void
913 __ops_memory_free(__ops_memory_t *mem)
914 {
915 	__ops_memory_release(mem);
916 	(void) free(mem);
917 }
918 
919 /**
920    \ingroup HighLevel_Memory
921    \brief Get length of data stored in __ops_memory_t struct
922    \return Number of bytes in data
923 */
924 size_t
925 __ops_mem_len(const __ops_memory_t *mem)
926 {
927 	return mem->length;
928 }
929 
930 /**
931    \ingroup HighLevel_Memory
932    \brief Get data stored in __ops_memory_t struct
933    \return Pointer to data
934 */
935 void *
936 __ops_mem_data(__ops_memory_t *mem)
937 {
938 	return mem->buf;
939 }
940 
941 /* read a gile into an __ops_memory_t */
942 int
943 __ops_mem_readfile(__ops_memory_t *mem, const char *f)
944 {
945 	struct stat	 st;
946 	FILE		*fp;
947 	int		 cc;
948 
949 	if ((fp = fopen(f, "rb")) == NULL) {
950 		(void) fprintf(stderr,
951 				"__ops_mem_readfile: can't open \"%s\"\n", f);
952 		return 0;
953 	}
954 	(void) fstat(fileno(fp), &st);
955 	mem->allocated = (size_t)st.st_size;
956 	mem->buf = mmap(NULL, mem->allocated, PROT_READ,
957 				MAP_FILE | MAP_PRIVATE, fileno(fp), 0);
958 	if (mem->buf == MAP_FAILED) {
959 		/* mmap failed for some reason - try to allocate memory */
960 		if ((mem->buf = calloc(1, mem->allocated)) == NULL) {
961 			(void) fprintf(stderr, "__ops_mem_readfile: calloc\n");
962 			(void) fclose(fp);
963 			return 0;
964 		}
965 		/* read into contents of mem */
966 		for (mem->length = 0 ;
967 		     (cc = read(fileno(fp), &mem->buf[mem->length],
968 					mem->allocated - mem->length)) > 0 ;
969 		     mem->length += (size_t)cc) {
970 		}
971 	} else {
972 		mem->length = mem->allocated;
973 		mem->mmapped = 1;
974 	}
975 	(void) fclose(fp);
976 	return (mem->allocated == mem->length);
977 }
978 
979 typedef struct {
980 	unsigned short  sum;
981 } sum16_t;
982 
983 
984 /**
985  * Searches the given map for the given type.
986  * Returns a human-readable descriptive string if found,
987  * returns NULL if not found
988  *
989  * It is the responsibility of the calling function to handle the
990  * error case sensibly (i.e. don't just print out the return string.
991  *
992  */
993 static const char *
994 str_from_map_or_null(int type, __ops_map_t *map)
995 {
996 	__ops_map_t      *row;
997 
998 	for (row = map; row->string != NULL; row++) {
999 		if (row->type == type) {
1000 			return row->string;
1001 		}
1002 	}
1003 	return NULL;
1004 }
1005 
1006 /**
1007  * \ingroup Core_Print
1008  *
1009  * Searches the given map for the given type.
1010  * Returns a readable string if found, "Unknown" if not.
1011  */
1012 
1013 const char     *
1014 __ops_str_from_map(int type, __ops_map_t *map)
1015 {
1016 	const char     *str;
1017 
1018 	str = str_from_map_or_null(type, map);
1019 	return (str) ? str : "Unknown";
1020 }
1021 
1022 void
1023 hexdump(FILE *fp, const unsigned char *src, size_t length, const char *sep)
1024 {
1025 	unsigned i;
1026 
1027 	for (i = 0 ; i < length ; i += 2) {
1028 		(void) fprintf(fp, "%02x", *src++);
1029 		(void) fprintf(fp, "%02x%s", *src++, sep);
1030 	}
1031 }
1032 
1033 /**
1034  * \ingroup HighLevel_Functions
1035  * \brief Initialises OpenPGP::SDK. To be called before any other OPS function.
1036  *
1037  * Initialises OpenPGP::SDK and the underlying openssl library.
1038  */
1039 
1040 void
1041 __ops_init(void)
1042 {
1043 	__ops_crypto_init();
1044 }
1045 
1046 /**
1047  * \ingroup HighLevel_Functions
1048  * \brief Closes down OpenPGP::SDK.
1049  *
1050  * Close down OpenPGP:SDK, release any resources under the control of
1051  * the library. No OpenPGP:SDK function other than __ops_init() should
1052  * be called after this function.
1053  */
1054 
1055 void
1056 __ops_finish(void)
1057 {
1058 	__ops_crypto_finish();
1059 }
1060 
1061 static int
1062 sum16_reader(void *dest_, size_t length, __ops_error_t **errors,
1063 	     __ops_reader_t *readinfo, __ops_cbdata_t *cbinfo)
1064 {
1065 	const unsigned char	*dest = dest_;
1066 	sum16_t			*arg = __ops_reader_get_arg(readinfo);
1067 	int			 r;
1068 	int			 n;
1069 
1070 	r = __ops_stacked_read(dest_, length, errors, readinfo, cbinfo);
1071 	if (r < 0) {
1072 		return r;
1073 	}
1074 	for (n = 0; n < r; ++n) {
1075 		arg->sum = (arg->sum + dest[n]) & 0xffff;
1076 	}
1077 	return r;
1078 }
1079 
1080 static void
1081 sum16_destroyer(__ops_reader_t *readinfo)
1082 {
1083 	(void) free(__ops_reader_get_arg(readinfo));
1084 }
1085 
1086 /**
1087    \ingroup Internal_Readers_Sum16
1088    \param stream Parse settings
1089 */
1090 
1091 void
1092 __ops_reader_push_sum16(__ops_stream_t *stream)
1093 {
1094 	sum16_t    *arg = calloc(1, sizeof(*arg));
1095 
1096 	__ops_reader_push(stream, sum16_reader, sum16_destroyer, arg);
1097 }
1098 
1099 /**
1100    \ingroup Internal_Readers_Sum16
1101    \param stream Parse settings
1102    \return sum
1103 */
1104 unsigned short
1105 __ops_reader_pop_sum16(__ops_stream_t *stream)
1106 {
1107 	unsigned short	 sum;
1108 	sum16_t		*arg;
1109 
1110 	arg = __ops_reader_get_arg(__ops_readinfo(stream));
1111 	sum = arg->sum;
1112 	__ops_reader_pop(stream);
1113 	free(arg);
1114 	return sum;
1115 }
1116 
1117 /* small useful functions for setting the file-level debugging levels */
1118 /* if the debugv list contains the filename in question, we're debugging it */
1119 
1120 enum {
1121 	MAX_DEBUG_NAMES = 32
1122 };
1123 
1124 static int      debugc;
1125 static char    *debugv[MAX_DEBUG_NAMES];
1126 
1127 /* set the debugging level per filename */
1128 int
1129 __ops_set_debug_level(const char *f)
1130 {
1131 	const char     *name;
1132 	int             i;
1133 
1134 	if (f == NULL) {
1135 		f = "all";
1136 	}
1137 	if ((name = strrchr(f, '/')) == NULL) {
1138 		name = f;
1139 	} else {
1140 		name += 1;
1141 	}
1142 	for (i = 0; i < debugc && i < MAX_DEBUG_NAMES; i++) {
1143 		if (strcmp(debugv[i], name) == 0) {
1144 			return 1;
1145 		}
1146 	}
1147 	if (i == MAX_DEBUG_NAMES) {
1148 		return 0;
1149 	}
1150 	debugv[debugc++] = strdup(name);
1151 	return 1;
1152 }
1153 
1154 /* get the debugging level per filename */
1155 int
1156 __ops_get_debug_level(const char *f)
1157 {
1158 	const char     *name;
1159 	int             i;
1160 
1161 	if ((name = strrchr(f, '/')) == NULL) {
1162 		name = f;
1163 	} else {
1164 		name += 1;
1165 	}
1166 	for (i = 0; i < debugc; i++) {
1167 		if (strcmp(debugv[i], "all") == 0 ||
1168 		    strcmp(debugv[i], name) == 0) {
1169 			return 1;
1170 		}
1171 	}
1172 	return 0;
1173 }
1174 
1175 /* return the version for the library */
1176 const char *
1177 __ops_get_info(const char *type)
1178 {
1179 	if (strcmp(type, "version") == 0) {
1180 		return NETPGP_VERSION_STRING;
1181 	}
1182 	if (strcmp(type, "maintainer") == 0) {
1183 		return NETPGP_MAINTAINER;
1184 	}
1185 	return "[unknown]";
1186 }
1187 
1188 void
1189 netpgp_log(const char *fmt, ...)
1190 {
1191 	va_list	 vp;
1192 	time_t	 t;
1193 	char	 buf[BUFSIZ * 2];
1194 	char	*cp;
1195 	int	 cc;
1196 
1197 	(void) time(&t);
1198 	cp = ctime(&t);
1199 	cc = snprintf(buf, sizeof(buf), "%.24s: netpgp: ", cp);
1200 	va_start(vp, fmt);
1201 	(void) vsnprintf(&buf[cc], sizeof(buf) - cc, fmt, vp);
1202 	va_end(vp);
1203 	/* do something with message */
1204 	/* put into log buffer? */
1205 }
1206