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