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