xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/reader.c (revision 7f21db1c0118155e0dd40b75182e30c589d9f63e)
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 #include "config.h"
50 
51 #ifdef HAVE_SYS_CDEFS_H
52 #include <sys/cdefs.h>
53 #endif
54 
55 #if defined(__NetBSD__)
56 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
57 __RCSID("$NetBSD: reader.c,v 1.29 2010/02/08 17:19:12 agc Exp $");
58 #endif
59 
60 #include <sys/types.h>
61 #include <sys/stat.h>
62 
63 #ifdef HAVE_SYS_MMAN_H
64 #include <sys/mman.h>
65 #endif
66 
67 #ifdef HAVE_SYS_PARAM_H
68 #include <sys/param.h>
69 #endif
70 
71 #ifdef HAVE_FCNTL_H
72 #include <fcntl.h>
73 #endif
74 
75 #ifdef HAVE_UNISTD_H
76 #include <unistd.h>
77 #endif
78 
79 #ifdef HAVE_DIRECT_H
80 #include <direct.h>
81 #endif
82 
83 #ifdef HAVE_INTTYPES_H
84 #include <inttypes.h>
85 #endif
86 
87 #ifdef HAVE_OPENSSL_IDEA_H
88 #include <openssl/cast.h>
89 #endif
90 
91 #ifdef HAVE_OPENSSL_IDEA_H
92 #include <openssl/idea.h>
93 #endif
94 
95 #ifdef HAVE_OPENSSL_AES_H
96 #include <openssl/aes.h>
97 #endif
98 
99 #ifdef HAVE_OPENSSL_DES_H
100 #include <openssl/des.h>
101 #endif
102 
103 #include <string.h>
104 #include <stdlib.h>
105 #include <stdio.h>
106 
107 #ifdef HAVE_TERMIOS_H
108 #include <termios.h>
109 #endif
110 
111 #ifdef HAVE_ERRNO_H
112 #include <errno.h>
113 #endif
114 
115 #ifdef HAVE_UNISTD_H
116 #include <unistd.h>
117 #endif
118 
119 #ifdef HAVE_LIMITS_H
120 #include <limits.h>
121 #endif
122 
123 #include "errors.h"
124 #include "crypto.h"
125 #include "create.h"
126 #include "signature.h"
127 #include "packet.h"
128 #include "packet-parse.h"
129 #include "packet-show.h"
130 #include "packet.h"
131 #include "keyring.h"
132 #include "readerwriter.h"
133 #include "netpgpdefs.h"
134 #include "netpgpdigest.h"
135 
136 
137 /* get a pass phrase from the user */
138 int
139 __ops_getpassphrase(void *in, char *phrase, size_t size)
140 {
141 	char	*p;
142 
143 	if (in == NULL) {
144 		while ((p = getpass("netpgp passphrase: ")) == NULL) {
145 		}
146 		(void) snprintf(phrase, size, "%s", p);
147 	} else {
148 		if (fgets(phrase, (int)size, in) == NULL) {
149 			return 0;
150 		}
151 		phrase[strlen(phrase) - 1] = 0x0;
152 	}
153 	return 1;
154 }
155 
156 /**
157  * \ingroup Internal_Readers_Generic
158  * \brief Starts reader stack
159  * \param stream Parse settings
160  * \param reader Reader to use
161  * \param destroyer Destroyer to use
162  * \param vp Reader-specific arg
163  */
164 void
165 __ops_reader_set(__ops_stream_t *stream,
166 		__ops_reader_func_t *reader,
167 		__ops_reader_destroyer_t *destroyer,
168 		void *vp)
169 {
170 	stream->readinfo.reader = reader;
171 	stream->readinfo.destroyer = destroyer;
172 	stream->readinfo.arg = vp;
173 }
174 
175 /**
176  * \ingroup Internal_Readers_Generic
177  * \brief Adds to reader stack
178  * \param stream Parse settings
179  * \param reader Reader to use
180  * \param destroyer Reader's destroyer
181  * \param vp Reader-specific arg
182  */
183 void
184 __ops_reader_push(__ops_stream_t *stream,
185 		__ops_reader_func_t *reader,
186 		__ops_reader_destroyer_t *destroyer,
187 		void *vp)
188 {
189 	__ops_reader_t *readinfo;
190 
191 	if ((readinfo = calloc(1, sizeof(*readinfo))) == NULL) {
192 		(void) fprintf(stderr, "__ops_reader_push: bad alloc\n");
193 	} else {
194 		*readinfo = stream->readinfo;
195 		(void) memset(&stream->readinfo, 0x0, sizeof(stream->readinfo));
196 		stream->readinfo.next = readinfo;
197 		stream->readinfo.parent = stream;
198 
199 		/* should copy accumulate flags from other reader? RW */
200 		stream->readinfo.accumulate = readinfo->accumulate;
201 
202 		__ops_reader_set(stream, reader, destroyer, vp);
203 	}
204 }
205 
206 /**
207  * \ingroup Internal_Readers_Generic
208  * \brief Removes from reader stack
209  * \param stream Parse settings
210  */
211 void
212 __ops_reader_pop(__ops_stream_t *stream)
213 {
214 	__ops_reader_t *next = stream->readinfo.next;
215 
216 	stream->readinfo = *next;
217 	free(next);
218 }
219 
220 /**
221  * \ingroup Internal_Readers_Generic
222  * \brief Gets arg from reader
223  * \param readinfo Reader info
224  * \return Pointer to reader info's arg
225  */
226 void           *
227 __ops_reader_get_arg(__ops_reader_t *readinfo)
228 {
229 	return readinfo->arg;
230 }
231 
232 /**************************************************************************/
233 
234 #define CRC24_POLY 0x1864cfbL
235 
236 enum {
237 	NONE = 0,
238 	BEGIN_PGP_MESSAGE,
239 	BEGIN_PGP_PUBLIC_KEY_BLOCK,
240 	BEGIN_PGP_PRIVATE_KEY_BLOCK,
241 	BEGIN_PGP_MULTI,
242 	BEGIN_PGP_SIGNATURE,
243 
244 	END_PGP_MESSAGE,
245 	END_PGP_PUBLIC_KEY_BLOCK,
246 	END_PGP_PRIVATE_KEY_BLOCK,
247 	END_PGP_MULTI,
248 	END_PGP_SIGNATURE,
249 
250 	BEGIN_PGP_SIGNED_MESSAGE
251 };
252 
253 /**
254  * \struct dearmour_t
255  */
256 typedef struct {
257 	enum {
258 		OUTSIDE_BLOCK = 0,
259 		BASE64,
260 		AT_TRAILER_NAME
261 	} state;
262 	int		lastseen;
263 	__ops_stream_t *parse_info;
264 	unsigned	seen_nl:1;
265 	unsigned	prev_nl:1;
266 	unsigned	allow_headers_without_gap:1;
267 			/* !< allow headers in armoured data that are
268 			* not separated from the data by a blank line
269 			* */
270 	unsigned	allow_no_gap:1;
271 			/* !< allow no blank line at the start of
272 			* armoured data */
273 	unsigned	allow_trailing_whitespace:1;
274 			/* !< allow armoured stuff to have trailing
275 			* whitespace where we wouldn't strictly expect
276 			* it */
277 	/* it is an error to get a cleartext message without a sig */
278 	unsigned   	expect_sig:1;
279 	unsigned   	got_sig:1;
280 	/* base64 stuff */
281 	unsigned        buffered;
282 	unsigned char   buffer[3];
283 	unsigned	eof64;
284 	unsigned long   checksum;
285 	unsigned long   read_checksum;
286 	/* unarmoured text blocks */
287 	unsigned char   unarmoured[NETPGP_BUFSIZ];
288 	size_t          unarmoredc;
289 	/* pushed back data (stored backwards) */
290 	unsigned char  *pushback;
291 	unsigned        pushbackc;
292 	/* armoured block headers */
293 	__ops_headers_t	headers;
294 } dearmour_t;
295 
296 static void
297 push_back(dearmour_t *dearmour, const unsigned char *buf,
298 	  unsigned length)
299 {
300 	unsigned        n;
301 
302 	if (dearmour->pushback) {
303 		(void) fprintf(stderr, "push_back: already pushed back\n");
304 	} else if ((dearmour->pushback = calloc(1, length)) == NULL) {
305 		(void) fprintf(stderr, "push_back: bad alloc\n");
306 	} else {
307 		for (n = 0; n < length; ++n) {
308 			dearmour->pushback[n] = buf[(length - n) - 1];
309 		}
310 		dearmour->pushbackc = length;
311 	}
312 }
313 
314 /* this struct holds a textual header line */
315 typedef struct headerline_t {
316 	const char	*s;		/* the header line */
317 	size_t		 len;		/* its length */
318 	int		 type;		/* the defined type */
319 } headerline_t;
320 
321 static headerline_t	headerlines[] = {
322 	{ "BEGIN PGP MESSAGE",		17, BEGIN_PGP_MESSAGE },
323 	{ "BEGIN PGP PUBLIC KEY BLOCK",	26, BEGIN_PGP_PUBLIC_KEY_BLOCK },
324 	{ "BEGIN PGP PRIVATE KEY BLOCK",27, BEGIN_PGP_PRIVATE_KEY_BLOCK },
325 	{ "BEGIN PGP MESSAGE, PART ",	25, BEGIN_PGP_MULTI },
326 	{ "BEGIN PGP SIGNATURE",	19, BEGIN_PGP_SIGNATURE },
327 
328 	{ "END PGP MESSAGE",		15, END_PGP_MESSAGE },
329 	{ "END PGP PUBLIC KEY BLOCK",	24, END_PGP_PUBLIC_KEY_BLOCK },
330 	{ "END PGP PRIVATE KEY BLOCK",	25, END_PGP_PRIVATE_KEY_BLOCK },
331 	{ "END PGP MESSAGE, PART ",	22, END_PGP_MULTI },
332 	{ "END PGP SIGNATURE",		17, END_PGP_SIGNATURE },
333 
334 	{ "BEGIN PGP SIGNED MESSAGE",	24, BEGIN_PGP_SIGNED_MESSAGE },
335 
336 	{ NULL,				0, -1	}
337 };
338 
339 /* search through the table of header lines */
340 static int
341 findheaderline(char *headerline)
342 {
343 	headerline_t	*hp;
344 
345 	for (hp = headerlines ; hp->s ; hp++) {
346 		if (strncmp(headerline, hp->s, hp->len) == 0) {
347 			break;
348 		}
349 	}
350 	return hp->type;
351 }
352 
353 static int
354 set_lastseen_headerline(dearmour_t *dearmour, char *hdr, __ops_error_t **errors)
355 {
356 	int	lastseen;
357 	int	prev;
358 
359 	prev = dearmour->lastseen;
360 	if ((lastseen = findheaderline(hdr)) == -1) {
361 		OPS_ERROR_1(errors, OPS_E_R_BAD_FORMAT,
362 			"Unrecognised Header Line %s", hdr);
363 		return 0;
364 	}
365 	dearmour->lastseen = lastseen;
366 	if (__ops_get_debug_level(__FILE__)) {
367 		printf("set header: hdr=%s, dearmour->lastseen=%d, prev=%d\n",
368 			hdr, dearmour->lastseen, prev);
369 	}
370 	switch (dearmour->lastseen) {
371 	case NONE:
372 		OPS_ERROR_1(errors, OPS_E_R_BAD_FORMAT,
373 			"Unrecognised last seen Header Line %s", hdr);
374 		break;
375 
376 	case END_PGP_MESSAGE:
377 		if (prev != BEGIN_PGP_MESSAGE) {
378 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
379 				"Got END PGP MESSAGE, but not after BEGIN");
380 		}
381 		break;
382 
383 	case END_PGP_PUBLIC_KEY_BLOCK:
384 		if (prev != BEGIN_PGP_PUBLIC_KEY_BLOCK) {
385 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
386 			"Got END PGP PUBLIC KEY BLOCK, but not after BEGIN");
387 		}
388 		break;
389 
390 	case END_PGP_PRIVATE_KEY_BLOCK:
391 		if (prev != BEGIN_PGP_PRIVATE_KEY_BLOCK) {
392 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
393 			"Got END PGP PRIVATE KEY BLOCK, but not after BEGIN");
394 		}
395 		break;
396 
397 	case BEGIN_PGP_MULTI:
398 	case END_PGP_MULTI:
399 		OPS_ERROR(errors, OPS_E_R_UNSUPPORTED,
400 			"Multi-part messages are not yet supported");
401 		break;
402 
403 	case END_PGP_SIGNATURE:
404 		if (prev != BEGIN_PGP_SIGNATURE) {
405 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
406 			"Got END PGP SIGNATURE, but not after BEGIN");
407 		}
408 		break;
409 
410 	case BEGIN_PGP_MESSAGE:
411 	case BEGIN_PGP_PUBLIC_KEY_BLOCK:
412 	case BEGIN_PGP_PRIVATE_KEY_BLOCK:
413 	case BEGIN_PGP_SIGNATURE:
414 	case BEGIN_PGP_SIGNED_MESSAGE:
415 		break;
416 	}
417 	return 1;
418 }
419 
420 static int
421 read_char(dearmour_t *dearmour,
422 		__ops_error_t **errors,
423 		__ops_reader_t *readinfo,
424 		__ops_cbdata_t *cbinfo,
425 		unsigned skip)
426 {
427 	unsigned char   c;
428 
429 	do {
430 		if (dearmour->pushbackc) {
431 			c = dearmour->pushback[--dearmour->pushbackc];
432 			if (dearmour->pushbackc == 0) {
433 				free(dearmour->pushback);
434 				dearmour->pushback = NULL;
435 			}
436 		} else if (__ops_stacked_read(&c, 1, errors, readinfo,
437 					cbinfo) != 1) {
438 			return -1;
439 		}
440 	} while (skip && c == '\r');
441 	dearmour->prev_nl = dearmour->seen_nl;
442 	dearmour->seen_nl = c == '\n';
443 	return c;
444 }
445 
446 static int
447 eat_whitespace(int first,
448 	       dearmour_t *dearmour,
449 	       __ops_error_t **errors,
450 	       __ops_reader_t *readinfo,
451 	       __ops_cbdata_t *cbinfo,
452 	       unsigned skip)
453 {
454 	int             c = first;
455 
456 	while (c == ' ' || c == '\t') {
457 		c = read_char(dearmour, errors, readinfo, cbinfo, skip);
458 	}
459 	return c;
460 }
461 
462 static int
463 read_and_eat_whitespace(dearmour_t *dearmour,
464 			__ops_error_t **errors,
465 			__ops_reader_t *readinfo,
466 			__ops_cbdata_t *cbinfo,
467 			unsigned skip)
468 {
469 	int             c;
470 
471 	do {
472 		c = read_char(dearmour, errors, readinfo, cbinfo, skip);
473 	} while (c == ' ' || c == '\t');
474 	return c;
475 }
476 
477 static void
478 flush(dearmour_t *dearmour, __ops_cbdata_t *cbinfo)
479 {
480 	__ops_packet_t	content;
481 
482 	if (dearmour->unarmoredc > 0) {
483 		content.u.unarmoured_text.data = dearmour->unarmoured;
484 		content.u.unarmoured_text.length = dearmour->unarmoredc;
485 		CALLBACK(OPS_PTAG_CT_UNARMOURED_TEXT, cbinfo, &content);
486 		dearmour->unarmoredc = 0;
487 	}
488 }
489 
490 static int
491 unarmoured_read_char(dearmour_t *dearmour,
492 			__ops_error_t **errors,
493 			__ops_reader_t *readinfo,
494 			__ops_cbdata_t *cbinfo,
495 			unsigned skip)
496 {
497 	int             c;
498 
499 	do {
500 		c = read_char(dearmour, errors, readinfo, cbinfo, 0);
501 		if (c < 0) {
502 			return c;
503 		}
504 		dearmour->unarmoured[dearmour->unarmoredc++] = c;
505 		if (dearmour->unarmoredc == sizeof(dearmour->unarmoured)) {
506 			flush(dearmour, cbinfo);
507 		}
508 	} while (skip && c == '\r');
509 	return c;
510 }
511 
512 /**
513  * \param headers
514  * \param key
515  *
516  * \return header value if found, otherwise NULL
517  */
518 static const char *
519 __ops_find_header(__ops_headers_t *headers, const char *key)
520 {
521 	unsigned        n;
522 
523 	for (n = 0; n < headers->headerc; ++n) {
524 		if (strcmp(headers->headers[n].key, key) == 0) {
525 			return headers->headers[n].value;
526 		}
527 	}
528 	return NULL;
529 }
530 
531 /**
532  * \param dest
533  * \param src
534  */
535 static void
536 __ops_dup_headers(__ops_headers_t *dest, const __ops_headers_t *src)
537 {
538 	unsigned        n;
539 
540 	if ((dest->headers = calloc(src->headerc, sizeof(*dest->headers))) == NULL) {
541 		(void) fprintf(stderr, "__ops_dup_headers: bad alloc\n");
542 	} else {
543 		dest->headerc = src->headerc;
544 		for (n = 0; n < src->headerc; ++n) {
545 			dest->headers[n].key = strdup(src->headers[n].key);
546 			dest->headers[n].value = strdup(src->headers[n].value);
547 		}
548 	}
549 }
550 
551 /*
552  * Note that this skips CRs so implementations always see just straight LFs
553  * as line terminators
554  */
555 static int
556 process_dash_escaped(dearmour_t *dearmour,
557 			__ops_error_t **errors,
558 			__ops_reader_t *readinfo,
559 			__ops_cbdata_t *cbinfo)
560 {
561 	__ops_packet_t content;
562 	__ops_packet_t content2;
563 	__ops_cleartext_body_t *body = &content.u.cleartext_body;
564 	__ops_cleartext_trailer_t *trailer = &content2.u.cleartext_trailer;
565 	const char     *hashstr;
566 	__ops_hash_t     *hash;
567 	int             total;
568 
569 	if ((hash = calloc(1, sizeof(*hash))) == NULL) {
570 		OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
571 			"process_dash_escaped: bad alloc");
572 		return -1;
573 	}
574 	hashstr = __ops_find_header(&dearmour->headers, "Hash");
575 	if (hashstr) {
576 		__ops_hash_alg_t alg;
577 
578 		alg = __ops_str_to_hash_alg(hashstr);
579 		if (!__ops_is_hash_alg_supported(&alg)) {
580 			free(hash);
581 			OPS_ERROR_1(errors, OPS_E_R_BAD_FORMAT,
582 				"Unsupported hash algorithm '%s'", hashstr);
583 			return -1;
584 		}
585 		if (alg == OPS_HASH_UNKNOWN) {
586 			free(hash);
587 			OPS_ERROR_1(errors, OPS_E_R_BAD_FORMAT,
588 				"Unknown hash algorithm '%s'", hashstr);
589 			return -1;
590 		}
591 		__ops_hash_any(hash, alg);
592 	} else {
593 		__ops_hash_md5(hash);
594 	}
595 
596 	if (!hash->init(hash)) {
597 		OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
598 			"can't initialise hash");
599 		return -1;
600 	}
601 
602 	body->length = 0;
603 	total = 0;
604 	for (;;) {
605 		int             c;
606 		unsigned        count;
607 
608 		c = read_char(dearmour, errors, readinfo, cbinfo, 1);
609 		if (c < 0) {
610 			return -1;
611 		}
612 		if (dearmour->prev_nl && c == '-') {
613 			if ((c = read_char(dearmour, errors, readinfo, cbinfo,
614 						0)) < 0) {
615 				return -1;
616 			}
617 			if (c != ' ') {
618 				/* then this had better be a trailer! */
619 				if (c != '-') {
620 					OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
621 						"Bad dash-escaping");
622 				}
623 				for (count = 2; count < 5; ++count) {
624 					if ((c = read_char(dearmour, errors,
625 						readinfo, cbinfo, 0)) < 0) {
626 						return -1;
627 					}
628 					if (c != '-') {
629 						OPS_ERROR(errors,
630 						OPS_E_R_BAD_FORMAT,
631 						"Bad dash-escaping (2)");
632 					}
633 				}
634 				dearmour->state = AT_TRAILER_NAME;
635 				break;
636 			}
637 			/* otherwise we read the next character */
638 			if ((c = read_char(dearmour, errors, readinfo, cbinfo,
639 						0)) < 0) {
640 				return -1;
641 			}
642 		}
643 		if (c == '\n' && body->length) {
644 			if (memchr(body->data + 1, '\n', body->length - 1)
645 						!= NULL) {
646 				(void) fprintf(stderr,
647 				"process_dash_escaped: newline found\n");
648 				return -1;
649 			}
650 			if (body->data[0] == '\n') {
651 				hash->add(hash, (const unsigned char *)"\r", 1);
652 			}
653 			hash->add(hash, body->data, body->length);
654 			if (__ops_get_debug_level(__FILE__)) {
655 				fprintf(stderr, "Got body:\n%s\n", body->data);
656 			}
657 			CALLBACK(OPS_PTAG_CT_SIGNED_CLEARTEXT_BODY, cbinfo,
658 						&content);
659 			body->length = 0;
660 		}
661 		body->data[body->length++] = c;
662 		total += 1;
663 		if (body->length == sizeof(body->data)) {
664 			if (__ops_get_debug_level(__FILE__)) {
665 				(void) fprintf(stderr, "Got body (2):\n%s\n",
666 						body->data);
667 			}
668 			CALLBACK(OPS_PTAG_CT_SIGNED_CLEARTEXT_BODY, cbinfo,
669 					&content);
670 			body->length = 0;
671 		}
672 	}
673 	if (body->data[0] != '\n') {
674 		(void) fprintf(stderr,
675 			"process_dash_escaped: no newline in body data\n");
676 		return -1;
677 	}
678 	if (body->length != 1) {
679 		(void) fprintf(stderr,
680 			"process_dash_escaped: bad body length\n");
681 		return -1;
682 	}
683 
684 	/* don't send that one character, because it's part of the trailer */
685 	trailer->hash = hash;
686 	CALLBACK(OPS_PTAG_CT_SIGNED_CLEARTEXT_TRAILER, cbinfo, &content2);
687 	return total;
688 }
689 
690 static int
691 add_header(dearmour_t *dearmour, const char *key, const char *value)
692 {
693 	int	n;
694 
695 	/*
696          * Check that the header is valid
697          */
698 	if (strcmp(key, "Version") == 0 ||
699 	    strcmp(key, "Comment") == 0 ||
700 	    strcmp(key, "MessageID") == 0 ||
701 	    strcmp(key, "Hash") == 0 ||
702 	    strcmp(key, "Charset") == 0) {
703 		n = dearmour->headers.headerc;
704 		dearmour->headers.headers = realloc(dearmour->headers.headers,
705 				(n + 1) * sizeof(*dearmour->headers.headers));
706 		if (dearmour->headers.headers == NULL) {
707 			(void) fprintf(stderr, "add_header: bad alloc\n");
708 			return 0;
709 		}
710 		dearmour->headers.headers[n].key = strdup(key);
711 		dearmour->headers.headers[n].value = strdup(value);
712 		dearmour->headers.headerc = n + 1;
713 		return 1;
714 	}
715 	return 0;
716 }
717 
718 /* \todo what does a return value of 0 indicate? 1 is good, -1 is bad */
719 static int
720 parse_headers(dearmour_t *dearmour, __ops_error_t **errors,
721 	      __ops_reader_t * readinfo, __ops_cbdata_t * cbinfo)
722 {
723 	unsigned        nbuf;
724 	unsigned        size;
725 	unsigned	first = 1;
726 	char           *buf;
727 	int             ret = 1;
728 
729 	nbuf = 0;
730 	size = 80;
731 	if ((buf = calloc(1, size)) == NULL) {
732 		(void) fprintf(stderr, "parse_headers: bad calloc\n");
733 		return -1;
734 	}
735 	for (;;) {
736 		int             c;
737 
738 		if ((c = read_char(dearmour, errors, readinfo, cbinfo, 1)) < 0) {
739 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT, "Unexpected EOF");
740 			ret = -1;
741 			break;
742 		}
743 		if (c == '\n') {
744 			char           *s;
745 
746 			if (nbuf == 0) {
747 				break;
748 			}
749 
750 			if (nbuf >= size) {
751 				(void) fprintf(stderr,
752 					"parse_headers: bad size\n");
753 				return -1;
754 			}
755 			buf[nbuf] = '\0';
756 
757 			if ((s = strchr(buf, ':')) == NULL) {
758 				if (!first && !dearmour->allow_headers_without_gap) {
759 					/*
760 					 * then we have seriously malformed
761 					 * armour
762 					 */
763 					OPS_ERROR(errors, OPS_E_R_BAD_FORMAT, "No colon in armour header");
764 					ret = -1;
765 					break;
766 				} else {
767 					if (first &&
768 					    !(dearmour->allow_headers_without_gap || dearmour->allow_no_gap)) {
769 						OPS_ERROR(errors, OPS_E_R_BAD_FORMAT, "No colon in armour header (2)");
770 						/*
771 						 * then we have a nasty
772 						 * armoured block with no
773 						 * headers, not even a blank
774 						 * line.
775 						 */
776 						buf[nbuf] = '\n';
777 						push_back(dearmour, (unsigned char *) buf, nbuf + 1);
778 						ret = -1;
779 						break;
780 					}
781 				}
782 			} else {
783 				*s = '\0';
784 				if (s[1] != ' ') {
785 					OPS_ERROR(errors, OPS_E_R_BAD_FORMAT, "No space in armour header");
786 					ret = -1;
787 					goto end;
788 				}
789 				if (!add_header(dearmour, buf, s + 2)) {
790 					OPS_ERROR_1(errors, OPS_E_R_BAD_FORMAT, "Invalid header %s", buf);
791 					ret = -1;
792 					goto end;
793 				}
794 				nbuf = 0;
795 			}
796 			first = 0;
797 		} else {
798 			if (size <= nbuf + 1) {
799 				size += size + 80;
800 				buf = realloc(buf, size);
801 				if (buf == NULL) {
802 					(void) fprintf(stderr, "bad alloc\n");
803 					ret = -1;
804 					goto end;
805 				}
806 			}
807 			buf[nbuf++] = c;
808 		}
809 	}
810 
811 end:
812 	free(buf);
813 
814 	return ret;
815 }
816 
817 static int
818 read4(dearmour_t *dearmour, __ops_error_t **errors,
819       __ops_reader_t *readinfo, __ops_cbdata_t *cbinfo,
820       int *pc, unsigned *pn, unsigned long *pl)
821 {
822 	int             n, c;
823 	unsigned long   l = 0;
824 
825 	for (n = 0; n < 4; ++n) {
826 		c = read_char(dearmour, errors, readinfo, cbinfo, 1);
827 		if (c < 0) {
828 			dearmour->eof64 = 1;
829 			return -1;
830 		}
831 		if (c == '-' || c == '=') {
832 			break;
833 		}
834 		l <<= 6;
835 		if (c >= 'A' && c <= 'Z') {
836 			l += (unsigned long)(c - 'A');
837 		} else if (c >= 'a' && c <= 'z') {
838 			l += (unsigned long)(c - 'a') + 26;
839 		} else if (c >= '0' && c <= '9') {
840 			l += (unsigned long)(c - '0') + 52;
841 		} else if (c == '+') {
842 			l += 62;
843 		} else if (c == '/') {
844 			l += 63;
845 		} else {
846 			--n;
847 			l >>= 6;
848 		}
849 	}
850 
851 	*pc = c;
852 	*pn = n;
853 	*pl = l;
854 
855 	return 4;
856 }
857 
858 unsigned
859 __ops_crc24(unsigned checksum, unsigned char c)
860 {
861 	unsigned        i;
862 
863 	checksum ^= c << 16;
864 	for (i = 0; i < 8; i++) {
865 		checksum <<= 1;
866 		if (checksum & 0x1000000)
867 			checksum ^= CRC24_POLY;
868 	}
869 	return checksum & 0xffffffL;
870 }
871 
872 static int
873 decode64(dearmour_t *dearmour, __ops_error_t **errors,
874 	 __ops_reader_t *readinfo, __ops_cbdata_t *cbinfo)
875 {
876 	unsigned        n;
877 	int             n2;
878 	unsigned long   l;
879 	int             c;
880 	int             ret;
881 
882 	if (dearmour->buffered) {
883 		(void) fprintf(stderr, "decode64: bad dearmour->buffered\n");
884 		return 0;
885 	}
886 
887 	ret = read4(dearmour, errors, readinfo, cbinfo, &c, &n, &l);
888 	if (ret < 0) {
889 		OPS_ERROR(errors, OPS_E_R_BAD_FORMAT, "Badly formed base64");
890 		return 0;
891 	}
892 	if (n == 3) {
893 		if (c != '=') {
894 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
895 					"Badly terminated base64 (2)");
896 			return 0;
897 		}
898 		dearmour->buffered = 2;
899 		dearmour->eof64 = 1;
900 		l >>= 2;
901 	} else if (n == 2) {
902 		if (c != '=') {
903 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
904 					"Badly terminated base64 (3)");
905 			return 0;
906 		}
907 		dearmour->buffered = 1;
908 		dearmour->eof64 = 1;
909 		l >>= 4;
910 		c = read_char(dearmour, errors, readinfo, cbinfo, 0);
911 		if (c != '=') {
912 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
913 					"Badly terminated base64");
914 			return 0;
915 		}
916 	} else if (n == 0) {
917 		if (!dearmour->prev_nl || c != '=') {
918 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
919 					"Badly terminated base64 (4)");
920 			return 0;
921 		}
922 		dearmour->buffered = 0;
923 	} else {
924 		if (n != 4) {
925 			(void) fprintf(stderr,
926 				"decode64: bad n (!= 4)\n");
927 			return 0;
928 		}
929 		dearmour->buffered = 3;
930 		if (c == '-' || c == '=') {
931 			(void) fprintf(stderr, "decode64: bad c\n");
932 			return 0;
933 		}
934 	}
935 
936 	if (dearmour->buffered < 3 && dearmour->buffered > 0) {
937 		/* then we saw padding */
938 		if (c != '=') {
939 			(void) fprintf(stderr, "decode64: bad c (=)\n");
940 			return 0;
941 		}
942 		c = read_and_eat_whitespace(dearmour, errors, readinfo, cbinfo,
943 				1);
944 		if (c != '\n') {
945 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
946 				"No newline at base64 end");
947 			return 0;
948 		}
949 		c = read_char(dearmour, errors, readinfo, cbinfo, 0);
950 		if (c != '=') {
951 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
952 				"No checksum at base64 end");
953 			return 0;
954 		}
955 	}
956 	if (c == '=') {
957 		/* now we are at the checksum */
958 		ret = read4(dearmour, errors, readinfo, cbinfo, &c, &n,
959 				&dearmour->read_checksum);
960 		if (ret < 0 || n != 4) {
961 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
962 					"Error in checksum");
963 			return 0;
964 		}
965 		c = read_char(dearmour, errors, readinfo, cbinfo, 1);
966 		if (dearmour->allow_trailing_whitespace)
967 			c = eat_whitespace(c, dearmour, errors, readinfo, cbinfo,
968 					1);
969 		if (c != '\n') {
970 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
971 					"Badly terminated checksum");
972 			return 0;
973 		}
974 		c = read_char(dearmour, errors, readinfo, cbinfo, 0);
975 		if (c != '-') {
976 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
977 					"Bad base64 trailer (2)");
978 			return 0;
979 		}
980 	}
981 	if (c == '-') {
982 		for (n = 0; n < 4; ++n)
983 			if (read_char(dearmour, errors, readinfo, cbinfo,
984 						0) != '-') {
985 				OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
986 						"Bad base64 trailer");
987 				return 0;
988 			}
989 		dearmour->eof64 = 1;
990 	} else {
991 		if (!dearmour->buffered) {
992 			(void) fprintf(stderr, "decode64: not buffered\n");
993 			return 0;
994 		}
995 	}
996 
997 	for (n = 0; n < dearmour->buffered; ++n) {
998 		dearmour->buffer[n] = (unsigned char)l;
999 		l >>= 8;
1000 	}
1001 
1002 	for (n2 = dearmour->buffered - 1; n2 >= 0; --n2)
1003 		dearmour->checksum = __ops_crc24((unsigned)dearmour->checksum,
1004 					dearmour->buffer[n2]);
1005 
1006 	if (dearmour->eof64 && dearmour->read_checksum != dearmour->checksum) {
1007 		OPS_ERROR(errors, OPS_E_R_BAD_FORMAT, "Checksum mismatch");
1008 		return 0;
1009 	}
1010 	return 1;
1011 }
1012 
1013 static void
1014 base64(dearmour_t *dearmour)
1015 {
1016 	dearmour->state = BASE64;
1017 	dearmour->checksum = CRC24_INIT;
1018 	dearmour->eof64 = 0;
1019 	dearmour->buffered = 0;
1020 }
1021 
1022 /* This reader is rather strange in that it can generate callbacks for */
1023 /* content - this is because plaintext is not encapsulated in PGP */
1024 /* packets... it also calls back for the text between the blocks. */
1025 
1026 static int
1027 armoured_data_reader(void *dest_, size_t length, __ops_error_t **errors,
1028 		     __ops_reader_t *readinfo,
1029 		     __ops_cbdata_t *cbinfo)
1030 {
1031 	__ops_packet_t	 content;
1032 	unsigned char	*dest = dest_;
1033 	dearmour_t	*dearmour;
1034 	unsigned	 first;
1035 	char		 buf[1024];
1036 	int		 saved;
1037 	int              ret;
1038 
1039 	dearmour = __ops_reader_get_arg(readinfo);
1040 	saved = length;
1041 	if (dearmour->eof64 && !dearmour->buffered) {
1042 		if (dearmour->state != OUTSIDE_BLOCK &&
1043 		    dearmour->state != AT_TRAILER_NAME) {
1044 			(void) fprintf(stderr,
1045 				"armoured_data_reader: bad dearmour state\n");
1046 			return 0;
1047 		}
1048 	}
1049 
1050 	while (length > 0) {
1051 		unsigned        count;
1052 		unsigned        n;
1053 		int             c;
1054 
1055 		flush(dearmour, cbinfo);
1056 		switch (dearmour->state) {
1057 		case OUTSIDE_BLOCK:
1058 			/*
1059 			 * This code returns EOF rather than EARLY_EOF
1060 			 * because if we don't see a header line at all, then
1061 			 * it is just an EOF (and not a BLOCK_END)
1062 			 */
1063 			while (!dearmour->seen_nl) {
1064 				if ((c = unarmoured_read_char(dearmour, errors,
1065 						readinfo, cbinfo, 1)) < 0) {
1066 					return 0;
1067 				}
1068 			}
1069 
1070 			/*
1071 			 * flush at this point so we definitely have room for
1072 			 * the header, and so we can easily erase it from the
1073 			 * buffer
1074 			 */
1075 			flush(dearmour, cbinfo);
1076 			/* Find and consume the 5 leading '-' */
1077 			for (count = 0; count < 5; ++count) {
1078 				if ((c = unarmoured_read_char(dearmour, errors,
1079 						readinfo, cbinfo, 0)) < 0) {
1080 					return 0;
1081 				}
1082 				if (c != '-') {
1083 					goto reloop;
1084 				}
1085 			}
1086 
1087 			/* Now find the block type */
1088 			for (n = 0; n < sizeof(buf) - 1;) {
1089 				if ((c = unarmoured_read_char(dearmour, errors,
1090 						readinfo, cbinfo, 0)) < 0) {
1091 					return 0;
1092 				}
1093 				if (c == '-') {
1094 					goto got_minus;
1095 				}
1096 				buf[n++] = c;
1097 			}
1098 			/* then I guess this wasn't a proper header */
1099 			break;
1100 
1101 got_minus:
1102 			buf[n] = '\0';
1103 
1104 			/* Consume trailing '-' */
1105 			for (count = 1; count < 5; ++count) {
1106 				if ((c = unarmoured_read_char(dearmour, errors,
1107 						readinfo, cbinfo, 0)) < 0) {
1108 					return 0;
1109 				}
1110 				if (c != '-') {
1111 					/* wasn't a header after all */
1112 					goto reloop;
1113 				}
1114 			}
1115 
1116 			/* Consume final NL */
1117 			if ((c = unarmoured_read_char(dearmour, errors, readinfo,
1118 						cbinfo, 1)) < 0) {
1119 				return 0;
1120 			}
1121 			if (dearmour->allow_trailing_whitespace) {
1122 				if ((c = eat_whitespace(c, dearmour, errors,
1123 						readinfo, cbinfo, 1)) < 0) {
1124 					return 0;
1125 				}
1126 			}
1127 			if (c != '\n') {
1128 				/* wasn't a header line after all */
1129 				break;
1130 			}
1131 
1132 			/*
1133 			 * Now we've seen the header, scrub it from the
1134 			 * buffer
1135 			 */
1136 			dearmour->unarmoredc = 0;
1137 
1138 			/*
1139 			 * But now we've seen a header line, then errors are
1140 			 * EARLY_EOF
1141 			 */
1142 			if ((ret = parse_headers(dearmour, errors, readinfo,
1143 					cbinfo)) <= 0) {
1144 				return -1;
1145 			}
1146 
1147 			if (!set_lastseen_headerline(dearmour, buf, errors)) {
1148 				return -1;
1149 			}
1150 
1151 			if (strcmp(buf, "BEGIN PGP SIGNED MESSAGE") == 0) {
1152 				__ops_dup_headers(
1153 					&content.u.cleartext_head.headers,
1154 					&dearmour->headers);
1155 				CALLBACK(OPS_PTAG_CT_SIGNED_CLEARTEXT_HEADER,
1156 					cbinfo,
1157 					&content);
1158 				ret = process_dash_escaped(dearmour, errors,
1159 						readinfo, cbinfo);
1160 				if (ret <= 0) {
1161 					return ret;
1162 				}
1163 			} else {
1164 				content.u.armour_header.type = buf;
1165 				content.u.armour_header.headers =
1166 						dearmour->headers;
1167 				(void) memset(&dearmour->headers, 0x0,
1168 						sizeof(dearmour->headers));
1169 				CALLBACK(OPS_PTAG_CT_ARMOUR_HEADER, cbinfo,
1170 						&content);
1171 				base64(dearmour);
1172 			}
1173 			break;
1174 
1175 		case BASE64:
1176 			first = 1;
1177 			while (length > 0) {
1178 				if (!dearmour->buffered) {
1179 					if (!dearmour->eof64) {
1180 						ret = decode64(dearmour,
1181 							errors, readinfo, cbinfo);
1182 						if (ret <= 0) {
1183 							return ret;
1184 						}
1185 					}
1186 					if (!dearmour->buffered) {
1187 						if (!dearmour->eof64) {
1188 							(void) fprintf(stderr,
1189 "armoured_data_reader: bad dearmour eof64\n");
1190 							return 0;
1191 						}
1192 						if (first) {
1193 							dearmour->state =
1194 								AT_TRAILER_NAME;
1195 							goto reloop;
1196 						}
1197 						return -1;
1198 					}
1199 				}
1200 				if (!dearmour->buffered) {
1201 					(void) fprintf(stderr,
1202 			"armoured_data_reader: bad dearmour buffered\n");
1203 					return 0;
1204 				}
1205 				*dest = dearmour->buffer[--dearmour->buffered];
1206 				++dest;
1207 				--length;
1208 				first = 0;
1209 			}
1210 			if (dearmour->eof64 && !dearmour->buffered) {
1211 				dearmour->state = AT_TRAILER_NAME;
1212 			}
1213 			break;
1214 
1215 		case AT_TRAILER_NAME:
1216 			for (n = 0; n < sizeof(buf) - 1;) {
1217 				if ((c = read_char(dearmour, errors, readinfo,
1218 						cbinfo, 0)) < 0) {
1219 					return -1;
1220 				}
1221 				if (c == '-') {
1222 					goto got_minus2;
1223 				}
1224 				buf[n++] = c;
1225 			}
1226 			/* then I guess this wasn't a proper trailer */
1227 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
1228 					"Bad ASCII armour trailer");
1229 			break;
1230 
1231 got_minus2:
1232 			buf[n] = '\0';
1233 
1234 			if (!set_lastseen_headerline(dearmour, buf, errors)) {
1235 				return -1;
1236 			}
1237 
1238 			/* Consume trailing '-' */
1239 			for (count = 1; count < 5; ++count) {
1240 				if ((c = read_char(dearmour, errors, readinfo,
1241 						cbinfo, 0)) < 0) {
1242 					return -1;
1243 				}
1244 				if (c != '-') {
1245 					/* wasn't a trailer after all */
1246 					OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
1247 						"Bad ASCII armour trailer (2)");
1248 				}
1249 			}
1250 
1251 			/* Consume final NL */
1252 			if ((c = read_char(dearmour, errors, readinfo, cbinfo,
1253 						1)) < 0) {
1254 				return -1;
1255 			}
1256 			if (dearmour->allow_trailing_whitespace) {
1257 				if ((c = eat_whitespace(c, dearmour, errors,
1258 						readinfo, cbinfo, 1)) < 0) {
1259 					return 0;
1260 				}
1261 			}
1262 			if (c != '\n') {
1263 				/* wasn't a trailer line after all */
1264 				OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
1265 					"Bad ASCII armour trailer (3)");
1266 			}
1267 
1268 			if (strncmp(buf, "BEGIN ", 6) == 0) {
1269 				if (!set_lastseen_headerline(dearmour, buf,
1270 						errors)) {
1271 					return -1;
1272 				}
1273 				if ((ret = parse_headers(dearmour, errors,
1274 						readinfo, cbinfo)) <= 0) {
1275 					return ret;
1276 				}
1277 				content.u.armour_header.type = buf;
1278 				content.u.armour_header.headers =
1279 						dearmour->headers;
1280 				(void) memset(&dearmour->headers, 0x0,
1281 						sizeof(dearmour->headers));
1282 				CALLBACK(OPS_PTAG_CT_ARMOUR_HEADER, cbinfo,
1283 						&content);
1284 				base64(dearmour);
1285 			} else {
1286 				content.u.armour_trailer.type = buf;
1287 				CALLBACK(OPS_PTAG_CT_ARMOUR_TRAILER, cbinfo,
1288 						&content);
1289 				dearmour->state = OUTSIDE_BLOCK;
1290 			}
1291 			break;
1292 		}
1293 reloop:
1294 		continue;
1295 	}
1296 
1297 	return saved;
1298 }
1299 
1300 static void
1301 armoured_data_destroyer(__ops_reader_t *readinfo)
1302 {
1303 	free(__ops_reader_get_arg(readinfo));
1304 }
1305 
1306 /**
1307  * \ingroup Core_Readers_Armour
1308  * \brief Pushes dearmouring reader onto stack
1309  * \param parse_info Usual structure containing information about to how to do the parse
1310  * \sa __ops_reader_pop_dearmour()
1311  */
1312 void
1313 __ops_reader_push_dearmour(__ops_stream_t *parse_info)
1314 /*
1315  * This function originally had these params to cater for packets which
1316  * didn't strictly match the RFC. The initial 0.5 release is only going to
1317  * support strict checking. If it becomes desirable to support loose checking
1318  * of armoured packets and these params are reinstated, parse_headers() must
1319  * be fixed so that these flags work correctly.
1320  *
1321  * // Allow headers in armoured data that are not separated from the data by a
1322  * blank line unsigned without_gap,
1323  *
1324  * // Allow no blank line at the start of armoured data unsigned no_gap,
1325  *
1326  * //Allow armoured data to have trailing whitespace where we strictly would not
1327  * expect it			      unsigned trailing_whitespace
1328  */
1329 {
1330 	dearmour_t *dearmour;
1331 
1332 	if ((dearmour = calloc(1, sizeof(*dearmour))) == NULL) {
1333 		(void) fprintf(stderr, "__ops_reader_push_dearmour: bad alloc\n");
1334 	} else {
1335 		dearmour->seen_nl = 1;
1336 		/*
1337 		    dearmour->allow_headers_without_gap=without_gap;
1338 		    dearmour->allow_no_gap=no_gap;
1339 		    dearmour->allow_trailing_whitespace=trailing_whitespace;
1340 		*/
1341 		dearmour->expect_sig = 0;
1342 		dearmour->got_sig = 0;
1343 
1344 		__ops_reader_push(parse_info, armoured_data_reader,
1345 			armoured_data_destroyer, dearmour);
1346 	}
1347 }
1348 
1349 /**
1350  * \ingroup Core_Readers_Armour
1351  * \brief Pops dearmour reader from stock
1352  * \param stream
1353  * \sa __ops_reader_push_dearmour()
1354  */
1355 void
1356 __ops_reader_pop_dearmour(__ops_stream_t *stream)
1357 {
1358 	dearmour_t *dearmour;
1359 
1360 	dearmour = __ops_reader_get_arg(__ops_readinfo(stream));
1361 	free(dearmour);
1362 	__ops_reader_pop(stream);
1363 }
1364 
1365 /**************************************************************************/
1366 
1367 /* this is actually used for *decrypting* */
1368 typedef struct {
1369 	unsigned char	 decrypted[1024 * 15];
1370 	size_t		 c;
1371 	size_t		 off;
1372 	__ops_crypt_t	*decrypt;
1373 	__ops_region_t	*region;
1374 	unsigned	 prevplain:1;
1375 } encrypted_t;
1376 
1377 static int
1378 encrypted_data_reader(void *dest,
1379 			size_t length,
1380 			__ops_error_t **errors,
1381 			__ops_reader_t *readinfo,
1382 			__ops_cbdata_t *cbinfo)
1383 {
1384 	encrypted_t	*encrypted;
1385 	char		*cdest;
1386 	int		 saved;
1387 
1388 	encrypted = __ops_reader_get_arg(readinfo);
1389 	saved = length;
1390 	/*
1391 	 * V3 MPIs have the count plain and the cipher is reset after each
1392 	 * count
1393 	 */
1394 	if (encrypted->prevplain && !readinfo->parent->reading_mpi_len) {
1395 		if (!readinfo->parent->reading_v3_secret) {
1396 			(void) fprintf(stderr,
1397 				"encrypted_data_reader: bad v3 secret\n");
1398 			return -1;
1399 		}
1400 		encrypted->decrypt->decrypt_resync(encrypted->decrypt);
1401 		encrypted->prevplain = 0;
1402 	} else if (readinfo->parent->reading_v3_secret &&
1403 		   readinfo->parent->reading_mpi_len) {
1404 		encrypted->prevplain = 1;
1405 	}
1406 	while (length > 0) {
1407 		if (encrypted->c) {
1408 			unsigned        n;
1409 
1410 			/*
1411 			 * if we are reading v3 we should never read
1412 			 * more than we're asked for */
1413 			if (length < encrypted->c &&
1414 			     (readinfo->parent->reading_v3_secret ||
1415 			      readinfo->parent->exact_read)) {
1416 				(void) fprintf(stderr,
1417 					"encrypted_data_reader: bad v3 read\n");
1418 				return 0;
1419 			}
1420 			n = MIN(length, encrypted->c);
1421 			(void) memcpy(dest,
1422 				encrypted->decrypted + encrypted->off, n);
1423 			encrypted->c -= n;
1424 			encrypted->off += n;
1425 			length -= n;
1426 			cdest = dest;
1427 			cdest += n;
1428 			dest = cdest;
1429 		} else {
1430 			unsigned        n = encrypted->region->length;
1431 			unsigned char   buffer[1024];
1432 
1433 			if (!n) {
1434 				return -1;
1435 			}
1436 			if (!encrypted->region->indeterminate) {
1437 				n -= encrypted->region->readc;
1438 				if (n == 0) {
1439 					return saved - length;
1440 				}
1441 				if (n > sizeof(buffer)) {
1442 					n = sizeof(buffer);
1443 				}
1444 			} else {
1445 				n = sizeof(buffer);
1446 			}
1447 
1448 			/*
1449 			 * we can only read as much as we're asked for
1450 			 * in v3 keys because they're partially
1451 			 * unencrypted!  */
1452 			if ((readinfo->parent->reading_v3_secret ||
1453 			     readinfo->parent->exact_read) && n > length) {
1454 				n = length;
1455 			}
1456 
1457 			if (!__ops_stacked_limited_read(buffer, n,
1458 				encrypted->region, errors, readinfo, cbinfo)) {
1459 				return -1;
1460 			}
1461 			if (!readinfo->parent->reading_v3_secret ||
1462 			    !readinfo->parent->reading_mpi_len) {
1463 				encrypted->c =
1464 					__ops_decrypt_se_ip(encrypted->decrypt,
1465 					encrypted->decrypted, buffer, n);
1466 
1467 				if (__ops_get_debug_level(__FILE__)) {
1468 					int             i;
1469 
1470 					(void) fprintf(stderr,
1471 						"READING:\nencrypted: ");
1472 					for (i = 0; i < 16; i++) {
1473 						(void) fprintf(stderr,
1474 							"%2x ", buffer[i]);
1475 					}
1476 					(void) fprintf(stderr, "\ndecrypted: ");
1477 					for (i = 0; i < 16; i++) {
1478 						(void) fprintf(stderr, "%2x ",
1479 						encrypted->decrypted[i]);
1480 					}
1481 					(void) fprintf(stderr, "\n");
1482 				}
1483 			} else {
1484 				(void) memcpy(
1485 	&encrypted->decrypted[encrypted->off], buffer, n);
1486 				encrypted->c = n;
1487 			}
1488 
1489 			if (encrypted->c == 0) {
1490 				(void) fprintf(stderr,
1491 				"encrypted_data_reader: 0 decrypted count\n");
1492 				return 0;
1493 			}
1494 
1495 			encrypted->off = 0;
1496 		}
1497 	}
1498 
1499 	return saved;
1500 }
1501 
1502 static void
1503 encrypted_data_destroyer(__ops_reader_t *readinfo)
1504 {
1505 	free(__ops_reader_get_arg(readinfo));
1506 }
1507 
1508 /**
1509  * \ingroup Core_Readers_SE
1510  * \brief Pushes decryption reader onto stack
1511  * \sa __ops_reader_pop_decrypt()
1512  */
1513 void
1514 __ops_reader_push_decrypt(__ops_stream_t *stream, __ops_crypt_t *decrypt,
1515 			__ops_region_t *region)
1516 {
1517 	encrypted_t	*encrypted;
1518 
1519 	if ((encrypted = calloc(1, sizeof(*encrypted))) == NULL) {
1520 		(void) fprintf(stderr, "__ops_reader_push_decrypted: bad alloc\n");
1521 	} else {
1522 		encrypted->decrypt = decrypt;
1523 		encrypted->region = region;
1524 		__ops_decrypt_init(encrypted->decrypt);
1525 		__ops_reader_push(stream, encrypted_data_reader,
1526 			encrypted_data_destroyer, encrypted);
1527 	}
1528 }
1529 
1530 /**
1531  * \ingroup Core_Readers_Encrypted
1532  * \brief Pops decryption reader from stack
1533  * \sa __ops_reader_push_decrypt()
1534  */
1535 void
1536 __ops_reader_pop_decrypt(__ops_stream_t *stream)
1537 {
1538 	encrypted_t	*encrypted;
1539 
1540 	encrypted = __ops_reader_get_arg(__ops_readinfo(stream));
1541 	encrypted->decrypt->decrypt_finish(encrypted->decrypt);
1542 	free(encrypted);
1543 	__ops_reader_pop(stream);
1544 }
1545 
1546 /**************************************************************************/
1547 
1548 typedef struct {
1549 	/* boolean: 0 once we've done the preamble/MDC checks */
1550 	/* and are reading from the plaintext */
1551 	int              passed_checks;
1552 	unsigned char	*plaintext;
1553 	size_t           plaintext_available;
1554 	size_t           plaintext_offset;
1555 	__ops_region_t	*region;
1556 	__ops_crypt_t	*decrypt;
1557 } decrypt_se_ip_t;
1558 
1559 /*
1560   Gets entire SE_IP data packet.
1561   Verifies leading preamble
1562   Verifies trailing MDC packet
1563   Then passes up plaintext as requested
1564 */
1565 static int
1566 se_ip_data_reader(void *dest_,
1567 			size_t len,
1568 			__ops_error_t **errors,
1569 			__ops_reader_t *readinfo,
1570 			__ops_cbdata_t *cbinfo)
1571 {
1572 	decrypt_se_ip_t	*se_ip;
1573 	__ops_region_t	 decrypted_region;
1574 	unsigned int	 n = 0;
1575 
1576 	se_ip = __ops_reader_get_arg(readinfo);
1577 	if (!se_ip->passed_checks) {
1578 		unsigned char  *buf = NULL;
1579 		unsigned char   hashed[OPS_SHA1_HASH_SIZE];
1580 		unsigned char  *preamble;
1581 		unsigned char  *plaintext;
1582 		unsigned char  *mdc;
1583 		unsigned char  *mdc_hash;
1584 		__ops_hash_t	hash;
1585 		size_t          b;
1586 		size_t          sz_preamble;
1587 		size_t          sz_mdc_hash;
1588 		size_t          sz_mdc;
1589 		size_t          sz_plaintext;
1590 
1591 		__ops_hash_any(&hash, OPS_HASH_SHA1);
1592 		if (!hash.init(&hash)) {
1593 			(void) fprintf(stderr,
1594 				"se_ip_data_reader: can't init hash\n");
1595 			return -1;
1596 		}
1597 
1598 		__ops_init_subregion(&decrypted_region, NULL);
1599 		decrypted_region.length =
1600 			se_ip->region->length - se_ip->region->readc;
1601 		if ((buf = calloc(1, decrypted_region.length)) == NULL) {
1602 			(void) fprintf(stderr, "se_ip_data_reader: bad alloc\n");
1603 			return -1;
1604 		}
1605 
1606 		/* read entire SE IP packet */
1607 		if (!__ops_stacked_limited_read(buf, decrypted_region.length,
1608 				&decrypted_region, errors, readinfo, cbinfo)) {
1609 			free(buf);
1610 			return -1;
1611 		}
1612 		if (__ops_get_debug_level(__FILE__)) {
1613 			unsigned	i;
1614 
1615 			fprintf(stderr, "\n\nentire SE IP packet (len=%d):\n",
1616 					decrypted_region.length);
1617 			for (i = 0; i < decrypted_region.length; i++) {
1618 				fprintf(stderr, "0x%02x ", buf[i]);
1619 				if (!((i + 1) % 8))
1620 					fprintf(stderr, "\n");
1621 			}
1622 			fprintf(stderr, "\n\n");
1623 		}
1624 		/* verify leading preamble */
1625 
1626 		if (__ops_get_debug_level(__FILE__)) {
1627 			unsigned	i;
1628 
1629 			fprintf(stderr, "\npreamble: ");
1630 			for (i = 0; i < se_ip->decrypt->blocksize + 2; i++)
1631 				fprintf(stderr, " 0x%02x", buf[i]);
1632 			fprintf(stderr, "\n");
1633 		}
1634 		b = se_ip->decrypt->blocksize;
1635 		if (buf[b - 2] != buf[b] || buf[b - 1] != buf[b + 1]) {
1636 			fprintf(stderr,
1637 			"Bad symmetric decrypt (%02x%02x vs %02x%02x)\n",
1638 				buf[b - 2], buf[b - 1], buf[b], buf[b + 1]);
1639 			OPS_ERROR(errors, OPS_E_PROTO_BAD_SYMMETRIC_DECRYPT,
1640 			"Bad symmetric decrypt when parsing SE IP packet");
1641 			free(buf);
1642 			return -1;
1643 		}
1644 		/* Verify trailing MDC hash */
1645 
1646 		sz_preamble = se_ip->decrypt->blocksize + 2;
1647 		sz_mdc_hash = OPS_SHA1_HASH_SIZE;
1648 		sz_mdc = 1 + 1 + sz_mdc_hash;
1649 		sz_plaintext = (decrypted_region.length - sz_preamble) - sz_mdc;
1650 
1651 		preamble = buf;
1652 		plaintext = buf + sz_preamble;
1653 		mdc = plaintext + sz_plaintext;
1654 		mdc_hash = mdc + 2;
1655 
1656 		if (__ops_get_debug_level(__FILE__)) {
1657 			unsigned	i;
1658 
1659 			fprintf(stderr, "\nplaintext (len=%" PRIsize "u): ",
1660 				sz_plaintext);
1661 			for (i = 0; i < sz_plaintext; i++)
1662 				fprintf(stderr, " 0x%02x", plaintext[i]);
1663 			fprintf(stderr, "\n");
1664 
1665 			fprintf(stderr, "\nmdc (len=%" PRIsize "u): ", sz_mdc);
1666 			for (i = 0; i < sz_mdc; i++)
1667 				fprintf(stderr, " 0x%02x", mdc[i]);
1668 			fprintf(stderr, "\n");
1669 		}
1670 		__ops_calc_mdc_hash(preamble, sz_preamble, plaintext,
1671 				sz_plaintext, hashed);
1672 
1673 		if (memcmp(mdc_hash, hashed, OPS_SHA1_HASH_SIZE) != 0) {
1674 			OPS_ERROR(errors, OPS_E_V_BAD_HASH,
1675 					"Bad hash in MDC packet");
1676 			free(buf);
1677 			return 0;
1678 		}
1679 		/* all done with the checks */
1680 		/* now can start reading from the plaintext */
1681 		if (se_ip->plaintext) {
1682 			(void) fprintf(stderr,
1683 				"se_ip_data_reader: bad plaintext\n");
1684 			return 0;
1685 		}
1686 		if ((se_ip->plaintext = calloc(1, sz_plaintext)) == NULL) {
1687 			(void) fprintf(stderr,
1688 				"se_ip_data_reader: bad alloc\n");
1689 			return 0;
1690 		}
1691 		memcpy(se_ip->plaintext, plaintext, sz_plaintext);
1692 		se_ip->plaintext_available = sz_plaintext;
1693 
1694 		se_ip->passed_checks = 1;
1695 
1696 		free(buf);
1697 	}
1698 	n = len;
1699 	if (n > se_ip->plaintext_available) {
1700 		n = se_ip->plaintext_available;
1701 	}
1702 
1703 	memcpy(dest_, se_ip->plaintext + se_ip->plaintext_offset, n);
1704 	se_ip->plaintext_available -= n;
1705 	se_ip->plaintext_offset += n;
1706 	/* len -= n; - not used at all, for info only */
1707 
1708 	return n;
1709 }
1710 
1711 static void
1712 se_ip_data_destroyer(__ops_reader_t *readinfo)
1713 {
1714 	decrypt_se_ip_t	*se_ip;
1715 
1716 	se_ip = __ops_reader_get_arg(readinfo);
1717 	free(se_ip->plaintext);
1718 	free(se_ip);
1719 }
1720 
1721 /**
1722    \ingroup Internal_Readers_SEIP
1723 */
1724 void
1725 __ops_reader_push_se_ip_data(__ops_stream_t *stream, __ops_crypt_t *decrypt,
1726 			   __ops_region_t * region)
1727 {
1728 	decrypt_se_ip_t *se_ip;
1729 
1730 	if ((se_ip = calloc(1, sizeof(*se_ip))) == NULL) {
1731 		(void) fprintf(stderr, "__ops_reader_push_se_ip_data: bad alloc\n");
1732 	} else {
1733 		se_ip->region = region;
1734 		se_ip->decrypt = decrypt;
1735 		__ops_reader_push(stream, se_ip_data_reader, se_ip_data_destroyer,
1736 				se_ip);
1737 	}
1738 }
1739 
1740 /**
1741    \ingroup Internal_Readers_SEIP
1742  */
1743 void
1744 __ops_reader_pop_se_ip_data(__ops_stream_t *stream)
1745 {
1746 	/*
1747 	 * decrypt_se_ip_t
1748 	 * *se_ip=__ops_reader_get_arg(__ops_readinfo(stream));
1749 	 */
1750 	/* free(se_ip); */
1751 	__ops_reader_pop(stream);
1752 }
1753 
1754 /**************************************************************************/
1755 
1756 /** Arguments for reader_fd
1757  */
1758 typedef struct mmap_reader_t {
1759 	void		*mem;		/* memory mapped file */
1760 	uint64_t	 size;		/* size of file */
1761 	uint64_t	 offset;	/* current offset in file */
1762 	int		 fd;		/* file descriptor */
1763 } mmap_reader_t;
1764 
1765 
1766 /**
1767  * \ingroup Core_Readers
1768  *
1769  * __ops_reader_fd() attempts to read up to "plength" bytes from the file
1770  * descriptor in "parse_info" into the buffer starting at "dest" using the
1771  * rules contained in "flags"
1772  *
1773  * \param	dest	Pointer to previously allocated buffer
1774  * \param	plength Number of bytes to try to read
1775  * \param	flags	Rules about reading to use
1776  * \param	readinfo	Reader info
1777  * \param	cbinfo	Callback info
1778  *
1779  * \return	n	Number of bytes read
1780  *
1781  * OPS_R_EARLY_EOF and OPS_R_ERROR push errors on the stack
1782  */
1783 static int
1784 fd_reader(void *dest, size_t length, __ops_error_t **errors,
1785 	  __ops_reader_t *readinfo, __ops_cbdata_t *cbinfo)
1786 {
1787 	mmap_reader_t *reader = __ops_reader_get_arg(readinfo);
1788 	int             n = read(reader->fd, dest, length);
1789 
1790 	__OPS_USED(cbinfo);
1791 	if (n == 0)
1792 		return 0;
1793 	if (n < 0) {
1794 		OPS_SYSTEM_ERROR_1(errors, OPS_E_R_READ_FAILED, "read",
1795 				   "file descriptor %d", reader->fd);
1796 		return -1;
1797 	}
1798 	return n;
1799 }
1800 
1801 static void
1802 reader_fd_destroyer(__ops_reader_t *readinfo)
1803 {
1804 	free(__ops_reader_get_arg(readinfo));
1805 }
1806 
1807 /**
1808    \ingroup Core_Readers_First
1809    \brief Starts stack with file reader
1810 */
1811 
1812 void
1813 __ops_reader_set_fd(__ops_stream_t *stream, int fd)
1814 {
1815 	mmap_reader_t *reader;
1816 
1817 	if ((reader = calloc(1, sizeof(*reader))) == NULL) {
1818 		(void) fprintf(stderr, "__ops_reader_set_fd: bad alloc\n");
1819 	} else {
1820 		reader->fd = fd;
1821 		__ops_reader_set(stream, fd_reader, reader_fd_destroyer, reader);
1822 	}
1823 }
1824 
1825 /**************************************************************************/
1826 
1827 typedef struct {
1828 	const unsigned char *buffer;
1829 	size_t          length;
1830 	size_t          offset;
1831 }               reader_mem_t;
1832 
1833 static int
1834 mem_reader(void *dest, size_t length, __ops_error_t **errors,
1835 	   __ops_reader_t *readinfo, __ops_cbdata_t *cbinfo)
1836 {
1837 	reader_mem_t *reader = __ops_reader_get_arg(readinfo);
1838 	unsigned        n;
1839 
1840 	__OPS_USED(cbinfo);
1841 	__OPS_USED(errors);
1842 
1843 	if (reader->offset + length > reader->length)
1844 		n = reader->length - reader->offset;
1845 	else
1846 		n = length;
1847 
1848 	if (n == 0)
1849 		return 0;
1850 
1851 	memcpy(dest, reader->buffer + reader->offset, n);
1852 	reader->offset += n;
1853 
1854 	return n;
1855 }
1856 
1857 static void
1858 mem_destroyer(__ops_reader_t *readinfo)
1859 {
1860 	free(__ops_reader_get_arg(readinfo));
1861 }
1862 
1863 /**
1864    \ingroup Core_Readers_First
1865    \brief Starts stack with memory reader
1866 */
1867 
1868 void
1869 __ops_reader_set_memory(__ops_stream_t *stream, const void *buffer,
1870 		      size_t length)
1871 {
1872 	reader_mem_t *mem;
1873 
1874 	if ((mem = calloc(1, sizeof(*mem))) == NULL) {
1875 		(void) fprintf(stderr, "__ops_reader_set_memory: bad alloc\n");
1876 	} else {
1877 		mem->buffer = buffer;
1878 		mem->length = length;
1879 		mem->offset = 0;
1880 		__ops_reader_set(stream, mem_reader, mem_destroyer, mem);
1881 	}
1882 }
1883 
1884 /**************************************************************************/
1885 
1886 /**
1887  \ingroup Core_Writers
1888  \brief Create and initialise output and mem; Set for writing to mem
1889  \param output Address where new output pointer will be set
1890  \param mem Address when new mem pointer will be set
1891  \param bufsz Initial buffer size (will automatically be increased when necessary)
1892  \note It is the caller's responsiblity to free output and mem.
1893  \sa __ops_teardown_memory_write()
1894 */
1895 void
1896 __ops_setup_memory_write(__ops_output_t **output, __ops_memory_t **mem, size_t bufsz)
1897 {
1898 	/*
1899          * initialise needed structures for writing to memory
1900          */
1901 
1902 	*output = __ops_output_new();
1903 	*mem = __ops_memory_new();
1904 
1905 	__ops_memory_init(*mem, bufsz);
1906 
1907 	__ops_writer_set_memory(*output, *mem);
1908 }
1909 
1910 /**
1911    \ingroup Core_Writers
1912    \brief Closes writer and frees output and mem
1913    \param output
1914    \param mem
1915    \sa __ops_setup_memory_write()
1916 */
1917 void
1918 __ops_teardown_memory_write(__ops_output_t *output, __ops_memory_t *mem)
1919 {
1920 	__ops_writer_close(output);/* new */
1921 	__ops_output_delete(output);
1922 	__ops_memory_free(mem);
1923 }
1924 
1925 /**
1926    \ingroup Core_Readers
1927    \brief Create parse_info and sets to read from memory
1928    \param stream Address where new parse_info will be set
1929    \param mem Memory to read from
1930    \param arg Reader-specific arg
1931    \param callback Callback to use with reader
1932    \param accumulate Set if we need to accumulate as we read. (Usually 0 unless doing signature verification)
1933    \note It is the caller's responsiblity to free parse_info
1934    \sa __ops_teardown_memory_read()
1935 */
1936 void
1937 __ops_setup_memory_read(__ops_io_t *io,
1938 			__ops_stream_t **stream,
1939 			__ops_memory_t *mem,
1940 			void *vp,
1941 			__ops_cb_ret_t callback(const __ops_packet_t *,
1942 						__ops_cbdata_t *),
1943 			unsigned accumulate)
1944 {
1945 	*stream = __ops_new(sizeof(**stream));
1946 	(*stream)->io = (*stream)->cbinfo.io = io;
1947 	__ops_set_callback(*stream, callback, vp);
1948 	__ops_reader_set_memory(*stream,
1949 			      __ops_mem_data(mem),
1950 			      __ops_mem_len(mem));
1951 	if (accumulate) {
1952 		(*stream)->readinfo.accumulate = 1;
1953 	}
1954 }
1955 
1956 /**
1957    \ingroup Core_Readers
1958    \brief Frees stream and mem
1959    \param stream
1960    \param mem
1961    \sa __ops_setup_memory_read()
1962 */
1963 void
1964 __ops_teardown_memory_read(__ops_stream_t *stream, __ops_memory_t *mem)
1965 {
1966 	__ops_stream_delete(stream);
1967 	__ops_memory_free(mem);
1968 }
1969 
1970 /**
1971  \ingroup Core_Writers
1972  \brief Create and initialise output and mem; Set for writing to file
1973  \param output Address where new output pointer will be set
1974  \param filename File to write to
1975  \param allow_overwrite Allows file to be overwritten, if set.
1976  \return Newly-opened file descriptor
1977  \note It is the caller's responsiblity to free output and to close fd.
1978  \sa __ops_teardown_file_write()
1979 */
1980 int
1981 __ops_setup_file_write(__ops_output_t **output, const char *filename,
1982 			unsigned allow_overwrite)
1983 {
1984 	int             fd = 0;
1985 	int             flags = 0;
1986 
1987 	/*
1988          * initialise needed structures for writing to file
1989          */
1990 	if (filename == NULL) {
1991 		/* write to stdout */
1992 		fd = STDOUT_FILENO;
1993 	} else {
1994 		flags = O_WRONLY | O_CREAT;
1995 		if (allow_overwrite)
1996 			flags |= O_TRUNC;
1997 		else
1998 			flags |= O_EXCL;
1999 #ifdef O_BINARY
2000 		flags |= O_BINARY;
2001 #endif
2002 		fd = open(filename, flags, 0600);
2003 		if (fd < 0) {
2004 			perror(filename);
2005 			return fd;
2006 		}
2007 	}
2008 	*output = __ops_output_new();
2009 	__ops_writer_set_fd(*output, fd);
2010 	return fd;
2011 }
2012 
2013 /**
2014    \ingroup Core_Writers
2015    \brief Closes writer, frees info, closes fd
2016    \param output
2017    \param fd
2018 */
2019 void
2020 __ops_teardown_file_write(__ops_output_t *output, int fd)
2021 {
2022 	__ops_writer_close(output);
2023 	close(fd);
2024 	__ops_output_delete(output);
2025 }
2026 
2027 /**
2028    \ingroup Core_Writers
2029    \brief As __ops_setup_file_write, but appends to file
2030 */
2031 int
2032 __ops_setup_file_append(__ops_output_t **output, const char *filename)
2033 {
2034 	int             fd;
2035 	/*
2036          * initialise needed structures for writing to file
2037          */
2038 
2039 #ifdef O_BINARY
2040 	fd = open(filename, O_WRONLY | O_APPEND | O_BINARY, 0600);
2041 #else
2042 	fd = open(filename, O_WRONLY | O_APPEND, 0600);
2043 #endif
2044 	if (fd < 0) {
2045 		perror(filename);
2046 		return fd;
2047 	}
2048 	*output = __ops_output_new();
2049 
2050 	__ops_writer_set_fd(*output, fd);
2051 
2052 	return fd;
2053 }
2054 
2055 /**
2056    \ingroup Core_Writers
2057    \brief As __ops_teardown_file_write()
2058 */
2059 void
2060 __ops_teardown_file_append(__ops_output_t *output, int fd)
2061 {
2062 	__ops_teardown_file_write(output, fd);
2063 }
2064 
2065 /**
2066    \ingroup Core_Readers
2067    \brief Creates parse_info, opens file, and sets to read from file
2068    \param stream Address where new parse_info will be set
2069    \param filename Name of file to read
2070    \param vp Reader-specific arg
2071    \param callback Callback to use when reading
2072    \param accumulate Set if we need to accumulate as we read. (Usually 0 unless doing signature verification)
2073    \note It is the caller's responsiblity to free parse_info and to close fd
2074    \sa __ops_teardown_file_read()
2075 */
2076 int
2077 __ops_setup_file_read(__ops_io_t *io,
2078 			__ops_stream_t **stream,
2079 			const char *filename,
2080 			void *vp,
2081 			__ops_cb_ret_t callback(const __ops_packet_t *,
2082 						__ops_cbdata_t *),
2083 			unsigned accumulate)
2084 {
2085 	int	fd;
2086 
2087 #ifdef O_BINARY
2088 	fd = open(filename, O_RDONLY | O_BINARY);
2089 #else
2090 	fd = open(filename, O_RDONLY);
2091 #endif
2092 	if (fd < 0) {
2093 		(void) fprintf(io->errs, "can't open \"%s\"\n", filename);
2094 		return fd;
2095 	}
2096 	*stream = __ops_new(sizeof(**stream));
2097 	(*stream)->io = (*stream)->cbinfo.io = io;
2098 	__ops_set_callback(*stream, callback, vp);
2099 #ifdef USE_MMAP_FOR_FILES
2100 	__ops_reader_set_mmap(*stream, fd);
2101 #else
2102 	__ops_reader_set_fd(*stream, fd);
2103 #endif
2104 	if (accumulate) {
2105 		(*stream)->readinfo.accumulate = 1;
2106 	}
2107 	return fd;
2108 }
2109 
2110 /**
2111    \ingroup Core_Readers
2112    \brief Frees stream and closes fd
2113    \param stream
2114    \param fd
2115    \sa __ops_setup_file_read()
2116 */
2117 void
2118 __ops_teardown_file_read(__ops_stream_t *stream, int fd)
2119 {
2120 	close(fd);
2121 	__ops_stream_delete(stream);
2122 }
2123 
2124 __ops_cb_ret_t
2125 litdata_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
2126 {
2127 	const __ops_contents_t	*content = &pkt->u;
2128 
2129 	if (__ops_get_debug_level(__FILE__)) {
2130 		printf("litdata_cb: ");
2131 		__ops_print_packet(&cbinfo->printstate, pkt);
2132 	}
2133 	/* Read data from packet into static buffer */
2134 	switch (pkt->tag) {
2135 	case OPS_PTAG_CT_LITDATA_BODY:
2136 		/* if writer enabled, use it */
2137 		if (cbinfo->output) {
2138 			if (__ops_get_debug_level(__FILE__)) {
2139 				printf("litdata_cb: length is %u\n",
2140 					content->litdata_body.length);
2141 			}
2142 			__ops_write(cbinfo->output,
2143 					content->litdata_body.data,
2144 					content->litdata_body.length);
2145 		}
2146 		break;
2147 
2148 	case OPS_PTAG_CT_LITDATA_HEADER:
2149 		/* ignore */
2150 		break;
2151 
2152 	default:
2153 		break;
2154 	}
2155 
2156 	return OPS_RELEASE_MEMORY;
2157 }
2158 
2159 __ops_cb_ret_t
2160 pk_sesskey_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
2161 {
2162 	const __ops_contents_t	*content = &pkt->u;
2163 	unsigned		 from;
2164 	__ops_io_t		*io;
2165 
2166 	io = cbinfo->io;
2167 	if (__ops_get_debug_level(__FILE__)) {
2168 		__ops_print_packet(&cbinfo->printstate, pkt);
2169 	}
2170 	/* Read data from packet into static buffer */
2171 	switch (pkt->tag) {
2172 	case OPS_PTAG_CT_PK_SESSION_KEY:
2173 		if (__ops_get_debug_level(__FILE__)) {
2174 			printf("OPS_PTAG_CT_PK_SESSION_KEY\n");
2175 		}
2176 		if (!cbinfo->cryptinfo.keyring) {
2177 			(void) fprintf(io->errs,
2178 				"pk_sesskey_cb: bad keyring\n");
2179 			return (__ops_cb_ret_t)0;
2180 		}
2181 		from = 0;
2182 		cbinfo->cryptinfo.keydata =
2183 			__ops_getkeybyid(io, cbinfo->cryptinfo.keyring,
2184 				content->pk_sesskey.key_id, &from);
2185 		if (!cbinfo->cryptinfo.keydata) {
2186 			break;
2187 		}
2188 		break;
2189 
2190 	default:
2191 		break;
2192 	}
2193 
2194 	return OPS_RELEASE_MEMORY;
2195 }
2196 
2197 /**
2198  \ingroup Core_Callbacks
2199 
2200 \brief Callback to get secret key, decrypting if necessary.
2201 
2202 @verbatim
2203  This callback does the following:
2204  * finds the session key in the keyring
2205  * gets a passphrase if required
2206  * decrypts the secret key, if necessary
2207  * sets the seckey in the content struct
2208 @endverbatim
2209 */
2210 
2211 __ops_cb_ret_t
2212 get_seckey_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
2213 {
2214 	const __ops_contents_t	*content = &pkt->u;
2215 	const __ops_seckey_t	*secret;
2216 	const __ops_key_t	*keypair;
2217 	unsigned		 from;
2218 	__ops_io_t		*io;
2219 
2220 	io = cbinfo->io;
2221 	if (__ops_get_debug_level(__FILE__)) {
2222 		__ops_print_packet(&cbinfo->printstate, pkt);
2223 	}
2224 	switch (pkt->tag) {
2225 	case OPS_GET_SECKEY:
2226 		from = 0;
2227 		cbinfo->cryptinfo.keydata =
2228 			__ops_getkeybyid(io, cbinfo->cryptinfo.keyring,
2229 				content->get_seckey.pk_sesskey->key_id,
2230 				&from);
2231 		if (!cbinfo->cryptinfo.keydata ||
2232 		    !__ops_is_key_secret(cbinfo->cryptinfo.keydata)) {
2233 			return (__ops_cb_ret_t)0;
2234 		}
2235 
2236 		keypair = cbinfo->cryptinfo.keydata;
2237 		do {
2238 			/* print out the user id */
2239 			__ops_print_keydata(io, keypair, "pub", &keypair->key.pubkey);
2240 			/* now decrypt key */
2241 			secret = __ops_decrypt_seckey(keypair, NULL); /* XXX - agc */
2242 			if (secret == NULL) {
2243 				(void) fprintf(io->errs, "Bad passphrase\n");
2244 			}
2245 		} while (secret == NULL);
2246 		*content->get_seckey.seckey = secret;
2247 		break;
2248 
2249 	default:
2250 		break;
2251 	}
2252 
2253 	return OPS_RELEASE_MEMORY;
2254 }
2255 
2256 /**
2257  \ingroup HighLevel_Callbacks
2258  \brief Callback to use when you need to prompt user for passphrase
2259  \param contents
2260  \param cbinfo
2261 */
2262 __ops_cb_ret_t
2263 get_passphrase_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
2264 {
2265 	const __ops_contents_t	*content = &pkt->u;
2266 	__ops_io_t		*io;
2267 
2268 	io = cbinfo->io;
2269 	if (__ops_get_debug_level(__FILE__)) {
2270 		__ops_print_packet(&cbinfo->printstate, pkt);
2271 	}
2272 	if (cbinfo->cryptinfo.keydata == NULL) {
2273 		(void) fprintf(io->errs, "get_passphrase_cb: NULL keydata\n");
2274 	} else {
2275 		__ops_print_keydata(io, cbinfo->cryptinfo.keydata, "pub",
2276 			&cbinfo->cryptinfo.keydata->key.pubkey);
2277 	}
2278 	switch (pkt->tag) {
2279 	case OPS_GET_PASSPHRASE:
2280 		*(content->skey_passphrase.passphrase) =
2281 				strdup(getpass("netpgp passphrase: "));
2282 		return OPS_KEEP_MEMORY;
2283 	default:
2284 		break;
2285 	}
2286 	return OPS_RELEASE_MEMORY;
2287 }
2288 
2289 unsigned
2290 __ops_reader_set_accumulate(__ops_stream_t *stream, unsigned state)
2291 {
2292 	return stream->readinfo.accumulate = state;
2293 }
2294 
2295 /**************************************************************************/
2296 
2297 static int
2298 hash_reader(void *dest,
2299 		size_t length,
2300 		__ops_error_t **errors,
2301 		__ops_reader_t *readinfo,
2302 		__ops_cbdata_t *cbinfo)
2303 {
2304 	__ops_hash_t	*hash = __ops_reader_get_arg(readinfo);
2305 	int		 r;
2306 
2307 	r = __ops_stacked_read(dest, length, errors, readinfo, cbinfo);
2308 	if (r <= 0) {
2309 		return r;
2310 	}
2311 	hash->add(hash, dest, (unsigned)r);
2312 	return r;
2313 }
2314 
2315 /**
2316    \ingroup Internal_Readers_Hash
2317    \brief Push hashed data reader on stack
2318 */
2319 void
2320 __ops_reader_push_hash(__ops_stream_t *stream, __ops_hash_t *hash)
2321 {
2322 	if (!hash->init(hash)) {
2323 		(void) fprintf(stderr, "__ops_reader_push_hash: can't init hash\n");
2324 		/* just continue and die */
2325 		/* XXX - agc - no way to return failure */
2326 	}
2327 	__ops_reader_push(stream, hash_reader, NULL, hash);
2328 }
2329 
2330 /**
2331    \ingroup Internal_Readers_Hash
2332    \brief Pop hashed data reader from stack
2333 */
2334 void
2335 __ops_reader_pop_hash(__ops_stream_t *stream)
2336 {
2337 	__ops_reader_pop(stream);
2338 }
2339 
2340 /* read memory from the previously mmap-ed file */
2341 static int
2342 mmap_reader(void *dest, size_t length, __ops_error_t **errors,
2343 	  __ops_reader_t *readinfo, __ops_cbdata_t *cbinfo)
2344 {
2345 	mmap_reader_t	*mem = __ops_reader_get_arg(readinfo);
2346 	unsigned	 n;
2347 	char		*cmem = mem->mem;
2348 
2349 	__OPS_USED(errors);
2350 	__OPS_USED(cbinfo);
2351 	n = MIN(length, (unsigned)(mem->size - mem->offset));
2352 	if (n > 0) {
2353 		(void) memcpy(dest, &cmem[(int)mem->offset], (unsigned)n);
2354 		mem->offset += n;
2355 	}
2356 	return n;
2357 }
2358 
2359 /* tear down the mmap, close the fd */
2360 static void
2361 mmap_destroyer(__ops_reader_t *readinfo)
2362 {
2363 	mmap_reader_t *mem = __ops_reader_get_arg(readinfo);
2364 
2365 	(void) munmap(mem->mem, (unsigned)mem->size);
2366 	(void) close(mem->fd);
2367 	free(__ops_reader_get_arg(readinfo));
2368 }
2369 
2370 /* set up the file to use mmap-ed memory if available, file IO otherwise */
2371 void
2372 __ops_reader_set_mmap(__ops_stream_t *stream, int fd)
2373 {
2374 	mmap_reader_t	*mem;
2375 	struct stat	 st;
2376 
2377 	if (fstat(fd, &st) != 0) {
2378 		(void) fprintf(stderr, "__ops_reader_set_mmap: can't fstat\n");
2379 	} else if ((mem = calloc(1, sizeof(*mem))) == NULL) {
2380 		(void) fprintf(stderr, "__ops_reader_set_mmap: bad alloc\n");
2381 	} else {
2382 		mem->size = (uint64_t)st.st_size;
2383 		mem->offset = 0;
2384 		mem->fd = fd;
2385 		mem->mem = mmap(NULL, (size_t)st.st_size, PROT_READ,
2386 				MAP_PRIVATE | MAP_FILE, fd, 0);
2387 		if (mem->mem == MAP_FAILED) {
2388 			__ops_reader_set(stream, fd_reader, reader_fd_destroyer,
2389 					mem);
2390 		} else {
2391 			__ops_reader_set(stream, mmap_reader, mmap_destroyer,
2392 					mem);
2393 		}
2394 	}
2395 }
2396