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