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