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