xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/reader.c (revision 179b12252ecaf3553d9c2b7458ce62b6a2203d0c)
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.42 2010/08/15 16:36:24 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 "netpgpsdk.h"
134 #include "netpgpdefs.h"
135 #include "netpgpdigest.h"
136 
137 
138 /* get a pass phrase from the user */
139 int
140 __ops_getpassphrase(void *in, char *phrase, size_t size)
141 {
142 	char	*p;
143 
144 	if (in == NULL) {
145 		while ((p = getpass("netpgp passphrase: ")) == NULL) {
146 		}
147 		(void) snprintf(phrase, size, "%s", p);
148 	} else {
149 		if (fgets(phrase, (int)size, in) == NULL) {
150 			return 0;
151 		}
152 		phrase[strlen(phrase) - 1] = 0x0;
153 	}
154 	return 1;
155 }
156 
157 /**
158  * \ingroup Internal_Readers_Generic
159  * \brief Starts reader stack
160  * \param stream Parse settings
161  * \param reader Reader to use
162  * \param destroyer Destroyer to use
163  * \param vp Reader-specific arg
164  */
165 void
166 __ops_reader_set(__ops_stream_t *stream,
167 		__ops_reader_func_t *reader,
168 		__ops_reader_destroyer_t *destroyer,
169 		void *vp)
170 {
171 	stream->readinfo.reader = reader;
172 	stream->readinfo.destroyer = destroyer;
173 	stream->readinfo.arg = vp;
174 }
175 
176 /**
177  * \ingroup Internal_Readers_Generic
178  * \brief Adds to reader stack
179  * \param stream Parse settings
180  * \param reader Reader to use
181  * \param destroyer Reader's destroyer
182  * \param vp Reader-specific arg
183  */
184 void
185 __ops_reader_push(__ops_stream_t *stream,
186 		__ops_reader_func_t *reader,
187 		__ops_reader_destroyer_t *destroyer,
188 		void *vp)
189 {
190 	__ops_reader_t *readinfo;
191 
192 	if ((readinfo = calloc(1, sizeof(*readinfo))) == NULL) {
193 		(void) fprintf(stderr, "__ops_reader_push: bad alloc\n");
194 	} else {
195 		*readinfo = stream->readinfo;
196 		(void) memset(&stream->readinfo, 0x0, sizeof(stream->readinfo));
197 		stream->readinfo.next = readinfo;
198 		stream->readinfo.parent = stream;
199 
200 		/* should copy accumulate flags from other reader? RW */
201 		stream->readinfo.accumulate = readinfo->accumulate;
202 
203 		__ops_reader_set(stream, reader, destroyer, vp);
204 	}
205 }
206 
207 /**
208  * \ingroup Internal_Readers_Generic
209  * \brief Removes from reader stack
210  * \param stream Parse settings
211  */
212 void
213 __ops_reader_pop(__ops_stream_t *stream)
214 {
215 	__ops_reader_t *next = stream->readinfo.next;
216 
217 	stream->readinfo = *next;
218 	free(next);
219 }
220 
221 /**
222  * \ingroup Internal_Readers_Generic
223  * \brief Gets arg from reader
224  * \param readinfo Reader info
225  * \return Pointer to reader info's arg
226  */
227 void           *
228 __ops_reader_get_arg(__ops_reader_t *readinfo)
229 {
230 	return readinfo->arg;
231 }
232 
233 /**************************************************************************/
234 
235 #define CRC24_POLY 0x1864cfbL
236 
237 enum {
238 	NONE = 0,
239 	BEGIN_PGP_MESSAGE,
240 	BEGIN_PGP_PUBLIC_KEY_BLOCK,
241 	BEGIN_PGP_PRIVATE_KEY_BLOCK,
242 	BEGIN_PGP_MULTI,
243 	BEGIN_PGP_SIGNATURE,
244 
245 	END_PGP_MESSAGE,
246 	END_PGP_PUBLIC_KEY_BLOCK,
247 	END_PGP_PRIVATE_KEY_BLOCK,
248 	END_PGP_MULTI,
249 	END_PGP_SIGNATURE,
250 
251 	BEGIN_PGP_SIGNED_MESSAGE
252 };
253 
254 /**
255  * \struct dearmour_t
256  */
257 typedef struct {
258 	enum {
259 		OUTSIDE_BLOCK = 0,
260 		BASE64,
261 		AT_TRAILER_NAME
262 	} state;
263 	int		lastseen;
264 	__ops_stream_t *parse_info;
265 	unsigned	seen_nl:1;
266 	unsigned	prev_nl:1;
267 	unsigned	allow_headers_without_gap:1;
268 			/* !< allow headers in armoured data that are
269 			* not separated from the data by a blank line
270 			* */
271 	unsigned	allow_no_gap:1;
272 			/* !< allow no blank line at the start of
273 			* armoured data */
274 	unsigned	allow_trailing_whitespace:1;
275 			/* !< allow armoured stuff to have trailing
276 			* whitespace where we wouldn't strictly expect
277 			* it */
278 	/* it is an error to get a cleartext message without a sig */
279 	unsigned   	expect_sig:1;
280 	unsigned   	got_sig:1;
281 	/* base64 stuff */
282 	unsigned        buffered;
283 	uint8_t		buffer[3];
284 	unsigned	eof64;
285 	uint32_t   checksum;
286 	uint32_t   read_checksum;
287 	/* unarmoured text blocks */
288 	uint8_t   unarmoured[NETPGP_BUFSIZ];
289 	size_t          unarmoredc;
290 	/* pushed back data (stored backwards) */
291 	uint8_t  *pushback;
292 	unsigned        pushbackc;
293 	/* armoured block headers */
294 	__ops_headers_t	headers;
295 } dearmour_t;
296 
297 static void
298 push_back(dearmour_t *dearmour, const uint8_t *buf,
299 	  unsigned length)
300 {
301 	unsigned        n;
302 
303 	if (dearmour->pushback) {
304 		(void) fprintf(stderr, "push_back: already pushed back\n");
305 	} else if ((dearmour->pushback = calloc(1, length)) == NULL) {
306 		(void) fprintf(stderr, "push_back: bad alloc\n");
307 	} else {
308 		for (n = 0; n < length; ++n) {
309 			dearmour->pushback[n] = buf[(length - n) - 1];
310 		}
311 		dearmour->pushbackc = length;
312 	}
313 }
314 
315 /* this struct holds a textual header line */
316 typedef struct headerline_t {
317 	const char	*s;		/* the header line */
318 	size_t		 len;		/* its length */
319 	int		 type;		/* the defined type */
320 } headerline_t;
321 
322 static headerline_t	headerlines[] = {
323 	{ "BEGIN PGP MESSAGE",		17, BEGIN_PGP_MESSAGE },
324 	{ "BEGIN PGP PUBLIC KEY BLOCK",	26, BEGIN_PGP_PUBLIC_KEY_BLOCK },
325 	{ "BEGIN PGP PRIVATE KEY BLOCK",27, BEGIN_PGP_PRIVATE_KEY_BLOCK },
326 	{ "BEGIN PGP MESSAGE, PART ",	25, BEGIN_PGP_MULTI },
327 	{ "BEGIN PGP SIGNATURE",	19, BEGIN_PGP_SIGNATURE },
328 
329 	{ "END PGP MESSAGE",		15, END_PGP_MESSAGE },
330 	{ "END PGP PUBLIC KEY BLOCK",	24, END_PGP_PUBLIC_KEY_BLOCK },
331 	{ "END PGP PRIVATE KEY BLOCK",	25, END_PGP_PRIVATE_KEY_BLOCK },
332 	{ "END PGP MESSAGE, PART ",	22, END_PGP_MULTI },
333 	{ "END PGP SIGNATURE",		17, END_PGP_SIGNATURE },
334 
335 	{ "BEGIN PGP SIGNED MESSAGE",	24, BEGIN_PGP_SIGNED_MESSAGE },
336 
337 	{ NULL,				0, -1	}
338 };
339 
340 /* search through the table of header lines */
341 static int
342 findheaderline(char *headerline)
343 {
344 	headerline_t	*hp;
345 
346 	for (hp = headerlines ; hp->s ; hp++) {
347 		if (strncmp(headerline, hp->s, hp->len) == 0) {
348 			break;
349 		}
350 	}
351 	return hp->type;
352 }
353 
354 static int
355 set_lastseen_headerline(dearmour_t *dearmour, char *hdr, __ops_error_t **errors)
356 {
357 	int	lastseen;
358 	int	prev;
359 
360 	prev = dearmour->lastseen;
361 	if ((lastseen = findheaderline(hdr)) == -1) {
362 		OPS_ERROR_1(errors, OPS_E_R_BAD_FORMAT,
363 			"Unrecognised Header Line %s", hdr);
364 		return 0;
365 	}
366 	dearmour->lastseen = lastseen;
367 	if (__ops_get_debug_level(__FILE__)) {
368 		printf("set header: hdr=%s, dearmour->lastseen=%d, prev=%d\n",
369 			hdr, dearmour->lastseen, prev);
370 	}
371 	switch (dearmour->lastseen) {
372 	case NONE:
373 		OPS_ERROR_1(errors, OPS_E_R_BAD_FORMAT,
374 			"Unrecognised last seen Header Line %s", hdr);
375 		break;
376 
377 	case END_PGP_MESSAGE:
378 		if (prev != BEGIN_PGP_MESSAGE) {
379 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
380 				"Got END PGP MESSAGE, but not after BEGIN");
381 		}
382 		break;
383 
384 	case END_PGP_PUBLIC_KEY_BLOCK:
385 		if (prev != BEGIN_PGP_PUBLIC_KEY_BLOCK) {
386 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
387 			"Got END PGP PUBLIC KEY BLOCK, but not after BEGIN");
388 		}
389 		break;
390 
391 	case END_PGP_PRIVATE_KEY_BLOCK:
392 		if (prev != BEGIN_PGP_PRIVATE_KEY_BLOCK) {
393 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
394 			"Got END PGP PRIVATE KEY BLOCK, but not after BEGIN");
395 		}
396 		break;
397 
398 	case BEGIN_PGP_MULTI:
399 	case END_PGP_MULTI:
400 		OPS_ERROR(errors, OPS_E_R_UNSUPPORTED,
401 			"Multi-part messages are not yet supported");
402 		break;
403 
404 	case END_PGP_SIGNATURE:
405 		if (prev != BEGIN_PGP_SIGNATURE) {
406 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
407 			"Got END PGP SIGNATURE, but not after BEGIN");
408 		}
409 		break;
410 
411 	case BEGIN_PGP_MESSAGE:
412 	case BEGIN_PGP_PUBLIC_KEY_BLOCK:
413 	case BEGIN_PGP_PRIVATE_KEY_BLOCK:
414 	case BEGIN_PGP_SIGNATURE:
415 	case BEGIN_PGP_SIGNED_MESSAGE:
416 		break;
417 	}
418 	return 1;
419 }
420 
421 static int
422 read_char(dearmour_t *dearmour,
423 		__ops_error_t **errors,
424 		__ops_reader_t *readinfo,
425 		__ops_cbdata_t *cbinfo,
426 		unsigned skip)
427 {
428 	uint8_t   c;
429 
430 	do {
431 		if (dearmour->pushbackc) {
432 			c = dearmour->pushback[--dearmour->pushbackc];
433 			if (dearmour->pushbackc == 0) {
434 				free(dearmour->pushback);
435 				dearmour->pushback = NULL;
436 			}
437 		} else if (__ops_stacked_read(&c, 1, errors, readinfo,
438 					cbinfo) != 1) {
439 			return -1;
440 		}
441 	} while (skip && c == '\r');
442 	dearmour->prev_nl = dearmour->seen_nl;
443 	dearmour->seen_nl = c == '\n';
444 	return c;
445 }
446 
447 static int
448 eat_whitespace(int first,
449 	       dearmour_t *dearmour,
450 	       __ops_error_t **errors,
451 	       __ops_reader_t *readinfo,
452 	       __ops_cbdata_t *cbinfo,
453 	       unsigned skip)
454 {
455 	int             c = first;
456 
457 	while (c == ' ' || c == '\t') {
458 		c = read_char(dearmour, errors, readinfo, cbinfo, skip);
459 	}
460 	return c;
461 }
462 
463 static int
464 read_and_eat_whitespace(dearmour_t *dearmour,
465 			__ops_error_t **errors,
466 			__ops_reader_t *readinfo,
467 			__ops_cbdata_t *cbinfo,
468 			unsigned skip)
469 {
470 	int             c;
471 
472 	do {
473 		c = read_char(dearmour, errors, readinfo, cbinfo, skip);
474 	} while (c == ' ' || c == '\t');
475 	return c;
476 }
477 
478 static void
479 flush(dearmour_t *dearmour, __ops_cbdata_t *cbinfo)
480 {
481 	__ops_packet_t	content;
482 
483 	if (dearmour->unarmoredc > 0) {
484 		content.u.unarmoured_text.data = dearmour->unarmoured;
485 		content.u.unarmoured_text.length = (unsigned)dearmour->unarmoredc;
486 		CALLBACK(OPS_PTAG_CT_UNARMOURED_TEXT, cbinfo, &content);
487 		dearmour->unarmoredc = 0;
488 	}
489 }
490 
491 static int
492 unarmoured_read_char(dearmour_t *dearmour,
493 			__ops_error_t **errors,
494 			__ops_reader_t *readinfo,
495 			__ops_cbdata_t *cbinfo,
496 			unsigned skip)
497 {
498 	int             c;
499 
500 	do {
501 		c = read_char(dearmour, errors, readinfo, cbinfo, 0);
502 		if (c < 0) {
503 			return c;
504 		}
505 		dearmour->unarmoured[dearmour->unarmoredc++] = c;
506 		if (dearmour->unarmoredc == sizeof(dearmour->unarmoured)) {
507 			flush(dearmour, cbinfo);
508 		}
509 	} while (skip && c == '\r');
510 	return c;
511 }
512 
513 /**
514  * \param headers
515  * \param key
516  *
517  * \return header value if found, otherwise NULL
518  */
519 static const char *
520 __ops_find_header(__ops_headers_t *headers, const char *key)
521 {
522 	unsigned        n;
523 
524 	for (n = 0; n < headers->headerc; ++n) {
525 		if (strcmp(headers->headers[n].key, key) == 0) {
526 			return headers->headers[n].value;
527 		}
528 	}
529 	return NULL;
530 }
531 
532 /**
533  * \param dest
534  * \param src
535  */
536 static void
537 __ops_dup_headers(__ops_headers_t *dest, const __ops_headers_t *src)
538 {
539 	unsigned        n;
540 
541 	if ((dest->headers = calloc(src->headerc, sizeof(*dest->headers))) == NULL) {
542 		(void) fprintf(stderr, "__ops_dup_headers: bad alloc\n");
543 	} else {
544 		dest->headerc = src->headerc;
545 		for (n = 0; n < src->headerc; ++n) {
546 			dest->headers[n].key = netpgp_strdup(src->headers[n].key);
547 			dest->headers[n].value = netpgp_strdup(src->headers[n].value);
548 		}
549 	}
550 }
551 
552 /*
553  * Note that this skips CRs so implementations always see just straight LFs
554  * as line terminators
555  */
556 static int
557 process_dash_escaped(dearmour_t *dearmour,
558 			__ops_error_t **errors,
559 			__ops_reader_t *readinfo,
560 			__ops_cbdata_t *cbinfo)
561 {
562 	__ops_fixed_body_t	*body;
563 	__ops_packet_t		 content2;
564 	__ops_packet_t		 content;
565 	const char		*hashstr;
566 	__ops_hash_t		*hash;
567 	int			 total;
568 
569 	body = &content.u.cleartext_body;
570 	if ((hash = calloc(1, sizeof(*hash))) == NULL) {
571 		OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
572 			"process_dash_escaped: bad alloc");
573 		return -1;
574 	}
575 	hashstr = __ops_find_header(&dearmour->headers, "Hash");
576 	if (hashstr) {
577 		__ops_hash_alg_t alg;
578 
579 		alg = __ops_str_to_hash_alg(hashstr);
580 		if (!__ops_is_hash_alg_supported(&alg)) {
581 			free(hash);
582 			OPS_ERROR_1(errors, OPS_E_R_BAD_FORMAT,
583 				"Unsupported hash algorithm '%s'", hashstr);
584 			return -1;
585 		}
586 		if (alg == OPS_HASH_UNKNOWN) {
587 			free(hash);
588 			OPS_ERROR_1(errors, OPS_E_R_BAD_FORMAT,
589 				"Unknown hash algorithm '%s'", hashstr);
590 			return -1;
591 		}
592 		__ops_hash_any(hash, alg);
593 	} else {
594 		__ops_hash_md5(hash);
595 	}
596 
597 	if (!hash->init(hash)) {
598 		OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
599 			"can't initialise hash");
600 		return -1;
601 	}
602 
603 	body->length = 0;
604 	total = 0;
605 	for (;;) {
606 		int             c;
607 		unsigned        count;
608 
609 		c = read_char(dearmour, errors, readinfo, cbinfo, 1);
610 		if (c < 0) {
611 			return -1;
612 		}
613 		if (dearmour->prev_nl && c == '-') {
614 			if ((c = read_char(dearmour, errors, readinfo, cbinfo,
615 						0)) < 0) {
616 				return -1;
617 			}
618 			if (c != ' ') {
619 				/* then this had better be a trailer! */
620 				if (c != '-') {
621 					OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
622 						"Bad dash-escaping");
623 				}
624 				for (count = 2; count < 5; ++count) {
625 					if ((c = read_char(dearmour, errors,
626 						readinfo, cbinfo, 0)) < 0) {
627 						return -1;
628 					}
629 					if (c != '-') {
630 						OPS_ERROR(errors,
631 						OPS_E_R_BAD_FORMAT,
632 						"Bad dash-escaping (2)");
633 					}
634 				}
635 				dearmour->state = AT_TRAILER_NAME;
636 				break;
637 			}
638 			/* otherwise we read the next character */
639 			if ((c = read_char(dearmour, errors, readinfo, cbinfo,
640 						0)) < 0) {
641 				return -1;
642 			}
643 		}
644 		if (c == '\n' && body->length) {
645 			if (memchr(body->data + 1, '\n', body->length - 1)
646 						!= NULL) {
647 				(void) fprintf(stderr,
648 				"process_dash_escaped: newline found\n");
649 				return -1;
650 			}
651 			if (body->data[0] == '\n') {
652 				hash->add(hash, (const uint8_t *)"\r", 1);
653 			}
654 			hash->add(hash, body->data, body->length);
655 			if (__ops_get_debug_level(__FILE__)) {
656 				fprintf(stderr, "Got body:\n%s\n", body->data);
657 			}
658 			CALLBACK(OPS_PTAG_CT_SIGNED_CLEARTEXT_BODY, cbinfo,
659 						&content);
660 			body->length = 0;
661 		}
662 		body->data[body->length++] = c;
663 		total += 1;
664 		if (body->length == sizeof(body->data)) {
665 			if (__ops_get_debug_level(__FILE__)) {
666 				(void) fprintf(stderr, "Got body (2):\n%s\n",
667 						body->data);
668 			}
669 			CALLBACK(OPS_PTAG_CT_SIGNED_CLEARTEXT_BODY, cbinfo,
670 					&content);
671 			body->length = 0;
672 		}
673 	}
674 	if (body->data[0] != '\n') {
675 		(void) fprintf(stderr,
676 			"process_dash_escaped: no newline in body data\n");
677 		return -1;
678 	}
679 	if (body->length != 1) {
680 		(void) fprintf(stderr,
681 			"process_dash_escaped: bad body length\n");
682 		return -1;
683 	}
684 
685 	/* don't send that one character, because it's part of the trailer */
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 = netpgp_strdup(key);
711 		dearmour->headers.headers[n].value = netpgp_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, (uint8_t *) 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, uint32_t *pl)
821 {
822 	int             n, c;
823 	uint32_t   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 += (uint32_t)(c - 'A');
837 		} else if (c >= 'a' && c <= 'z') {
838 			l += (uint32_t)(c - 'a') + 26;
839 		} else if (c >= '0' && c <= '9') {
840 			l += (uint32_t)(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, uint8_t 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 (unsigned)(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 	uint32_t   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] = (uint8_t)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 	dearmour_t	*dearmour;
1033 	unsigned	 first;
1034 	uint8_t		*dest = dest_;
1035 	char		 buf[1024];
1036 	int		 saved;
1037 	int              ret;
1038 
1039 	dearmour = __ops_reader_get_arg(readinfo);
1040 	saved = (int)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,
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 = 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 	uint8_t		 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 = (int)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 = (int)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 			uint8_t		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 (int)(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 = (unsigned)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 					hexdump(stderr, "encrypted", buffer, 16);
1469 					hexdump(stderr, "decrypted", encrypted->decrypted, 16);
1470 				}
1471 			} else {
1472 				(void) memcpy(
1473 	&encrypted->decrypted[encrypted->off], buffer, n);
1474 				encrypted->c = n;
1475 			}
1476 
1477 			if (encrypted->c == 0) {
1478 				(void) fprintf(stderr,
1479 				"encrypted_data_reader: 0 decrypted count\n");
1480 				return 0;
1481 			}
1482 
1483 			encrypted->off = 0;
1484 		}
1485 	}
1486 
1487 	return saved;
1488 }
1489 
1490 static void
1491 encrypted_data_destroyer(__ops_reader_t *readinfo)
1492 {
1493 	free(__ops_reader_get_arg(readinfo));
1494 }
1495 
1496 /**
1497  * \ingroup Core_Readers_SE
1498  * \brief Pushes decryption reader onto stack
1499  * \sa __ops_reader_pop_decrypt()
1500  */
1501 void
1502 __ops_reader_push_decrypt(__ops_stream_t *stream, __ops_crypt_t *decrypt,
1503 			__ops_region_t *region)
1504 {
1505 	encrypted_t	*encrypted;
1506 
1507 	if ((encrypted = calloc(1, sizeof(*encrypted))) == NULL) {
1508 		(void) fprintf(stderr, "__ops_reader_push_decrypted: bad alloc\n");
1509 	} else {
1510 		encrypted->decrypt = decrypt;
1511 		encrypted->region = region;
1512 		__ops_decrypt_init(encrypted->decrypt);
1513 		__ops_reader_push(stream, encrypted_data_reader,
1514 			encrypted_data_destroyer, encrypted);
1515 	}
1516 }
1517 
1518 /**
1519  * \ingroup Core_Readers_Encrypted
1520  * \brief Pops decryption reader from stack
1521  * \sa __ops_reader_push_decrypt()
1522  */
1523 void
1524 __ops_reader_pop_decrypt(__ops_stream_t *stream)
1525 {
1526 	encrypted_t	*encrypted;
1527 
1528 	encrypted = __ops_reader_get_arg(__ops_readinfo(stream));
1529 	encrypted->decrypt->decrypt_finish(encrypted->decrypt);
1530 	free(encrypted);
1531 	__ops_reader_pop(stream);
1532 }
1533 
1534 /**************************************************************************/
1535 
1536 typedef struct {
1537 	/* boolean: 0 once we've done the preamble/MDC checks */
1538 	/* and are reading from the plaintext */
1539 	int              passed_checks;
1540 	uint8_t		*plaintext;
1541 	size_t           plaintext_available;
1542 	size_t           plaintext_offset;
1543 	__ops_region_t	*region;
1544 	__ops_crypt_t	*decrypt;
1545 } decrypt_se_ip_t;
1546 
1547 /*
1548   Gets entire SE_IP data packet.
1549   Verifies leading preamble
1550   Verifies trailing MDC packet
1551   Then passes up plaintext as requested
1552 */
1553 static int
1554 se_ip_data_reader(void *dest_,
1555 			size_t len,
1556 			__ops_error_t **errors,
1557 			__ops_reader_t *readinfo,
1558 			__ops_cbdata_t *cbinfo)
1559 {
1560 	decrypt_se_ip_t	*se_ip;
1561 	__ops_region_t	 decrypted_region;
1562 	unsigned	 n = 0;
1563 
1564 	se_ip = __ops_reader_get_arg(readinfo);
1565 	if (!se_ip->passed_checks) {
1566 		uint8_t		*buf = NULL;
1567 		uint8_t		hashed[OPS_SHA1_HASH_SIZE];
1568 		uint8_t		*preamble;
1569 		uint8_t		*plaintext;
1570 		uint8_t		*mdc;
1571 		uint8_t		*mdc_hash;
1572 		__ops_hash_t	hash;
1573 		size_t		b;
1574 		size_t          sz_preamble;
1575 		size_t          sz_mdc_hash;
1576 		size_t          sz_mdc;
1577 		size_t          sz_plaintext;
1578 
1579 		__ops_hash_any(&hash, OPS_HASH_SHA1);
1580 		if (!hash.init(&hash)) {
1581 			(void) fprintf(stderr,
1582 				"se_ip_data_reader: can't init hash\n");
1583 			return -1;
1584 		}
1585 
1586 		__ops_init_subregion(&decrypted_region, NULL);
1587 		decrypted_region.length =
1588 			se_ip->region->length - se_ip->region->readc;
1589 		if ((buf = calloc(1, decrypted_region.length)) == NULL) {
1590 			(void) fprintf(stderr, "se_ip_data_reader: bad alloc\n");
1591 			return -1;
1592 		}
1593 
1594 		/* read entire SE IP packet */
1595 		if (!__ops_stacked_limited_read(buf, decrypted_region.length,
1596 				&decrypted_region, errors, readinfo, cbinfo)) {
1597 			free(buf);
1598 			return -1;
1599 		}
1600 		if (__ops_get_debug_level(__FILE__)) {
1601 			hexdump(stderr, "SE IP packet", buf, decrypted_region.length);
1602 		}
1603 		/* verify leading preamble */
1604 		if (__ops_get_debug_level(__FILE__)) {
1605 			hexdump(stderr, "preamble", buf, se_ip->decrypt->blocksize);
1606 		}
1607 		b = se_ip->decrypt->blocksize;
1608 		if (buf[b - 2] != buf[b] || buf[b - 1] != buf[b + 1]) {
1609 			fprintf(stderr,
1610 			"Bad symmetric decrypt (%02x%02x vs %02x%02x)\n",
1611 				buf[b - 2], buf[b - 1], buf[b], buf[b + 1]);
1612 			OPS_ERROR(errors, OPS_E_PROTO_BAD_SYMMETRIC_DECRYPT,
1613 			"Bad symmetric decrypt when parsing SE IP packet");
1614 			free(buf);
1615 			return -1;
1616 		}
1617 		/* Verify trailing MDC hash */
1618 
1619 		sz_preamble = se_ip->decrypt->blocksize + 2;
1620 		sz_mdc_hash = OPS_SHA1_HASH_SIZE;
1621 		sz_mdc = 1 + 1 + sz_mdc_hash;
1622 		sz_plaintext = (decrypted_region.length - sz_preamble) - sz_mdc;
1623 
1624 		preamble = buf;
1625 		plaintext = buf + sz_preamble;
1626 		mdc = plaintext + sz_plaintext;
1627 		mdc_hash = mdc + 2;
1628 
1629 		if (__ops_get_debug_level(__FILE__)) {
1630 			hexdump(stderr, "plaintext", plaintext, sz_plaintext);
1631 			hexdump(stderr, "mdc", mdc, sz_mdc);
1632 		}
1633 		__ops_calc_mdc_hash(preamble, sz_preamble, plaintext,
1634 				(unsigned)sz_plaintext, hashed);
1635 
1636 		if (memcmp(mdc_hash, hashed, OPS_SHA1_HASH_SIZE) != 0) {
1637 			OPS_ERROR(errors, OPS_E_V_BAD_HASH,
1638 					"Bad hash in MDC packet");
1639 			free(buf);
1640 			return 0;
1641 		}
1642 		/* all done with the checks */
1643 		/* now can start reading from the plaintext */
1644 		if (se_ip->plaintext) {
1645 			(void) fprintf(stderr,
1646 				"se_ip_data_reader: bad plaintext\n");
1647 			return 0;
1648 		}
1649 		if ((se_ip->plaintext = calloc(1, sz_plaintext)) == NULL) {
1650 			(void) fprintf(stderr,
1651 				"se_ip_data_reader: bad alloc\n");
1652 			return 0;
1653 		}
1654 		memcpy(se_ip->plaintext, plaintext, sz_plaintext);
1655 		se_ip->plaintext_available = sz_plaintext;
1656 
1657 		se_ip->passed_checks = 1;
1658 
1659 		free(buf);
1660 	}
1661 	n = (unsigned)len;
1662 	if (n > se_ip->plaintext_available) {
1663 		n = (unsigned)se_ip->plaintext_available;
1664 	}
1665 
1666 	memcpy(dest_, se_ip->plaintext + se_ip->plaintext_offset, n);
1667 	se_ip->plaintext_available -= n;
1668 	se_ip->plaintext_offset += n;
1669 	/* len -= n; - not used at all, for info only */
1670 
1671 	return n;
1672 }
1673 
1674 static void
1675 se_ip_data_destroyer(__ops_reader_t *readinfo)
1676 {
1677 	decrypt_se_ip_t	*se_ip;
1678 
1679 	se_ip = __ops_reader_get_arg(readinfo);
1680 	free(se_ip->plaintext);
1681 	free(se_ip);
1682 }
1683 
1684 /**
1685    \ingroup Internal_Readers_SEIP
1686 */
1687 void
1688 __ops_reader_push_se_ip_data(__ops_stream_t *stream, __ops_crypt_t *decrypt,
1689 			   __ops_region_t * region)
1690 {
1691 	decrypt_se_ip_t *se_ip;
1692 
1693 	if ((se_ip = calloc(1, sizeof(*se_ip))) == NULL) {
1694 		(void) fprintf(stderr, "__ops_reader_push_se_ip_data: bad alloc\n");
1695 	} else {
1696 		se_ip->region = region;
1697 		se_ip->decrypt = decrypt;
1698 		__ops_reader_push(stream, se_ip_data_reader, se_ip_data_destroyer,
1699 				se_ip);
1700 	}
1701 }
1702 
1703 /**
1704    \ingroup Internal_Readers_SEIP
1705  */
1706 void
1707 __ops_reader_pop_se_ip_data(__ops_stream_t *stream)
1708 {
1709 	/*
1710 	 * decrypt_se_ip_t
1711 	 * *se_ip=__ops_reader_get_arg(__ops_readinfo(stream));
1712 	 */
1713 	/* free(se_ip); */
1714 	__ops_reader_pop(stream);
1715 }
1716 
1717 /**************************************************************************/
1718 
1719 /** Arguments for reader_fd
1720  */
1721 typedef struct mmap_reader_t {
1722 	void		*mem;		/* memory mapped file */
1723 	uint64_t	 size;		/* size of file */
1724 	uint64_t	 offset;	/* current offset in file */
1725 	int		 fd;		/* file descriptor */
1726 } mmap_reader_t;
1727 
1728 
1729 /**
1730  * \ingroup Core_Readers
1731  *
1732  * __ops_reader_fd() attempts to read up to "plength" bytes from the file
1733  * descriptor in "parse_info" into the buffer starting at "dest" using the
1734  * rules contained in "flags"
1735  *
1736  * \param	dest	Pointer to previously allocated buffer
1737  * \param	plength Number of bytes to try to read
1738  * \param	flags	Rules about reading to use
1739  * \param	readinfo	Reader info
1740  * \param	cbinfo	Callback info
1741  *
1742  * \return	n	Number of bytes read
1743  *
1744  * OPS_R_EARLY_EOF and OPS_R_ERROR push errors on the stack
1745  */
1746 static int
1747 fd_reader(void *dest, size_t length, __ops_error_t **errors,
1748 	  __ops_reader_t *readinfo, __ops_cbdata_t *cbinfo)
1749 {
1750 	mmap_reader_t	*reader;
1751 	int		 n;
1752 
1753 	__OPS_USED(cbinfo);
1754 	reader = __ops_reader_get_arg(readinfo);
1755 	n = (int)read(reader->fd, dest, length);
1756 	if (n == 0)
1757 		return 0;
1758 	if (n < 0) {
1759 		OPS_SYSTEM_ERROR_1(errors, OPS_E_R_READ_FAILED, "read",
1760 				   "file descriptor %d", reader->fd);
1761 		return -1;
1762 	}
1763 	return n;
1764 }
1765 
1766 static void
1767 reader_fd_destroyer(__ops_reader_t *readinfo)
1768 {
1769 	free(__ops_reader_get_arg(readinfo));
1770 }
1771 
1772 /**
1773    \ingroup Core_Readers_First
1774    \brief Starts stack with file reader
1775 */
1776 
1777 void
1778 __ops_reader_set_fd(__ops_stream_t *stream, int fd)
1779 {
1780 	mmap_reader_t *reader;
1781 
1782 	if ((reader = calloc(1, sizeof(*reader))) == NULL) {
1783 		(void) fprintf(stderr, "__ops_reader_set_fd: bad alloc\n");
1784 	} else {
1785 		reader->fd = fd;
1786 		__ops_reader_set(stream, fd_reader, reader_fd_destroyer, reader);
1787 	}
1788 }
1789 
1790 /**************************************************************************/
1791 
1792 typedef struct {
1793 	const uint8_t *buffer;
1794 	size_t          length;
1795 	size_t          offset;
1796 } reader_mem_t;
1797 
1798 static int
1799 mem_reader(void *dest, size_t length, __ops_error_t **errors,
1800 	   __ops_reader_t *readinfo, __ops_cbdata_t *cbinfo)
1801 {
1802 	reader_mem_t *reader = __ops_reader_get_arg(readinfo);
1803 	unsigned        n;
1804 
1805 	__OPS_USED(cbinfo);
1806 	__OPS_USED(errors);
1807 
1808 	if (reader->offset + length > reader->length)
1809 		n = (unsigned)(reader->length - reader->offset);
1810 	else
1811 		n = (unsigned)length;
1812 
1813 	if (n == (unsigned)0)
1814 		return 0;
1815 
1816 	memcpy(dest, reader->buffer + reader->offset, n);
1817 	reader->offset += n;
1818 
1819 	return n;
1820 }
1821 
1822 static void
1823 mem_destroyer(__ops_reader_t *readinfo)
1824 {
1825 	free(__ops_reader_get_arg(readinfo));
1826 }
1827 
1828 /**
1829    \ingroup Core_Readers_First
1830    \brief Starts stack with memory reader
1831 */
1832 
1833 void
1834 __ops_reader_set_memory(__ops_stream_t *stream, const void *buffer,
1835 		      size_t length)
1836 {
1837 	reader_mem_t *mem;
1838 
1839 	if ((mem = calloc(1, sizeof(*mem))) == NULL) {
1840 		(void) fprintf(stderr, "__ops_reader_set_memory: bad alloc\n");
1841 	} else {
1842 		mem->buffer = buffer;
1843 		mem->length = length;
1844 		mem->offset = 0;
1845 		__ops_reader_set(stream, mem_reader, mem_destroyer, mem);
1846 	}
1847 }
1848 
1849 /**************************************************************************/
1850 
1851 /**
1852  \ingroup Core_Writers
1853  \brief Create and initialise output and mem; Set for writing to mem
1854  \param output Address where new output pointer will be set
1855  \param mem Address when new mem pointer will be set
1856  \param bufsz Initial buffer size (will automatically be increased when necessary)
1857  \note It is the caller's responsiblity to free output and mem.
1858  \sa __ops_teardown_memory_write()
1859 */
1860 void
1861 __ops_setup_memory_write(__ops_output_t **output, __ops_memory_t **mem, size_t bufsz)
1862 {
1863 	/*
1864          * initialise needed structures for writing to memory
1865          */
1866 
1867 	*output = __ops_output_new();
1868 	*mem = __ops_memory_new();
1869 
1870 	__ops_memory_init(*mem, bufsz);
1871 
1872 	__ops_writer_set_memory(*output, *mem);
1873 }
1874 
1875 /**
1876    \ingroup Core_Writers
1877    \brief Closes writer and frees output and mem
1878    \param output
1879    \param mem
1880    \sa __ops_setup_memory_write()
1881 */
1882 void
1883 __ops_teardown_memory_write(__ops_output_t *output, __ops_memory_t *mem)
1884 {
1885 	__ops_writer_close(output);/* new */
1886 	__ops_output_delete(output);
1887 	__ops_memory_free(mem);
1888 }
1889 
1890 /**
1891    \ingroup Core_Readers
1892    \brief Create parse_info and sets to read from memory
1893    \param stream Address where new parse_info will be set
1894    \param mem Memory to read from
1895    \param arg Reader-specific arg
1896    \param callback Callback to use with reader
1897    \param accumulate Set if we need to accumulate as we read. (Usually 0 unless doing signature verification)
1898    \note It is the caller's responsiblity to free parse_info
1899    \sa __ops_teardown_memory_read()
1900 */
1901 void
1902 __ops_setup_memory_read(__ops_io_t *io,
1903 			__ops_stream_t **stream,
1904 			__ops_memory_t *mem,
1905 			void *vp,
1906 			__ops_cb_ret_t callback(const __ops_packet_t *,
1907 						__ops_cbdata_t *),
1908 			unsigned accumulate)
1909 {
1910 	*stream = __ops_new(sizeof(**stream));
1911 	(*stream)->io = (*stream)->cbinfo.io = io;
1912 	__ops_set_callback(*stream, callback, vp);
1913 	__ops_reader_set_memory(*stream,
1914 			      __ops_mem_data(mem),
1915 			      __ops_mem_len(mem));
1916 	if (accumulate) {
1917 		(*stream)->readinfo.accumulate = 1;
1918 	}
1919 }
1920 
1921 /**
1922    \ingroup Core_Readers
1923    \brief Frees stream and mem
1924    \param stream
1925    \param mem
1926    \sa __ops_setup_memory_read()
1927 */
1928 void
1929 __ops_teardown_memory_read(__ops_stream_t *stream, __ops_memory_t *mem)
1930 {
1931 	__ops_stream_delete(stream);
1932 	__ops_memory_free(mem);
1933 }
1934 
1935 /**
1936  \ingroup Core_Writers
1937  \brief Create and initialise output and mem; Set for writing to file
1938  \param output Address where new output pointer will be set
1939  \param filename File to write to
1940  \param allow_overwrite Allows file to be overwritten, if set.
1941  \return Newly-opened file descriptor
1942  \note It is the caller's responsiblity to free output and to close fd.
1943  \sa __ops_teardown_file_write()
1944 */
1945 int
1946 __ops_setup_file_write(__ops_output_t **output, const char *filename,
1947 			unsigned allow_overwrite)
1948 {
1949 	int             fd = 0;
1950 	int             flags = 0;
1951 
1952 	/*
1953          * initialise needed structures for writing to file
1954          */
1955 	if (filename == NULL) {
1956 		/* write to stdout */
1957 		fd = STDOUT_FILENO;
1958 	} else {
1959 		flags = O_WRONLY | O_CREAT;
1960 		if (allow_overwrite)
1961 			flags |= O_TRUNC;
1962 		else
1963 			flags |= O_EXCL;
1964 #ifdef O_BINARY
1965 		flags |= O_BINARY;
1966 #endif
1967 		fd = open(filename, flags, 0600);
1968 		if (fd < 0) {
1969 			perror(filename);
1970 			return fd;
1971 		}
1972 	}
1973 	*output = __ops_output_new();
1974 	__ops_writer_set_fd(*output, fd);
1975 	return fd;
1976 }
1977 
1978 /**
1979    \ingroup Core_Writers
1980    \brief Closes writer, frees info, closes fd
1981    \param output
1982    \param fd
1983 */
1984 void
1985 __ops_teardown_file_write(__ops_output_t *output, int fd)
1986 {
1987 	__ops_writer_close(output);
1988 	close(fd);
1989 	__ops_output_delete(output);
1990 }
1991 
1992 /**
1993    \ingroup Core_Writers
1994    \brief As __ops_setup_file_write, but appends to file
1995 */
1996 int
1997 __ops_setup_file_append(__ops_output_t **output, const char *filename)
1998 {
1999 	int	fd;
2000 
2001 	/*
2002          * initialise needed structures for writing to file
2003          */
2004 #ifdef O_BINARY
2005 	fd = open(filename, O_WRONLY | O_APPEND | O_BINARY, 0600);
2006 #else
2007 	fd = open(filename, O_WRONLY | O_APPEND, 0600);
2008 #endif
2009 	if (fd >= 0) {
2010 		*output = __ops_output_new();
2011 		__ops_writer_set_fd(*output, fd);
2012 	}
2013 	return fd;
2014 }
2015 
2016 /**
2017    \ingroup Core_Writers
2018    \brief As __ops_teardown_file_write()
2019 */
2020 void
2021 __ops_teardown_file_append(__ops_output_t *output, int fd)
2022 {
2023 	__ops_teardown_file_write(output, fd);
2024 }
2025 
2026 /**
2027    \ingroup Core_Readers
2028    \brief Creates parse_info, opens file, and sets to read from file
2029    \param stream Address where new parse_info will be set
2030    \param filename Name of file to read
2031    \param vp Reader-specific arg
2032    \param callback Callback to use when reading
2033    \param accumulate Set if we need to accumulate as we read. (Usually 0 unless doing signature verification)
2034    \note It is the caller's responsiblity to free parse_info and to close fd
2035    \sa __ops_teardown_file_read()
2036 */
2037 int
2038 __ops_setup_file_read(__ops_io_t *io,
2039 			__ops_stream_t **stream,
2040 			const char *filename,
2041 			void *vp,
2042 			__ops_cb_ret_t callback(const __ops_packet_t *,
2043 						__ops_cbdata_t *),
2044 			unsigned accumulate)
2045 {
2046 	int	fd;
2047 
2048 #ifdef O_BINARY
2049 	fd = open(filename, O_RDONLY | O_BINARY);
2050 #else
2051 	fd = open(filename, O_RDONLY);
2052 #endif
2053 	if (fd < 0) {
2054 		(void) fprintf(io->errs, "can't open \"%s\"\n", filename);
2055 		return fd;
2056 	}
2057 	*stream = __ops_new(sizeof(**stream));
2058 	(*stream)->io = (*stream)->cbinfo.io = io;
2059 	__ops_set_callback(*stream, callback, vp);
2060 #ifdef USE_MMAP_FOR_FILES
2061 	__ops_reader_set_mmap(*stream, fd);
2062 #else
2063 	__ops_reader_set_fd(*stream, fd);
2064 #endif
2065 	if (accumulate) {
2066 		(*stream)->readinfo.accumulate = 1;
2067 	}
2068 	return fd;
2069 }
2070 
2071 /**
2072    \ingroup Core_Readers
2073    \brief Frees stream and closes fd
2074    \param stream
2075    \param fd
2076    \sa __ops_setup_file_read()
2077 */
2078 void
2079 __ops_teardown_file_read(__ops_stream_t *stream, int fd)
2080 {
2081 	close(fd);
2082 	__ops_stream_delete(stream);
2083 }
2084 
2085 __ops_cb_ret_t
2086 __ops_litdata_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
2087 {
2088 	const __ops_contents_t	*content = &pkt->u;
2089 
2090 	if (__ops_get_debug_level(__FILE__)) {
2091 		printf("__ops_litdata_cb: ");
2092 		__ops_print_packet(&cbinfo->printstate, pkt);
2093 	}
2094 	/* Read data from packet into static buffer */
2095 	switch (pkt->tag) {
2096 	case OPS_PTAG_CT_LITDATA_BODY:
2097 		/* if writer enabled, use it */
2098 		if (cbinfo->output) {
2099 			if (__ops_get_debug_level(__FILE__)) {
2100 				printf("__ops_litdata_cb: length is %u\n",
2101 					content->litdata_body.length);
2102 			}
2103 			__ops_write(cbinfo->output,
2104 					content->litdata_body.data,
2105 					content->litdata_body.length);
2106 		}
2107 		break;
2108 
2109 	case OPS_PTAG_CT_LITDATA_HEADER:
2110 		/* ignore */
2111 		break;
2112 
2113 	default:
2114 		break;
2115 	}
2116 
2117 	return OPS_RELEASE_MEMORY;
2118 }
2119 
2120 __ops_cb_ret_t
2121 __ops_pk_sesskey_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
2122 {
2123 	const __ops_contents_t	*content = &pkt->u;
2124 	unsigned		 from;
2125 	__ops_io_t		*io;
2126 
2127 	io = cbinfo->io;
2128 	if (__ops_get_debug_level(__FILE__)) {
2129 		__ops_print_packet(&cbinfo->printstate, pkt);
2130 	}
2131 	/* Read data from packet into static buffer */
2132 	switch (pkt->tag) {
2133 	case OPS_PTAG_CT_PK_SESSION_KEY:
2134 		if (__ops_get_debug_level(__FILE__)) {
2135 			printf("OPS_PTAG_CT_PK_SESSION_KEY\n");
2136 		}
2137 		if (!cbinfo->cryptinfo.secring) {
2138 			(void) fprintf(io->errs,
2139 				"__ops_pk_sesskey_cb: bad keyring\n");
2140 			return (__ops_cb_ret_t)0;
2141 		}
2142 		from = 0;
2143 		cbinfo->cryptinfo.keydata =
2144 			__ops_getkeybyid(io, cbinfo->cryptinfo.secring,
2145 				content->pk_sesskey.key_id, &from, NULL);
2146 		if (!cbinfo->cryptinfo.keydata) {
2147 			break;
2148 		}
2149 		break;
2150 
2151 	default:
2152 		break;
2153 	}
2154 
2155 	return OPS_RELEASE_MEMORY;
2156 }
2157 
2158 /**
2159  \ingroup Core_Callbacks
2160 
2161 \brief Callback to get secret key, decrypting if necessary.
2162 
2163 @verbatim
2164  This callback does the following:
2165  * finds the session key in the keyring
2166  * gets a passphrase if required
2167  * decrypts the secret key, if necessary
2168  * sets the seckey in the content struct
2169 @endverbatim
2170 */
2171 
2172 __ops_cb_ret_t
2173 __ops_get_seckey_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
2174 {
2175 	const __ops_contents_t	*content = &pkt->u;
2176 	const __ops_seckey_t	*secret;
2177 	const __ops_key_t	*pubkey;
2178 	const __ops_key_t	*keypair;
2179 	unsigned		 from;
2180 	__ops_io_t		*io;
2181 
2182 	io = cbinfo->io;
2183 	if (__ops_get_debug_level(__FILE__)) {
2184 		__ops_print_packet(&cbinfo->printstate, pkt);
2185 	}
2186 	switch (pkt->tag) {
2187 	case OPS_GET_SECKEY:
2188 		/* print key from pubring */
2189 		from = 0;
2190 		pubkey = __ops_getkeybyid(io, cbinfo->cryptinfo.pubring,
2191 				content->get_seckey.pk_sesskey->key_id,
2192 				&from, NULL);
2193 		/* validate key from secring */
2194 		from = 0;
2195 		cbinfo->cryptinfo.keydata =
2196 			__ops_getkeybyid(io, cbinfo->cryptinfo.secring,
2197 				content->get_seckey.pk_sesskey->key_id,
2198 				&from, NULL);
2199 		if (!cbinfo->cryptinfo.keydata ||
2200 		    !__ops_is_key_secret(cbinfo->cryptinfo.keydata)) {
2201 			return (__ops_cb_ret_t)0;
2202 		}
2203 		keypair = cbinfo->cryptinfo.keydata;
2204 		if (pubkey == NULL) {
2205 			pubkey = keypair;
2206 		}
2207 		do {
2208 			/* print out the user id */
2209 			__ops_print_keydata(io, cbinfo->cryptinfo.pubring, pubkey,
2210 				"signature ", &pubkey->key.pubkey, 0);
2211 			/* now decrypt key */
2212 			secret = __ops_decrypt_seckey(keypair, cbinfo->passfp);
2213 			if (secret == NULL) {
2214 				(void) fprintf(io->errs, "Bad passphrase\n");
2215 			}
2216 		} while (secret == NULL);
2217 		*content->get_seckey.seckey = secret;
2218 		break;
2219 
2220 	default:
2221 		break;
2222 	}
2223 
2224 	return OPS_RELEASE_MEMORY;
2225 }
2226 
2227 /**
2228  \ingroup HighLevel_Callbacks
2229  \brief Callback to use when you need to prompt user for passphrase
2230  \param contents
2231  \param cbinfo
2232 */
2233 __ops_cb_ret_t
2234 get_passphrase_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
2235 {
2236 	const __ops_contents_t	*content = &pkt->u;
2237 	__ops_io_t		*io;
2238 
2239 	io = cbinfo->io;
2240 	if (__ops_get_debug_level(__FILE__)) {
2241 		__ops_print_packet(&cbinfo->printstate, pkt);
2242 	}
2243 	if (cbinfo->cryptinfo.keydata == NULL) {
2244 		(void) fprintf(io->errs, "get_passphrase_cb: NULL keydata\n");
2245 	} else {
2246 		__ops_print_keydata(io, cbinfo->cryptinfo.pubring, cbinfo->cryptinfo.keydata, "signature ",
2247 			&cbinfo->cryptinfo.keydata->key.pubkey, 0);
2248 	}
2249 	switch (pkt->tag) {
2250 	case OPS_GET_PASSPHRASE:
2251 		*(content->skey_passphrase.passphrase) =
2252 				netpgp_strdup(getpass("netpgp passphrase: "));
2253 		return OPS_KEEP_MEMORY;
2254 	default:
2255 		break;
2256 	}
2257 	return OPS_RELEASE_MEMORY;
2258 }
2259 
2260 unsigned
2261 __ops_reader_set_accumulate(__ops_stream_t *stream, unsigned state)
2262 {
2263 	return stream->readinfo.accumulate = state;
2264 }
2265 
2266 /**************************************************************************/
2267 
2268 static int
2269 hash_reader(void *dest,
2270 		size_t length,
2271 		__ops_error_t **errors,
2272 		__ops_reader_t *readinfo,
2273 		__ops_cbdata_t *cbinfo)
2274 {
2275 	__ops_hash_t	*hash = __ops_reader_get_arg(readinfo);
2276 	int		 r;
2277 
2278 	r = __ops_stacked_read(dest, length, errors, readinfo, cbinfo);
2279 	if (r <= 0) {
2280 		return r;
2281 	}
2282 	hash->add(hash, dest, (unsigned)r);
2283 	return r;
2284 }
2285 
2286 /**
2287    \ingroup Internal_Readers_Hash
2288    \brief Push hashed data reader on stack
2289 */
2290 void
2291 __ops_reader_push_hash(__ops_stream_t *stream, __ops_hash_t *hash)
2292 {
2293 	if (!hash->init(hash)) {
2294 		(void) fprintf(stderr, "__ops_reader_push_hash: can't init hash\n");
2295 		/* just continue and die */
2296 		/* XXX - agc - no way to return failure */
2297 	}
2298 	__ops_reader_push(stream, hash_reader, NULL, hash);
2299 }
2300 
2301 /**
2302    \ingroup Internal_Readers_Hash
2303    \brief Pop hashed data reader from stack
2304 */
2305 void
2306 __ops_reader_pop_hash(__ops_stream_t *stream)
2307 {
2308 	__ops_reader_pop(stream);
2309 }
2310 
2311 /* read memory from the previously mmap-ed file */
2312 static int
2313 mmap_reader(void *dest, size_t length, __ops_error_t **errors,
2314 	  __ops_reader_t *readinfo, __ops_cbdata_t *cbinfo)
2315 {
2316 	mmap_reader_t	*mem = __ops_reader_get_arg(readinfo);
2317 	unsigned	 n;
2318 	char		*cmem = mem->mem;
2319 
2320 	__OPS_USED(errors);
2321 	__OPS_USED(cbinfo);
2322 	n = (unsigned)MIN(length, (unsigned)(mem->size - mem->offset));
2323 	if (n > 0) {
2324 		(void) memcpy(dest, &cmem[(int)mem->offset], (unsigned)n);
2325 		mem->offset += n;
2326 	}
2327 	return (int)n;
2328 }
2329 
2330 /* tear down the mmap, close the fd */
2331 static void
2332 mmap_destroyer(__ops_reader_t *readinfo)
2333 {
2334 	mmap_reader_t *mem = __ops_reader_get_arg(readinfo);
2335 
2336 	(void) munmap(mem->mem, (unsigned)mem->size);
2337 	(void) close(mem->fd);
2338 	free(__ops_reader_get_arg(readinfo));
2339 }
2340 
2341 /* set up the file to use mmap-ed memory if available, file IO otherwise */
2342 void
2343 __ops_reader_set_mmap(__ops_stream_t *stream, int fd)
2344 {
2345 	mmap_reader_t	*mem;
2346 	struct stat	 st;
2347 
2348 	if (fstat(fd, &st) != 0) {
2349 		(void) fprintf(stderr, "__ops_reader_set_mmap: can't fstat\n");
2350 	} else if ((mem = calloc(1, sizeof(*mem))) == NULL) {
2351 		(void) fprintf(stderr, "__ops_reader_set_mmap: bad alloc\n");
2352 	} else {
2353 		mem->size = (uint64_t)st.st_size;
2354 		mem->offset = 0;
2355 		mem->fd = fd;
2356 		mem->mem = mmap(NULL, (size_t)st.st_size, PROT_READ,
2357 				MAP_PRIVATE | MAP_FILE, fd, 0);
2358 		if (mem->mem == MAP_FAILED) {
2359 			__ops_reader_set(stream, fd_reader, reader_fd_destroyer,
2360 					mem);
2361 		} else {
2362 			__ops_reader_set(stream, mmap_reader, mmap_destroyer,
2363 					mem);
2364 		}
2365 	}
2366 }
2367